/** * Module Initialization Tests - Tests E2E * * Vérifie que le module Scrying Pool s'initialise correctement * dans FoundryVTT et que toutes les fonctionnalités de base sont disponibles. */ import { test, expect } from '@playwright/test'; import { waitForFoundryReady, waitForVVMModule, clickFoundryButton, } from '../utils/foundry-helpers'; const MODULE_ID = 'scrying-pool'; const MODULE_NAME = 'Scrying Pool'; test.describe('Module Initialization', () => { test.setTimeout(60000); test.beforeEach(async ({ page }) => { await page.goto('https://localhost:31000', { waitUntil: 'domcontentloaded', timeout: 30000, }); await waitForFoundryReady(page); }); // ============================================================================ // Initialisation de base // ============================================================================ test('Module is registered in FoundryVTT', async ({ page }) => { const module = await page.evaluate((moduleId) => { return game.modules?.get(moduleId); }, MODULE_ID); expect(module).toBeTruthy(); expect(module?.id).toBe(MODULE_ID); }); test('Module has correct name', async ({ page }) => { const module = await page.evaluate((moduleId) => { return game.modules?.get(moduleId); }, MODULE_ID); expect(module?.data?.title).toContain(MODULE_NAME); }); test('Module is active', async ({ page }) => { await waitForVVMModule(page); const isActive = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); return module?.active; }, MODULE_ID); expect(isActive).toBe(true); }); test('Module loads without errors', async ({ page }) => { // Vérifier qu'il n'y a pas d'erreurs dans la console const errors = []; page.on('console', msg => { if (msg.type() === 'error') { errors.push(msg.text()); } }); await waitForVVMModule(page); await page.waitForTimeout(2000); // Filtrer les erreurs connues (qui ne sont pas liées à notre module) const vvmErrors = errors.filter(err => err.includes('ScryingPool') || err.includes(MODULE_ID)); expect(vvmErrors).toHaveLength(0); }); // ============================================================================ // Vérification des composants // ============================================================================ test('ScryingPoolStrip is available for GM', async ({ page }) => { await waitForVVMModule(page); const isGM = await page.evaluate(() => game.user?.isGM || false); if (isGM) { // L'application ScryingPoolStrip devrait être enregistrée const app = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); if (module && module.api?.roleRenderer) { return module.api.roleRenderer._strip; } return null; }, MODULE_ID); // Devrait exister après l'initialisation expect(app).toBeTruthy(); } }); test('VisibilityBadges are injected into AV tiles', async ({ page }) => { await waitForVVMModule(page); // Attendre que les badges soient injectés await page.waitForSelector('.sp-visibility-badge', { state: 'visible', timeout: 10000, }); const badges = page.locator('.sp-visibility-badge'); expect(await badges.count()).toBeGreaterThan(0); }); test('ScryingPoolController is initialized', async ({ page }) => { await waitForVVMModule(page); const controller = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); return module?.api?.controller; }, MODULE_ID); expect(controller).toBeTruthy(); }); test('StateStore is initialized with correct data', async ({ page }) => { await waitForVVMModule(page); const stateStore = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); return module?.api?.stateStore; }, MODULE_ID); expect(stateStore).toBeTruthy(); // Vérifier que la matrice de visibilité existe const matrix = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); if (module?.api?.stateStore) { return module.api.stateStore.getMatrix(); } return null; }, MODULE_ID); expect(matrix).toBeTruthy(); expect(matrix).toHaveProperty('_version'); expect(matrix).toHaveProperty('matrix'); }); test('SocketHandler is registered', async ({ page }) => { await waitForVVMModule(page); const socketHandler = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); return module?.api?.socketHandler; }, MODULE_ID); expect(socketHandler).toBeTruthy(); }); test('VisibilityManager is initialized', async ({ page }) => { await waitForVVMModule(page); const visibilityManager = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); return module?.api?.visibilityManager; }, MODULE_ID); expect(visibilityManager).toBeTruthy(); }); // ============================================================================ // Vérification des paramètres // ============================================================================ test('World settings are registered', async ({ page }) => { await waitForVVMModule(page); const settings = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); if (module) { return Array.from(game.settings.settings.entries()) .filter(([key]) => key.startsWith(`${moduleId}.`)) .map(([key, value]) => key); } return []; }, MODULE_ID); expect(settings.length).toBeGreaterThan(0); expect(settings).toContain(`${MODULE_ID}.webrtcMode`); }); test('Client settings are registered', async ({ page }) => { await waitForVVMModule(page); const clientSettings = await page.evaluate((moduleId, userId) => { const module = game.modules?.get(moduleId); if (module && game.users?.get(userId)) { const user = game.users.get(userId); return Array.from(user.getSettings().entries()) .filter(([key]) => key.includes(moduleId)) .map(([key]) => key); } return []; }, MODULE_ID, 'gamemaster'); expect(clientSettings.length).toBeGreaterThan(0); }); // ============================================================================ // Vérification des menus // ============================================================================ test('GM Player Privacy Selector menu is registered', async ({ page }) => { await waitForVVMModule(page); const isGM = await page.evaluate(() => game.user?.isGM || false); if (isGM) { // Le menu devrait être disponible dans les paramètres const menuItem = page.locator('button:has-text("Player Privacy")'); await expect(menuItem).toBeVisible({ timeout: 10000 }); } }); // ============================================================================ // Vérification des hooks // ============================================================================ test('Hooks are registered correctly', async ({ page }) => { await waitForVVMModule(page); // Vérifier que les hooks sont enregistrés const hooks = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); if (module && game.hooks) { const hookEvents = []; for (const [event, handlers] of game.hooks.events.entries()) { if (event.startsWith('scrying-pool.')) { hookEvents.push(event); } } return hookEvents; } return []; }, MODULE_ID); expect(hooks.length).toBeGreaterThan(0); expect(hooks).toContain('scrying-pool:stateChanged'); }); // ============================================================================ // Vérification des styles // ============================================================================ test('Module CSS is loaded', async ({ page }) => { await waitForVVMModule(page); // Vérifier qu'une classe CSS du module existe const element = page.locator('.scrying-pool'); // Devrait exister même s'il n'est pas visible expect(await element.count()).toBeGreaterThan(0); }); test('Design tokens are defined', async ({ page }) => { await waitForVVMModule(page); const tokens = await page.evaluate(() => { const style = getComputedStyle(document.documentElement); const tokenNames = [ '--sp-surface', '--sp-border', '--sp-text-primary', '--sp-text-secondary', '--sp-accent', ]; return tokenNames.filter(name => style.getPropertyValue(name).trim() !== ''); }); expect(tokens.length).toBeGreaterThan(0); }); // ============================================================================ // Vérification des templates // ============================================================================ test('Handlebars templates are precompiled', async ({ page }) => { await waitForVVMModule(page); // Vérifier que les templates sont disponibles const templates = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); if (module && game.templates) { const templatePrefix = `modules/${moduleId}/templates/`; return Array.from(game.templates.cache.keys()) .filter(key => key.startsWith(templatePrefix)) .map(key => key.replace(templatePrefix, '')); } return []; }, MODULE_ID); expect(templates.length).toBeGreaterThan(0); }); // ============================================================================ // Vérification des localisations // ============================================================================ test('Localization strings are available', async ({ page }) => { await waitForVVMModule(page); const i18nKeys = await page.evaluate((moduleId) => { const module = game.modules?.get(moduleId); if (module && game.i18n) { const langData = game.i18n.getLanguages(); const moduleKeys = []; for (const [lang, translations] of Object.entries(langData)) { for (const [key] of Object.entries(translations)) { if (key.startsWith(`${moduleId}.`)) { moduleKeys.push(key); } } } return moduleKeys; } return []; }, MODULE_ID); expect(i18nKeys.length).toBeGreaterThan(0); }); });