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,151 @@
|
||||
/**
|
||||
* Setup simplifié pour FoundryVTT E2E Tests
|
||||
*
|
||||
* Environnement existant :
|
||||
* - Serveur FoundryVTT sur https://localhost:31000
|
||||
* - Monde déjà disponible
|
||||
* - Utilisateur: gamemaster (pas de mot de passe)
|
||||
* - Module Video View Manager déjà installé
|
||||
*
|
||||
* Ce setup vérifie simplement que tout est accessible.
|
||||
*/
|
||||
|
||||
import { chromium } from '@playwright/test';
|
||||
|
||||
const FOUNDRY_URL = 'https://localhost:31000';
|
||||
const TEST_USER = 'gamemaster';
|
||||
|
||||
/**
|
||||
* Vérifie que FoundryVTT est accessible
|
||||
*/
|
||||
async function verifyFoundryAccessible(page) {
|
||||
console.log('🔍 Vérification de l\'accès à FoundryVTT...');
|
||||
|
||||
try {
|
||||
await page.goto(FOUNDRY_URL, {
|
||||
timeout: 30000,
|
||||
waitUntil: 'domcontentloaded',
|
||||
});
|
||||
|
||||
// Attendre un élément Foundry (le body devrait exister)
|
||||
await page.waitForSelector('body', { timeout: 10000 });
|
||||
|
||||
console.log('✅ FoundryVTT est accessible sur https://localhost:31000');
|
||||
|
||||
// Vérifier que le module est chargé (en mode GM)
|
||||
const title = await page.title();
|
||||
console.log(`📖 Titre de la page: ${title}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Impossible de se connecter à FoundryVTT:', error.message);
|
||||
console.error('💡 Vérifiez que:');
|
||||
console.error(' - FoundryVTT est en cours d\'exécution sur https://localhost:31000');
|
||||
console.error(' - Le monde est accessible');
|
||||
console.error(' - Le module Video View Manager est installé');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie que le module Video View Manager est actif
|
||||
*/
|
||||
async function verifyModuleActive(page) {
|
||||
console.log('📦 Vérification du module Video View Manager...');
|
||||
|
||||
try {
|
||||
// Attendre que le module soit initialisé (check pour un élément spécifique)
|
||||
await page.waitForFunction(() => {
|
||||
return typeof game !== 'undefined' &&
|
||||
game.modules?.get?.('video-view-manager')?.active;
|
||||
}, { timeout: 15000 });
|
||||
|
||||
const isActive = await page.evaluate(() => {
|
||||
const module = game.modules.get('video-view-manager');
|
||||
return module?.active || false;
|
||||
});
|
||||
|
||||
if (isActive) {
|
||||
console.log('✅ Module Video View Manager est actif');
|
||||
} else {
|
||||
console.warn('⚠️ Module Video View Manager n\'est pas actif');
|
||||
console.warn(' Essayez de recharger la page (Ctrl+R)');
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Impossible de vérifier l\'état du module:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie que l'utilisateur est GM
|
||||
*/
|
||||
async function verifyIsGM(page) {
|
||||
console.log('👑 Vérification du rôle GM...');
|
||||
|
||||
try {
|
||||
const isGM = await page.evaluate(() => {
|
||||
return game.user?.isGM || false;
|
||||
});
|
||||
|
||||
if (isGM) {
|
||||
console.log('✅ Utilisateur est GM (gamemaster)');
|
||||
} else {
|
||||
console.warn('⚠️ Utilisateur n\'est pas GM');
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Impossible de vérifier le rôle:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exécute le setup
|
||||
*/
|
||||
async function globalSetup() {
|
||||
console.log('\n🚀 Démarrage du setup E2E pour FoundryVTT...\n');
|
||||
console.log('Configuration détectée:');
|
||||
console.log(' - URL: https://localhost:31000');
|
||||
console.log(' - User: gamemaster');
|
||||
console.log(' - Monde: déjà disponible\n');
|
||||
|
||||
const browser = await chromium.launch({
|
||||
headless: true,
|
||||
timeout: 30000,
|
||||
ignoreHTTPSErrors: true,
|
||||
});
|
||||
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1920, height: 1080 },
|
||||
userAgent: 'VVM-E2E-Setup/1.0',
|
||||
ignoreHTTPSErrors: true,
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
// Vérifier l'accès à Foundry
|
||||
await verifyFoundryAccessible(page);
|
||||
|
||||
// Vérifier que le module est actif
|
||||
await verifyModuleActive(page);
|
||||
|
||||
// Vérifier le rôle GM
|
||||
await verifyIsGM(page);
|
||||
|
||||
console.log('\n✅ Setup E2E terminé avec succès !\n');
|
||||
console.log('Prêt à exécuter les tests sur:');
|
||||
console.log(` ${FOUNDRY_URL}\n`);
|
||||
|
||||
// Stocker des informations pour les tests
|
||||
process.env.FOUNDRY_URL = FOUNDRY_URL;
|
||||
process.env.FOUNDRY_USER = TEST_USER;
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ Setup échoué:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
await page.close();
|
||||
await context.close();
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
export default globalSetup;
|
||||
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Global Setup for FoundryVTT E2E Tests
|
||||
*
|
||||
* Ce script prépare l'environnement avant l'exécution des tests :
|
||||
* - Démarre le serveur FoundryVTT (si non déjà démarré)
|
||||
* - Crée un monde de test
|
||||
* - Configure les utilisateurs de test
|
||||
* - Installe le module Video View Manager
|
||||
*/
|
||||
|
||||
import { chromium } from '@playwright/test';
|
||||
|
||||
// Configuration du monde de test
|
||||
const FOUNDRY_BASE_URL = 'http://localhost:30000';
|
||||
const TEST_WORLD_NAME = 'VVM-E2E-Test-World';
|
||||
const TEST_GM_USER = 'TestGM';
|
||||
const TEST_PLAYER_USER = 'TestPlayer';
|
||||
|
||||
// Stockage global pour l'état
|
||||
const globalSetup = {
|
||||
browser: null,
|
||||
context: null,
|
||||
page: null,
|
||||
worldCreated: false,
|
||||
};
|
||||
|
||||
/**
|
||||
* Crée un monde de test dans FoundryVTT
|
||||
*/
|
||||
async function createTestWorld(page) {
|
||||
console.log('🌍 Creating test world...');
|
||||
|
||||
// Naviguer vers la page de gestion des mondes
|
||||
await page.goto(`${FOUNDRY_BASE_URL}/setup`);
|
||||
|
||||
// Attendre que la page se charge
|
||||
await page.waitForSelector('#world-list', { timeout: 30000 });
|
||||
|
||||
// Vérifier si le monde de test existe déjà
|
||||
const worldExists = await page.locator(`#world-list [data-world-id]:has-text("${TEST_WORLD_NAME}")`).count();
|
||||
|
||||
if (worldExists > 0) {
|
||||
console.log(`✅ Test world "${TEST_WORLD_NAME}" already exists`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Créer un nouveau monde
|
||||
await page.locator('button:has-text("Create World")').click();
|
||||
await page.waitForSelector('#create-world-dialog', { timeout: 10000 });
|
||||
|
||||
// Remplir le formulaire
|
||||
await page.locator('#create-world-dialog input[name="worldName"]').fill(TEST_WORLD_NAME);
|
||||
await page.locator('#create-world-dialog input[name="system"]').fill('dnd5e'); // Système par défaut
|
||||
|
||||
// Créer le monde
|
||||
await page.locator('#create-world-dialog button:has-text("Create")').click();
|
||||
|
||||
// Attendre la confirmation
|
||||
await page.waitForSelector(`#world-list [data-world-id]:has-text("${TEST_WORLD_NAME}")`, { timeout: 15000 });
|
||||
|
||||
console.log(`✅ Created test world: ${TEST_WORLD_NAME}`);
|
||||
globalSetup.worldCreated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure les utilisateurs de test
|
||||
*/
|
||||
async function configureTestUsers(page) {
|
||||
console.log('👥 Configuring test users...');
|
||||
|
||||
// Naviguer vers la gestion des utilisateurs
|
||||
await page.goto(`${FOUNDRY_BASE_URL}/setup/users`);
|
||||
await page.waitForSelector('#users-list', { timeout: 30000 });
|
||||
|
||||
// Vérifier/Créer l'utilisateur GM
|
||||
const gmExists = await page.locator(`#users-list [data-user-id]:has-text("${TEST_GM_USER}")`).count();
|
||||
if (gmExists === 0) {
|
||||
await page.locator('button:has-text("Add User")').click();
|
||||
await page.waitForSelector('#add-user-dialog', { timeout: 10000 });
|
||||
await page.locator('#add-user-dialog input[name="username"]').fill(TEST_GM_USER);
|
||||
await page.locator('#add-user-dialog input[name="password"]').fill('test123');
|
||||
await page.locator('#add-user-dialog select[name="role"]').selectOption('Game Master');
|
||||
await page.locator('#add-user-dialog button:has-text("Add")').click();
|
||||
await page.waitForSelector(`#users-list [data-user-id]:has-text("${TEST_GM_USER}")`, { timeout: 10000 });
|
||||
console.log(`✅ Created GM user: ${TEST_GM_USER}`);
|
||||
}
|
||||
|
||||
// Vérifier/Créer l'utilisateur Player
|
||||
const playerExists = await page.locator(`#users-list [data-user-id]:has-text("${TEST_PLAYER_USER}")`).count();
|
||||
if (playerExists === 0) {
|
||||
await page.locator('button:has-text("Add User")').click();
|
||||
await page.waitForSelector('#add-user-dialog', { timeout: 10000 });
|
||||
await page.locator('#add-user-dialog input[name="username"]').fill(TEST_PLAYER_USER);
|
||||
await page.locator('#add-user-dialog input[name="password"]').fill('test123');
|
||||
await page.locator('#add-user-dialog select[name="role"]').selectOption('Player');
|
||||
await page.locator('#add-user-dialog button:has-text("Add")').click();
|
||||
await page.waitForSelector(`#users-list [data-user-id]:has-text("${TEST_PLAYER_USER}")`, { timeout: 10000 });
|
||||
console.log(`✅ Created Player user: ${TEST_PLAYER_USER}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Installe le module Video View Manager
|
||||
*/
|
||||
async function installVVMModule(page) {
|
||||
console.log('📦 Installing Video View Manager module...');
|
||||
|
||||
// Naviguer vers la gestion des modules
|
||||
await page.goto(`${FOUNDRY_BASE_URL}/setup/modules`);
|
||||
await page.waitForSelector('#modules-list', { timeout: 30000 });
|
||||
|
||||
// Vérifier si le module est déjà installé
|
||||
const moduleInstalled = await page.locator(`#modules-list [data-module-id="video-view-manager"]`).count();
|
||||
|
||||
if (moduleInstalled > 0) {
|
||||
console.log('✅ Video View Manager module already installed');
|
||||
return;
|
||||
}
|
||||
|
||||
// Installer le module depuis le fichier local
|
||||
// Note: En environnement de test, le module devrait déjà être dans le dossier modules/
|
||||
// Sinon, il faut le copier manuellement
|
||||
console.log('⚠️ Module must be manually placed in FoundryVTT modules/ folder');
|
||||
console.log(' Copy video-view-manager/ to foundrydata-dev/Data/modules/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde l'état pour globalTeardown
|
||||
*/
|
||||
async function saveState() {
|
||||
process.env.FOUNDRY_TEST_WORLD = TEST_WORLD_NAME;
|
||||
process.env.FOUNDRY_TEST_GM = TEST_GM_USER;
|
||||
process.env.FOUNDRY_TEST_PLAYER = TEST_PLAYER_USER;
|
||||
}
|
||||
|
||||
// Exécuter le setup
|
||||
async function globalSetup() {
|
||||
console.log('\n🚀 Starting FoundryVTT E2E Test Setup...\n');
|
||||
|
||||
// Créer le navigateur
|
||||
const browser = await chromium.launch({
|
||||
headless: true,
|
||||
timeout: 60000,
|
||||
});
|
||||
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1920, height: 1080 },
|
||||
userAgent: 'VVM-E2E-Setup/1.0',
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
// Se connecter (FoundryVTT local n'a pas d'authentification par défaut)
|
||||
await page.goto(FOUNDRY_BASE_URL, { timeout: 30000 });
|
||||
|
||||
// Créer le monde de test
|
||||
await createTestWorld(page);
|
||||
|
||||
// Configurer les utilisateurs
|
||||
await configureTestUsers(page);
|
||||
|
||||
// Installer le module
|
||||
await installVVMModule(page);
|
||||
|
||||
// Sauvegarder l'état
|
||||
await saveState();
|
||||
|
||||
console.log('\n✅ FoundryVTT E2E Test Setup Complete!\n');
|
||||
console.log('📋 Configuration:');
|
||||
console.log(` - World: ${TEST_WORLD_NAME}`);
|
||||
console.log(` - GM User: ${TEST_GM_USER}`);
|
||||
console.log(` - Player User: ${TEST_PLAYER_USER}`);
|
||||
console.log(` - Foundry URL: ${FOUNDRY_BASE_URL}`);
|
||||
console.log('\n💡 Ensure FoundryVTT server is running on localhost:30000');
|
||||
console.log('💡 Ensure Video View Manager module is in modules/ folder\n');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Setup failed:', error);
|
||||
throw error;
|
||||
} finally {
|
||||
await page.close();
|
||||
await context.close();
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
export default globalSetup;
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Global Teardown for FoundryVTT E2E Tests
|
||||
*
|
||||
* Nettoie après l'exécution des tests :
|
||||
* - Supprime le monde de test
|
||||
* - Nettoie les fichiers temporaires
|
||||
*/
|
||||
|
||||
import { chromium } from '@playwright/test';
|
||||
|
||||
const FOUNDRY_BASE_URL = 'http://localhost:30000';
|
||||
const TEST_WORLD_NAME = process.env.FOUNDRY_TEST_WORLD || 'VVM-E2E-Test-World';
|
||||
|
||||
/**
|
||||
* Supprime le monde de test
|
||||
*/
|
||||
async function deleteTestWorld(page) {
|
||||
console.log('🗑️ Deleting test world...');
|
||||
|
||||
try {
|
||||
await page.goto(`${FOUNDRY_BASE_URL}/setup`, { timeout: 30000 });
|
||||
await page.waitForSelector('#world-list', { timeout: 30000 });
|
||||
|
||||
// Trouver le monde de test
|
||||
const worldRow = page.locator(`#world-list [data-world-id]:has-text("${TEST_WORLD_NAME}")`);
|
||||
|
||||
if (await worldRow.count() > 0) {
|
||||
// Ouvrir le menu du monde
|
||||
await worldRow.locator('.world-actions-button').click();
|
||||
await page.waitForSelector('.world-context-menu', { timeout: 5000 });
|
||||
|
||||
// Cliquer sur Supprimer
|
||||
await page.locator('.world-context-menu [data-action="delete"]').click();
|
||||
|
||||
// Confirmer la suppression
|
||||
await page.waitForSelector('.delete-confirmation-dialog', { timeout: 5000 });
|
||||
await page.locator('.delete-confirmation-dialog button:has-text("Delete")').click();
|
||||
|
||||
// Attendre la suppression
|
||||
await page.waitForSelector(`#world-list [data-world-id]:has-text("${TEST_WORLD_NAME}")`, {
|
||||
state: 'detached',
|
||||
timeout: 10000
|
||||
});
|
||||
|
||||
console.log(`✅ Deleted test world: ${TEST_WORLD_NAME}`);
|
||||
} else {
|
||||
console.log(`⚠️ Test world "${TEST_WORLD_NAME}" not found, skipping deletion`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('⚠️ Could not delete test world (may have already been deleted):', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nettoie les utilisateurs de test
|
||||
*/
|
||||
async function cleanupTestUsers(page) {
|
||||
console.log('🧹 Cleaning up test users...');
|
||||
|
||||
try {
|
||||
const testUsers = [
|
||||
process.env.FOUNDRY_TEST_GM || 'TestGM',
|
||||
process.env.FOUNDRY_TEST_PLAYER || 'TestPlayer'
|
||||
];
|
||||
|
||||
await page.goto(`${FOUNDRY_BASE_URL}/setup/users`, { timeout: 30000 });
|
||||
await page.waitForSelector('#users-list', { timeout: 30000 });
|
||||
|
||||
for (const username of testUsers) {
|
||||
const userRow = page.locator(`#users-list [data-user-id]:has-text("${username}")`);
|
||||
|
||||
if (await userRow.count() > 0) {
|
||||
await userRow.locator('.user-actions-button').click();
|
||||
await page.waitForSelector('.user-context-menu', { timeout: 5000 });
|
||||
await page.locator('.user-context-menu [data-action="delete"]').click();
|
||||
await page.locator('.delete-confirmation-dialog button:has-text("Delete")').click();
|
||||
|
||||
await page.waitForSelector(`#users-list [data-user-id]:has-text("${username}")`, {
|
||||
state: 'detached',
|
||||
timeout: 5000
|
||||
});
|
||||
|
||||
console.log(`✅ Deleted test user: ${username}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('⚠️ Could not cleanup test users:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exécute le nettoyage
|
||||
*/
|
||||
async function globalTeardown() {
|
||||
console.log('\n🧹 Running FoundryVTT E2E Test Teardown...\n');
|
||||
|
||||
const browser = await chromium.launch({
|
||||
headless: true,
|
||||
timeout: 30000,
|
||||
});
|
||||
|
||||
const context = await browser.newContext({
|
||||
viewport: { width: 1920, height: 1080 },
|
||||
userAgent: 'VVM-E2E-Teardown/1.0',
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
|
||||
try {
|
||||
await page.goto(FOUNDRY_BASE_URL, { timeout: 30000 });
|
||||
|
||||
// Supprimer le monde de test
|
||||
await deleteTestWorld(page);
|
||||
|
||||
// Nettoyer les utilisateurs
|
||||
await cleanupTestUsers(page);
|
||||
|
||||
console.log('\n✅ FoundryVTT E2E Test Teardown Complete!\n');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Teardown failed:', error);
|
||||
} finally {
|
||||
await page.close();
|
||||
await context.close();
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
export default globalTeardown;
|
||||
Reference in New Issue
Block a user