@@ -22,10 +22,10 @@ function createMockAdapter(overrides = {}) {
|
||||
localize: vi.fn((key) => {
|
||||
// For testing, return strings with placeholders that match ConfirmationBar's .replace() calls
|
||||
const translations = {
|
||||
'video-view-manager.presets.confirmation.applied': 'Preset applied — {name}',
|
||||
'video-view-manager.presets.confirmation.counts': '{hidden} hidden, {visible} visible',
|
||||
'video-view-manager.presets.confirmation.partial-fail': '(some updates pending)',
|
||||
'video-view-manager.presets.confirmation.undo': 'Undo preset apply',
|
||||
'scrying-pool.presets.confirmation.applied': 'Preset applied — {name}',
|
||||
'scrying-pool.presets.confirmation.counts': '{hidden} hidden, {visible} visible',
|
||||
'scrying-pool.presets.confirmation.partial-fail': '(some updates pending)',
|
||||
'scrying-pool.presets.confirmation.undo': 'Undo preset apply',
|
||||
};
|
||||
return translations[key] ?? key;
|
||||
}),
|
||||
|
||||
@@ -77,8 +77,8 @@ describe('DirectorsBoard', () => {
|
||||
|
||||
it('has DEFAULT_OPTIONS with position', () => {
|
||||
expect(DirectorsBoard.DEFAULT_OPTIONS.position).toEqual({
|
||||
width: 400,
|
||||
height: 300,
|
||||
width: 420,
|
||||
height: 480,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -110,7 +110,7 @@ describe('DirectorsBoard', () => {
|
||||
boardWithOptions._loadPosition();
|
||||
|
||||
expect(game.user.getFlag).toHaveBeenCalledWith(
|
||||
'video-view-manager',
|
||||
'scrying-pool',
|
||||
'directorsBoardState'
|
||||
);
|
||||
// Position should be merged into options.position (not replaced)
|
||||
@@ -136,8 +136,8 @@ describe('DirectorsBoard', () => {
|
||||
expect(boardWithOptions.options.position).toEqual({
|
||||
left: 100,
|
||||
top: 200,
|
||||
width: 400,
|
||||
height: 300,
|
||||
width: 420,
|
||||
height: 480,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ describe('PresetLoadDialog', () => {
|
||||
it('should return hasPresets false when no presets exist', async () => {
|
||||
scenePresetManager.list.mockReturnValue([]);
|
||||
adapter.i18n.localize = vi.fn((key) => {
|
||||
if (key === 'video-view-manager.presets.load.emptyMessage') return 'No presets available';
|
||||
if (key === 'scrying-pool.presets.load.emptyMessage') return 'No presets available';
|
||||
return key;
|
||||
});
|
||||
|
||||
@@ -163,10 +163,10 @@ describe('PresetLoadDialog', () => {
|
||||
it('should use i18n for labels', async () => {
|
||||
adapter.i18n.localize = vi.fn((key) => {
|
||||
const translations = {
|
||||
'video-view-manager.presets.load.loadButton': 'Load',
|
||||
'video-view-manager.presets.load.cancelButton': 'Cancel',
|
||||
'video-view-manager.presets.load.title': 'Load Preset',
|
||||
'video-view-manager.presets.load.emptyMessage': 'No presets',
|
||||
'scrying-pool.presets.load.loadButton': 'Load',
|
||||
'scrying-pool.presets.load.cancelButton': 'Cancel',
|
||||
'scrying-pool.presets.load.title': 'Load Preset',
|
||||
'scrying-pool.presets.load.emptyMessage': 'No presets',
|
||||
};
|
||||
return translations[key] || key;
|
||||
});
|
||||
@@ -276,7 +276,7 @@ describe('PresetLoadDialog', () => {
|
||||
|
||||
it('should show notification on successful load via adapter.notifications', async () => {
|
||||
adapter.i18n.localize = vi.fn((key) => {
|
||||
if (key === 'video-view-manager.presets.notifications.applied') return 'Applied preset: {name}';
|
||||
if (key === 'scrying-pool.presets.notifications.applied') return 'Applied preset: {name}';
|
||||
return key;
|
||||
});
|
||||
|
||||
@@ -398,7 +398,7 @@ describe('PresetLoadDialog', () => {
|
||||
|
||||
it('should use the correct template path', () => {
|
||||
expect(PresetLoadDialog.PARTS.dialog.template).toBe(
|
||||
'modules/video-view-manager/templates/preset-load-dialog.hbs'
|
||||
'modules/scrying-pool/templates/preset-load-dialog.hbs'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ describe('PresetSaveDialog', () => {
|
||||
|
||||
it('should return empty string as defaultName when no presets exist', async () => {
|
||||
adapter.i18n.localize = vi.fn((key) => {
|
||||
if (key === 'video-view-manager.presets.save.namePlaceholder') return 'Enter preset name';
|
||||
if (key === 'scrying-pool.presets.save.namePlaceholder') return 'Enter preset name';
|
||||
return key;
|
||||
});
|
||||
|
||||
@@ -146,11 +146,11 @@ describe('PresetSaveDialog', () => {
|
||||
it('should return all i18n labels', async () => {
|
||||
adapter.i18n.localize = vi.fn((key) => {
|
||||
const translations = {
|
||||
'video-view-manager.presets.save.saveButton': 'Save',
|
||||
'video-view-manager.presets.save.cancelButton': 'Cancel',
|
||||
'video-view-manager.presets.save.title': 'Save Preset',
|
||||
'video-view-manager.presets.save.nameLabel': 'Preset Name',
|
||||
'video-view-manager.presets.save.namePlaceholder': 'Enter preset name',
|
||||
'scrying-pool.presets.save.saveButton': 'Save',
|
||||
'scrying-pool.presets.save.cancelButton': 'Cancel',
|
||||
'scrying-pool.presets.save.title': 'Save Preset',
|
||||
'scrying-pool.presets.save.nameLabel': 'Preset Name',
|
||||
'scrying-pool.presets.save.namePlaceholder': 'Enter preset name',
|
||||
};
|
||||
return translations[key] || key;
|
||||
});
|
||||
@@ -320,7 +320,7 @@ describe('PresetSaveDialog', () => {
|
||||
scenePresetManager.save = vi.fn().mockResolvedValue({ name: 'My Preset' });
|
||||
dialog.close = vi.fn().mockResolvedValue({});
|
||||
adapter.i18n.localize = vi.fn((key) => {
|
||||
if (key === 'video-view-manager.presets.notifications.saved') return 'Preset {name} saved!';
|
||||
if (key === 'scrying-pool.presets.notifications.saved') return 'Preset {name} saved!';
|
||||
return key;
|
||||
});
|
||||
|
||||
@@ -447,7 +447,7 @@ describe('PresetSaveDialog', () => {
|
||||
|
||||
it('should use the correct template path', () => {
|
||||
expect(PresetSaveDialog.PARTS.dialog.template).toBe(
|
||||
'modules/video-view-manager/templates/preset-save-dialog.hbs'
|
||||
'modules/scrying-pool/templates/preset-save-dialog.hbs'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -459,7 +459,7 @@ describe('PresetSaveDialog', () => {
|
||||
expect(options.classes).toContain('preset-save-dialog');
|
||||
expect(options.window.title).toBe('Save Scene Preset');
|
||||
expect(options.window.resizable).toBe(false);
|
||||
expect(options.position.width).toBe(320);
|
||||
expect(options.position.width).toBe(360);
|
||||
});
|
||||
|
||||
it('should store references to dependencies', () => {
|
||||
|
||||
@@ -88,8 +88,8 @@ describe('ScenePresetPanel', () => {
|
||||
|
||||
it('sets aria-label using i18n', () => {
|
||||
panel.init();
|
||||
expect(adapter.i18n.localize).toHaveBeenCalledWith('video-view-manager.scenePresetPanel.title');
|
||||
expect(panel._element.getAttribute('aria-label')).toBe('video-view-manager.scenePresetPanel.title');
|
||||
expect(adapter.i18n.localize).toHaveBeenCalledWith('scrying-pool.scenePresetPanel.title');
|
||||
expect(panel._element.getAttribute('aria-label')).toBe('scrying-pool.scenePresetPanel.title');
|
||||
});
|
||||
|
||||
it('sets aria-expanded to false initially', () => {
|
||||
@@ -267,7 +267,7 @@ describe('ScenePresetPanel', () => {
|
||||
|
||||
it('uses i18n for message', () => {
|
||||
panel._buildEmptyHtml();
|
||||
expect(adapter.i18n.localize).toHaveBeenCalledWith('video-view-manager.scenePresetPanel.noScene');
|
||||
expect(adapter.i18n.localize).toHaveBeenCalledWith('scrying-pool.scenePresetPanel.noScene');
|
||||
});
|
||||
|
||||
it('escapes HTML in message', () => {
|
||||
@@ -450,7 +450,7 @@ describe('ScenePresetPanel', () => {
|
||||
mockTarget.checked = true;
|
||||
await panel._onToggleAutoApply(mockTarget);
|
||||
expect(adapter.notifications.info).toHaveBeenCalledWith(
|
||||
'video-view-manager.scenePresetPanel.notifications.enabled'
|
||||
'scrying-pool.scenePresetPanel.notifications.enabled'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -460,7 +460,7 @@ describe('ScenePresetPanel', () => {
|
||||
mockTarget.checked = false;
|
||||
await panel._onToggleAutoApply(mockTarget);
|
||||
expect(adapter.notifications.info).toHaveBeenCalledWith(
|
||||
'video-view-manager.scenePresetPanel.notifications.disabled'
|
||||
'scrying-pool.scenePresetPanel.notifications.disabled'
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -241,6 +241,30 @@ describe('ScryingPoolStrip', () => {
|
||||
const data = strip.getData();
|
||||
expect(data.hasStreamAccess).toBe(false);
|
||||
});
|
||||
|
||||
it('includes current user when showGMSelfFeed is true', () => {
|
||||
adapter.settings = { get: vi.fn(() => true) };
|
||||
adapter.users.all.mockReturnValue([{ id: 'u1' }, { id: 'u2' }]);
|
||||
const data = strip.getData();
|
||||
expect(data.participants.map(p => p.userId)).toContain('u1');
|
||||
expect(data.participants.map(p => p.userId)).toContain('u2');
|
||||
});
|
||||
|
||||
it('excludes current user when showGMSelfFeed is false', () => {
|
||||
adapter.settings = { get: vi.fn(() => false) };
|
||||
adapter.users.all.mockReturnValue([{ id: 'u1' }, { id: 'u2' }]);
|
||||
const data = strip.getData();
|
||||
// u1 is the current user (mocked in beforeEach), should be excluded
|
||||
expect(data.participants.map(p => p.userId)).not.toContain('u1');
|
||||
expect(data.participants.map(p => p.userId)).toContain('u2');
|
||||
});
|
||||
|
||||
it('includes all users when settings is unavailable (defaults to true)', () => {
|
||||
// no adapter.settings — fallback to true
|
||||
adapter.users.all.mockReturnValue([{ id: 'u1' }, { id: 'u2' }]);
|
||||
const data = strip.getData();
|
||||
expect(data.participants.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_attachVideoStream() (Story 5.1)', () => {
|
||||
|
||||
@@ -31,8 +31,6 @@ function createMockAdapter(overrides = {}) {
|
||||
'SCRYING_POOL.PrivacyPanel.sectionDescription': 'Control which automation effects can affect your camera.',
|
||||
'SCRYING_POOL.PrivacyPanel.reactionCamLabel': 'Reaction Cam',
|
||||
'SCRYING_POOL.PrivacyPanel.reactionCamDescription': 'Automatically show your camera during key moments (combat, rolls, etc.)',
|
||||
'SCRYING_POOL.PrivacyPanel.hpReactiveCamStylingLabel': 'HP-Reactive Cam Styling',
|
||||
'SCRYING_POOL.PrivacyPanel.hpReactiveCamStylingDescription': 'Apply visual styling to your camera based on your character\'s HP',
|
||||
'SCRYING_POOL.PrivacyPanel.toggleOn': 'Enabled',
|
||||
'SCRYING_POOL.PrivacyPanel.toggleOff': 'Disabled',
|
||||
'SCRYING_POOL.PrivacyPanel.readOnlyNotice': 'This player\'s privacy settings are read-only',
|
||||
@@ -130,7 +128,6 @@ describe('PlayerPrivacyPanel', () => {
|
||||
it('should return context with settings', async () => {
|
||||
const settings = createPrivacySettings({
|
||||
reactionCamEnabled: true,
|
||||
hpReactiveCamStylingEnabled: false,
|
||||
});
|
||||
playerPrivacyManager.getSettings.mockReturnValue(settings);
|
||||
adapter.users.current.mockReturnValue({ id: targetUserId });
|
||||
@@ -140,7 +137,7 @@ describe('PlayerPrivacyPanel', () => {
|
||||
expect(context.title).toBe('Player Privacy Panel');
|
||||
expect(context.sectionHeader).toBe('Automation Opt-ins');
|
||||
expect(context.automationEffects).toBeDefined();
|
||||
expect(context.automationEffects).toHaveLength(2);
|
||||
expect(context.automationEffects).toHaveLength(1);
|
||||
expect(context.isReadOnly).toBe(false);
|
||||
expect(context.isOwnUser).toBe(true);
|
||||
});
|
||||
@@ -156,25 +153,22 @@ describe('PlayerPrivacyPanel', () => {
|
||||
expect(context.isOwnUser).toBe(false);
|
||||
});
|
||||
|
||||
it('should include both automation effects', async () => {
|
||||
it('should include the available automation effect', async () => {
|
||||
const context = await panel._prepareContext();
|
||||
|
||||
expect(context.automationEffects).toHaveLength(2);
|
||||
expect(context.automationEffects).toHaveLength(1);
|
||||
expect(context.automationEffects[0].key).toBe('reactionCam');
|
||||
expect(context.automationEffects[1].key).toBe('hpReactiveCamStyling');
|
||||
});
|
||||
|
||||
it('should reflect current settings in context', async () => {
|
||||
const settings = createPrivacySettings({
|
||||
reactionCamEnabled: true,
|
||||
hpReactiveCamStylingEnabled: true,
|
||||
});
|
||||
playerPrivacyManager.getSettings.mockReturnValue(settings);
|
||||
|
||||
const context = await panel._prepareContext();
|
||||
|
||||
expect(context.automationEffects[0].enabled).toBe(true);
|
||||
expect(context.automationEffects[1].enabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -354,13 +348,11 @@ describe('PlayerPrivacyPanel', () => {
|
||||
it('should clear cached elements', () => {
|
||||
// Set up some cached values
|
||||
panel._reactionCamToggle = document.createElement('div');
|
||||
panel._hpReactiveCamToggle = document.createElement('div');
|
||||
panel._currentSettings = createPrivacySettings();
|
||||
|
||||
panel._onClose();
|
||||
|
||||
expect(panel._reactionCamToggle).toBe(null);
|
||||
expect(panel._hpReactiveCamToggle).toBe(null);
|
||||
expect(panel._currentSettings).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -238,7 +238,7 @@ describe('VisibilityBadge', () => {
|
||||
badge.init();
|
||||
await badge._setFirstBadgeEncountered();
|
||||
const mockUser = adapter.users.current();
|
||||
expect(mockUser.setFlag).toHaveBeenCalledWith('video-view-manager', 'firstBadgeEncounter', true);
|
||||
expect(mockUser.setFlag).toHaveBeenCalledWith('scrying-pool', 'firstBadgeEncounter', true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -390,7 +390,7 @@ describe('FirstEncounterPanel (via VisibilityBadge)', () => {
|
||||
// Directly call _onGotIt to avoid async click handler timing issues
|
||||
await panel._onGotIt();
|
||||
const mockUser = adapter.users.current();
|
||||
expect(mockUser.setFlag).toHaveBeenCalledWith('video-view-manager', 'firstBadgeEncounter', true);
|
||||
expect(mockUser.setFlag).toHaveBeenCalledWith('scrying-pool', 'firstBadgeEncounter', true);
|
||||
});
|
||||
|
||||
it('clears timer (no ghost timer after dismissal)', async () => {
|
||||
|
||||
Reference in New Issue
Block a user