187 lines
7.1 KiB
Markdown
187 lines
7.1 KiB
Markdown
# Instructions
|
||
|
||
- Following Playwright test failed.
|
||
- Explain why, be concise, respect Playwright best practices.
|
||
- Provide a snippet of code with the fix, if possible.
|
||
|
||
# Test info
|
||
|
||
- Name: specs/epic-1-visibility.spec.js >> Epic 1: Core Camera Visibility Control >> FR-1: Hide/Show Participant via Context Menu >> Visibility change is immediate (no layout shift)
|
||
- Location: specs/epic-1-visibility.spec.js:92:5
|
||
|
||
# Error details
|
||
|
||
```
|
||
Test timeout of 120000ms exceeded while running "beforeEach" hook.
|
||
```
|
||
|
||
```
|
||
Error: page.waitForFunction: Test timeout of 120000ms exceeded.
|
||
```
|
||
|
||
# Page snapshot
|
||
|
||
```yaml
|
||
- generic [active] [ref=e1]:
|
||
- list:
|
||
- listitem [ref=e2]:
|
||
- text:
|
||
- paragraph [ref=e3]: Foundry Virtual Tabletop nécessite une résolution d'écran de 1366px par 768px ou plus. Votre écran a une résolution de 1280px par 720px. Vous devez augmenter votre résolution ou utiliser un autre périphérique d'affichage, sinon certaines fonctionnalités du logiciel ne fonctionneront pas correctement.
|
||
- text:
|
||
- banner [ref=e5]:
|
||
- heading "Donjon & Cie" [level=1] [ref=e6]
|
||
- generic [ref=e7]:
|
||
- generic [ref=e8]:
|
||
- heading "Rejoindre la partie" [level=2] [ref=e9]
|
||
- combobox [ref=e14] [cursor=pointer]:
|
||
- option [selected]
|
||
- option "Gamemaster" [disabled]
|
||
- textbox "Mot de passe" [ref=e19]
|
||
- contentinfo [ref=e20]:
|
||
- button "Rejoindre la partie" [ref=e21] [cursor=pointer]:
|
||
- generic: Rejoindre la partie
|
||
- generic [ref=e22]:
|
||
- heading "Détails de la session" [level=2] [ref=e23]
|
||
- generic [ref=e25]: Prochaine partie
|
||
- generic [ref=e27]:
|
||
- generic [ref=e28]: Joueurs présents
|
||
- generic [ref=e30]:
|
||
- generic [ref=e31]: "1"
|
||
- generic [ref=e32]: /
|
||
- generic [ref=e33]: "1"
|
||
- generic [ref=e34]:
|
||
- heading "Retour à l’accueil" [level=2] [ref=e35]
|
||
- textbox [ref=e39]
|
||
- contentinfo [ref=e40]:
|
||
- button "Retour à l’accueil" [ref=e41] [cursor=pointer]:
|
||
- generic: Retour à l’accueil
|
||
- article [ref=e42]:
|
||
- heading "Description du monde" [level=2] [ref=e43]
|
||
- contentinfo [ref=e44]:
|
||
- paragraph [ref=e45]: Version 14 Build 361
|
||
```
|
||
|
||
# Test source
|
||
|
||
```ts
|
||
1 | /**
|
||
2 | * Helpers pour les tests E2E avec FoundryVTT
|
||
3 | *
|
||
4 | * Fournit des fonctions utilitaires pour :
|
||
5 | * - Attendre que Foundry soit prêt
|
||
6 | * - Attendre que le module soit chargé
|
||
7 | * - Interagir avec l'UI FoundryVTT
|
||
8 | * - Gérer les sélecteurs spécifiques au module
|
||
9 | */
|
||
10 |
|
||
11 | import { expect } from '@playwright/test';
|
||
12 |
|
||
13 | /**
|
||
14 | * Attend que FoundryVTT soit complètement chargé
|
||
15 | * @param {import('@playwright/test').Page} page - La page Playwright
|
||
16 | * @param {number} timeout - Timeout en ms (défaut: 30000)
|
||
17 | */
|
||
18 | export async function waitForFoundryReady(page, timeout = 30000) {
|
||
> 19 | await page.waitForFunction(() => {
|
||
| ^ Error: page.waitForFunction: Test timeout of 120000ms exceeded.
|
||
20 | return typeof game !== 'undefined' && game.ready;
|
||
21 | }, { timeout });
|
||
22 | }
|
||
23 |
|
||
24 | /**
|
||
25 | * Attend que le module Video View Manager soit actif
|
||
26 | * @param {import('@playwright/test').Page} page - La page Playwright
|
||
27 | * @param {number} timeout - Timeout en ms (défaut: 15000)
|
||
28 | */
|
||
29 | export async function waitForVVMModule(page, timeout = 15000) {
|
||
30 | await page.waitForFunction(() => {
|
||
31 | const module = game.modules?.get?.('video-view-manager');
|
||
32 | return module?.active === true;
|
||
33 | }, { timeout });
|
||
34 | }
|
||
35 |
|
||
36 | /**
|
||
37 | * Attend qu'un élément du module soit présent
|
||
38 | * @param {import('@playwright/test').Page} page - La page Playwright
|
||
39 | * @param {string} selector - Sélecteur CSS
|
||
40 | * @param {number} timeout - Timeout en ms (défaut: 10000)
|
||
41 | */
|
||
42 | export async function waitForVVMElement(page, selector, timeout = 10000) {
|
||
43 | await page.waitForSelector(selector, {
|
||
44 | state: 'visible',
|
||
45 | timeout
|
||
46 | });
|
||
47 | }
|
||
48 |
|
||
49 | /**
|
||
50 | * Clique sur un bouton dans l'UI Foundry avec retry
|
||
51 | * @param {import('@playwright/test').Page} page - La page Playwright
|
||
52 | * @param {string|import('@playwright/test').Locator} button - Sélecteur ou Locator
|
||
53 | * @param {number} retries - Nombre de tentatives (défaut: 3)
|
||
54 | */
|
||
55 | export async function clickFoundryButton(page, button, retries = 3) {
|
||
56 | for (let i = 0; i < retries; i++) {
|
||
57 | try {
|
||
58 | const locator = typeof button === 'string' ? page.locator(button) : button;
|
||
59 | await locator.click({ timeout: 5000 });
|
||
60 | return;
|
||
61 | } catch (error) {
|
||
62 | if (i === retries - 1) throw error;
|
||
63 | await page.waitForTimeout(1000);
|
||
64 | }
|
||
65 | }
|
||
66 | }
|
||
67 |
|
||
68 | /**
|
||
69 | * Ouvre le sidebar de configuration Foundry
|
||
70 | * @param {import('@playwright/test').Page} page - La page Playwright
|
||
71 | */
|
||
72 | export async function openFoundrySidebar(page) {
|
||
73 | await clickFoundryButton(page, 'button[aria-label="Configure Settings"]');
|
||
74 | await page.waitForSelector('.app-v2.settings', { state: 'visible', timeout: 10000 });
|
||
75 | }
|
||
76 |
|
||
77 | /**
|
||
78 | * Ouvre le Director's Board (Epic 2)
|
||
79 | * @param {import('@playwright/test').Page} page - La page Playwright
|
||
80 | */
|
||
81 | export async function openDirectorsBoard(page) {
|
||
82 | // Le Director's Board a un bouton dédié dans la sidebar
|
||
83 | await page.waitForSelector('button[aria-label*="Director\'s Board"]', { timeout: 10000 });
|
||
84 | await clickFoundryButton(page, 'button[aria-label*="Director\'s Board"]');
|
||
85 |
|
||
86 | // Attendre que le board soit ouvert
|
||
87 | await page.waitForSelector('.scrying-pool-directors-board', {
|
||
88 | state: 'visible',
|
||
89 | timeout: 10000
|
||
90 | });
|
||
91 | }
|
||
92 |
|
||
93 | /**
|
||
94 | * Ouvre le Player Privacy Panel pour un utilisateur
|
||
95 | * @param {import('@playwright/test').Page} page - La page Playwright
|
||
96 | * @param {string} userId - L'ID de l'utilisateur
|
||
97 | */
|
||
98 | export async function openPlayerPrivacyPanel(page, userId) {
|
||
99 | // Le panel s'ouvre via les paramètres du module
|
||
100 | await openFoundrySidebar(page);
|
||
101 |
|
||
102 | // Naviguer vers les paramètres du module
|
||
103 | await clickFoundryButton(page, 'button:has-text("Video View Manager")');
|
||
104 | await page.waitForTimeout(1000);
|
||
105 |
|
||
106 | // Cliquer sur le bouton Player Privacy
|
||
107 | await clickFoundryButton(page, 'button:has-text("Player Privacy")');
|
||
108 |
|
||
109 | // Attendre le panel
|
||
110 | await page.waitForSelector('.sp-player-privacy-panel', {
|
||
111 | state: 'visible',
|
||
112 | timeout: 10000
|
||
113 | });
|
||
114 | }
|
||
115 |
|
||
116 | /**
|
||
117 | * Sélectionne un utilisateur dans une liste Foundry
|
||
118 | * @param {import('@playwright/test').Page} page - La page Playwright
|
||
119 | * @param {string} username - Le nom de l'utilisateur
|
||
``` |