Story 4.2: Fix lint errors and code review findings
- Remove unused StripOverlayLayer import and stripOverlayLayer variable from module.js - Add comprehensive JSDoc annotations to FoundryAdapter.js methods (settings, socket, users, scenes, notifications, hooks) - Add /* global Dialog */ comment to PlayerPrivacyPanel.js for ESLint - Remove unused _force parameter from GMPlayerPrivacySelector.js render() method - Fix PlayerPrivacyPanelMenu.js: add constructor() to fallback class and call super() All 862 unit tests passing. All Story 4.2 acceptance criteria met. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* 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 Video View Manager 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?.('video-view-manager');
|
||||
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("Video View Manager")');
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user