@@ -3,7 +3,6 @@
|
||||
*
|
||||
* FR-23: Player Privacy Panel accessible from module settings
|
||||
* FR-24: Reaction Cam automation requires explicit opt-in
|
||||
* FR-25: HP-Reactive Cam Styling requires explicit opt-in
|
||||
* FR-26: Custom Portrait Fallback settable via file picker
|
||||
*/
|
||||
|
||||
@@ -53,14 +52,11 @@ test.describe('FR-23: Player Privacy Panel Accessibility', () => {
|
||||
|
||||
// Vérifier que les sections existent
|
||||
const reactionCamSection = page.locator('.sp-automation-item:has-text("Reaction Cam")');
|
||||
const hpStylingSection = page.locator('.sp-automation-item:has-text("HP-Reactive")');
|
||||
|
||||
await expect(reactionCamSection).toBeVisible({ timeout: 5000 });
|
||||
await expect(hpStylingSection).toBeVisible({ timeout: 5000 });
|
||||
|
||||
// Vérifier les toggles
|
||||
const toggles = page.locator('.sp-toggle-switch');
|
||||
expect(await toggles.count()).toBeGreaterThanOrEqual(2);
|
||||
await expect(toggles).toHaveCount(1);
|
||||
});
|
||||
|
||||
test('Panel shows opt-in status as ON/OFF for each automation', async ({ page }) => {
|
||||
@@ -81,7 +77,7 @@ test.describe('FR-23: Player Privacy Panel Accessibility', () => {
|
||||
|
||||
// Les contrôles devraient être désactivés
|
||||
const toggles = page.locator('.sp-toggle-switch:disabled');
|
||||
await expect(toggles).toHaveCount(2); // Reaction Cam et HP-Reactive
|
||||
await expect(toggles).toHaveCount(1);
|
||||
});
|
||||
|
||||
test('Settings persist in world-level user flags', async ({ page }) => {
|
||||
@@ -163,7 +159,7 @@ test.describe('FR-24: Reaction Cam Automation', () => {
|
||||
// Si désactivé, le trigger ne devrait pas fonctionner
|
||||
// Simuler un trigger
|
||||
const triggerResult = await page.evaluate(() => {
|
||||
const module = game.modules.get('video-view-manager');
|
||||
const module = game.modules.get('scrying-pool');
|
||||
if (module && module.api?.reactionCam) {
|
||||
// Vérifier que Reaction Cam est désactivé
|
||||
return module.api.reactionCam.isEnabled();
|
||||
@@ -229,7 +225,7 @@ test.describe('FR-24: Reaction Cam Automation', () => {
|
||||
|
||||
// Simuler un trigger
|
||||
const result = await page.evaluate(() => {
|
||||
const module = game.modules.get('video-view-manager');
|
||||
const module = game.modules.get('scrying-pool');
|
||||
if (module && module.api?.reactionCam) {
|
||||
// Le trigger devrait skipper ce joueur
|
||||
return { skipped: true, reason: 'opted-out' };
|
||||
@@ -242,77 +238,6 @@ test.describe('FR-24: Reaction Cam Automation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// FR-25: HP-Reactive Cam Styling Opt-In
|
||||
// ============================================================================
|
||||
test.describe('FR-25: HP-Reactive Cam Styling', () => {
|
||||
test('HP-Reactive Cam Styling requires explicit opt-in (default: off)', async ({ page }) => {
|
||||
await openPlayerPrivacyPanel(page, TEST_USER);
|
||||
|
||||
const stylingToggle = page.locator('.sp-automation-item:has-text("HP-Reactive") .sp-toggle-switch');
|
||||
|
||||
// Vérifier que l'état par défaut est OFF
|
||||
const isChecked = await stylingToggle.evaluate(el => el.checked);
|
||||
expect(isChecked).toBe(false);
|
||||
});
|
||||
|
||||
test('HP-Reactive Styling remains disabled until explicitly enabled', async ({ page }) => {
|
||||
await openPlayerPrivacyPanel(page, TEST_USER);
|
||||
|
||||
const stylingToggle = page.locator('.sp-automation-item:has-text("HP-Reactive") .sp-toggle-switch');
|
||||
|
||||
// Simuler un changement de HP
|
||||
const result = await page.evaluate(() => {
|
||||
const module = game.modules.get('video-view-manager');
|
||||
if (module && module.api?.hpStyling) {
|
||||
// Vérifier que le styling est désactivé
|
||||
return module.api.hpStyling.isEnabled();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('GM is not notified of individual styling opt-in statuses', async ({ page }) => {
|
||||
// Activer HP-Reactive pour un joueur
|
||||
await openPlayerPrivacyPanel(page, TEST_USER);
|
||||
const stylingToggle = page.locator('.sp-automation-item:has-text("HP-Reactive") .sp-toggle-switch');
|
||||
await stylingToggle.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Vérifier qu'il n'y a pas de notification pour le GM
|
||||
// (Contrairement à Reaction Cam qui montre un badge)
|
||||
const notification = page.locator('.notification:has-text("HP-Reactive")');
|
||||
|
||||
// Devrait ne PAS voir de notification
|
||||
expect(await notification.count()).toBe(0);
|
||||
|
||||
// Nettoyer
|
||||
await stylingToggle.click();
|
||||
});
|
||||
|
||||
test('Styling opt-in flag persists across sessions', async ({ page }) => {
|
||||
// Activer
|
||||
await openPlayerPrivacyPanel(page, TEST_USER);
|
||||
const stylingToggle = page.locator('.sp-automation-item:has-text("HP-Reactive") .sp-toggle-switch');
|
||||
await stylingToggle.click();
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
// Recharger
|
||||
await page.reload();
|
||||
await waitForFoundryReady(page);
|
||||
|
||||
// Vérifier
|
||||
await openPlayerPrivacyPanel(page, TEST_USER);
|
||||
const isChecked = await stylingToggle.evaluate(el => el.checked);
|
||||
expect(isChecked).toBe(true);
|
||||
|
||||
// Désactiver
|
||||
await stylingToggle.click();
|
||||
});
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// FR-26: Custom Portrait Fallback
|
||||
// ============================================================================
|
||||
@@ -388,7 +313,7 @@ test.describe('FR-26: Custom Portrait Fallback', () => {
|
||||
|
||||
// Via l'API, définir un portrait
|
||||
await page.evaluate(() => {
|
||||
const module = game.modules.get('video-view-manager');
|
||||
const module = game.modules.get('scrying-pool');
|
||||
if (module && module.api?.portraitFallbackHandler) {
|
||||
const dataURL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
|
||||
module.api.portraitFallbackHandler.setPortraitFallback('gamemaster', dataURL);
|
||||
@@ -412,7 +337,7 @@ test.describe('FR-26: Custom Portrait Fallback', () => {
|
||||
|
||||
// Définir un portrait personnalisé
|
||||
await page.evaluate(() => {
|
||||
const module = game.modules.get('video-view-manager');
|
||||
const module = game.modules.get('scrying-pool');
|
||||
if (module && module.api?.portraitFallbackHandler) {
|
||||
const dataURL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
|
||||
module.api.portraitFallbackHandler.setPortraitFallback('gamemaster', dataURL);
|
||||
@@ -421,7 +346,7 @@ test.describe('FR-26: Custom Portrait Fallback', () => {
|
||||
|
||||
// Forcer l'état never-connected pour un utilisateur
|
||||
await page.evaluate(() => {
|
||||
const module = game.modules.get('video-view-manager');
|
||||
const module = game.modules.get('scrying-pool');
|
||||
if (module && module.api?.controller) {
|
||||
module.api.controller.setState('gamemaster', 'never-connected');
|
||||
}
|
||||
@@ -462,7 +387,7 @@ async function testPortraitUpload(page, filename, shouldSucceed) {
|
||||
|
||||
// Pour l'instant, on simule via l'API
|
||||
const result = await page.evaluate(({ filename, shouldSucceed }) => {
|
||||
const module = game.modules.get('video-view-manager');
|
||||
const module = game.modules.get('scrying-pool');
|
||||
if (module && module.api?.portraitFallbackHandler) {
|
||||
if (shouldSucceed) {
|
||||
// Fichier valide
|
||||
|
||||
Reference in New Issue
Block a user