Files
uberwald 5dc9b3b8d4
CI / ci (push) Failing after 7s
Module cleanup and tests
2026-05-24 23:13:45 +02:00

258 lines
8.5 KiB
JavaScript

/**
* Helpers pour les tests E2E avec FoundryVTT
*
* Fournit des fonctions utilitaires pour :
* - Attendre que Foundry soit prêt
* - Attendre que le module soit chargé
* - Interagir avec l'UI FoundryVTT
* - Gérer les sélecteurs spécifiques au module
*/
import { expect } from '@playwright/test';
/**
* Attend que FoundryVTT soit complètement chargé
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {number} timeout - Timeout en ms (défaut: 30000)
*/
export async function waitForFoundryReady(page, timeout = 30000) {
await page.waitForFunction(() => {
return typeof game !== 'undefined' && game.ready;
}, { timeout });
}
/**
* Attend que le module Scrying Pool soit actif
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {number} timeout - Timeout en ms (défaut: 15000)
*/
export async function waitForVVMModule(page, timeout = 15000) {
await page.waitForFunction(() => {
const module = game.modules?.get?.('scrying-pool');
return module?.active === true;
}, { timeout });
}
/**
* Attend qu'un élément du module soit présent
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} selector - Sélecteur CSS
* @param {number} timeout - Timeout en ms (défaut: 10000)
*/
export async function waitForVVMElement(page, selector, timeout = 10000) {
await page.waitForSelector(selector, {
state: 'visible',
timeout
});
}
/**
* Clique sur un bouton dans l'UI Foundry avec retry
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string|import('@playwright/test').Locator} button - Sélecteur ou Locator
* @param {number} retries - Nombre de tentatives (défaut: 3)
*/
export async function clickFoundryButton(page, button, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const locator = typeof button === 'string' ? page.locator(button) : button;
await locator.click({ timeout: 5000 });
return;
} catch (error) {
if (i === retries - 1) throw error;
await page.waitForTimeout(1000);
}
}
}
/**
* Ouvre le sidebar de configuration Foundry
* @param {import('@playwright/test').Page} page - La page Playwright
*/
export async function openFoundrySidebar(page) {
await clickFoundryButton(page, 'button[aria-label="Configure Settings"]');
await page.waitForSelector('.app-v2.settings', { state: 'visible', timeout: 10000 });
}
/**
* Ouvre le Director's Board (Epic 2)
* @param {import('@playwright/test').Page} page - La page Playwright
*/
export async function openDirectorsBoard(page) {
// Le Director's Board a un bouton dédié dans la sidebar
await page.waitForSelector('button[aria-label*="Director\'s Board"]', { timeout: 10000 });
await clickFoundryButton(page, 'button[aria-label*="Director\'s Board"]');
// Attendre que le board soit ouvert
await page.waitForSelector('.scrying-pool-directors-board', {
state: 'visible',
timeout: 10000
});
}
/**
* Ouvre le Player Privacy Panel pour un utilisateur
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} userId - L'ID de l'utilisateur
*/
export async function openPlayerPrivacyPanel(page, userId) {
// Le panel s'ouvre via les paramètres du module
await openFoundrySidebar(page);
// Naviguer vers les paramètres du module
await clickFoundryButton(page, 'button:has-text("Scrying Pool")');
await page.waitForTimeout(1000);
// Cliquer sur le bouton Player Privacy
await clickFoundryButton(page, 'button:has-text("Player Privacy")');
// Attendre le panel
await page.waitForSelector('.sp-player-privacy-panel', {
state: 'visible',
timeout: 10000
});
}
/**
* Sélectionne un utilisateur dans une liste Foundry
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} username - Le nom de l'utilisateur
*/
export async function selectUserInList(page, username) {
const userItem = page.locator(`.sp-user-item:has-text("${username}")`);
await userItem.click({ timeout: 5000 });
await page.waitForTimeout(500);
}
/**
* Attend qu'une notification Foundry apparaisse
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} text - Texte de la notification
* @param {number} timeout - Timeout en ms
*/
export async function waitForNotification(page, text, timeout = 10000) {
await page.waitForSelector(
`.notification:has-text("${text}")`,
{ state: 'visible', timeout }
);
}
/**
* Vérifie qu'un AV Tile a un badge de visibilité spécifique
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} userId - L'ID de l'utilisateur
* @param {string} state - L'état attendu (active, hidden, etc.)
*/
export async function verifyAVTileState(page, userId, state) {
const tile = page.locator(`[data-user-id="${userId}"] .sp-visibility-badge`);
await expect(tile).toBeVisible({ timeout: 5000 });
// Vérifier le texte ou la classe CSS
const expectedText = {
active: 'Live',
hidden: 'Hidden from table',
'self-muted': 'Camera paused',
offline: 'Not connected',
'cam-lost': 'Camera unavailable',
reconnecting: 'Rejoining view',
'never-connected': 'Not yet connected',
ghost: 'Leaving',
}[state];
if (expectedText) {
await expect(tile).toContainText(expectedText);
}
}
/**
* Charge un preset de scène
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} presetName - Le nom du preset
*/
export async function loadScenePreset(page, presetName) {
await openDirectorsBoard(page);
// Cliquer sur le bouton Load Preset
await clickFoundryButton(page, 'button:has-text("Load Preset")');
// Sélectionner le preset dans la liste
await page.waitForSelector('.sp-preset-list', { state: 'visible', timeout: 5000 });
await clickFoundryButton(page, `.sp-preset-item:has-text("${presetName}")`);
// Attendre la confirmation
await waitForNotification(page, `Applied preset: ${presetName}`, 5000);
}
/**
* Sauvegarde le preset courant
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} presetName - Le nom du preset
*/
export async function saveScenePreset(page, presetName) {
await openDirectorsBoard(page);
// Cliquer sur Save Preset
await clickFoundryButton(page, 'button:has-text("Save Preset")');
// Remplir le nom du preset
await page.waitForSelector('.sp-save-preset-dialog', { state: 'visible', timeout: 5000 });
await page.locator('.sp-save-preset-dialog input[name="presetName"]').fill(presetName);
// Confirmer
await clickFoundryButton(page, '.sp-save-preset-dialog button:has-text("Save")');
// Attendre la confirmation
await waitForNotification(page, `Saved preset: ${presetName}`, 5000);
}
/**
* Hide un participant via le context menu
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} username - Le nom du participant
*/
export async function hideParticipant(page, username) {
// Trouver la tuile AV du participant
const tile = page.locator(`.av-tile:has-text("${username}")`);
// Clic droit pour ouvrir le context menu
await tile.click({ button: 'right', timeout: 5000 });
// Sélectionner "Hide from table"
await page.waitForSelector('.context-menu', { state: 'visible', timeout: 5000 });
await clickFoundryButton(page, '.context-menu li:has-text("Hide from table")');
// Attendre que le badge soit mis à jour
await page.waitForTimeout(1000);
}
/**
* Show un participant via le context menu
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} username - Le nom du participant
*/
export async function showParticipant(page, username) {
const tile = page.locator(`.av-tile:has-text("${username}")`);
await tile.click({ button: 'right', timeout: 5000 });
await page.waitForSelector('.context-menu', { state: 'visible', timeout: 5000 });
await clickFoundryButton(page, '.context-menu li:has-text("Show to table")');
await page.waitForTimeout(1000);
}
/**
* Utilise le Director's Board pour toggler un participant
* @param {import('@playwright/test').Page} page - La page Playwright
* @param {string} username - Le nom du participant
*/
export async function toggleParticipantInBoard(page, username) {
await openDirectorsBoard(page);
// Trouver la carte du participant
const card = page.locator(`.sp-participant-card:has-text("${username}")`);
await card.click({ timeout: 5000 });
// Le toggle devrait se faire automatiquement au clic
await page.waitForTimeout(500);
}