fix: sync context panel iframe themes
Keeps embedded sessions aligned with parent theme Prevents iframe reloads on theme changes Supports theme hotkeys from focused iframes
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import { afterAll, beforeEach, describe, expect, test } from 'bun:test';
|
||||
import { getDefaultTheme } from '@/lib/theme/themes';
|
||||
import type { Theme } from '@/types/theme';
|
||||
import { buildEmbeddedSessionChatURL, getOrCreateEmbeddedSessionChatURL, type EmbeddedSessionChatURLCacheEntry } from './contextPanelEmbeddedChat';
|
||||
|
||||
const originalWindow = globalThis.window;
|
||||
|
||||
const installWindowLocation = (href = 'http://127.0.0.1:5173/app') => {
|
||||
const url = new URL(href);
|
||||
Object.defineProperty(globalThis, 'window', {
|
||||
configurable: true,
|
||||
value: {
|
||||
location: {
|
||||
href: url.toString(),
|
||||
origin: url.origin,
|
||||
pathname: url.pathname,
|
||||
search: url.search,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const makeTheme = (id: string, variant: 'light' | 'dark'): Theme => ({
|
||||
...getDefaultTheme(variant === 'dark'),
|
||||
metadata: {
|
||||
...getDefaultTheme(variant === 'dark').metadata,
|
||||
id,
|
||||
name: id,
|
||||
variant,
|
||||
},
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
installWindowLocation();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
Object.defineProperty(globalThis, 'window', {
|
||||
configurable: true,
|
||||
value: originalWindow,
|
||||
});
|
||||
});
|
||||
|
||||
describe('embedded session chat URL', () => {
|
||||
test('includes parent effective system theme bootstrap data', () => {
|
||||
const currentTheme = makeTheme('custom-dark', 'dark');
|
||||
|
||||
const src = buildEmbeddedSessionChatURL('ses_1', '/repo', false, {
|
||||
mode: 'system',
|
||||
lightThemeId: 'custom-light',
|
||||
darkThemeId: 'custom-dark',
|
||||
currentTheme,
|
||||
});
|
||||
|
||||
const url = new URL(src);
|
||||
expect(url.searchParams.get('ocPanel')).toBe('session-chat');
|
||||
expect(url.searchParams.get('themeMode')).toBe('system');
|
||||
expect(url.searchParams.get('themeVariant')).toBe('dark');
|
||||
expect(url.searchParams.get('lightThemeId')).toBe('custom-light');
|
||||
expect(url.searchParams.get('darkThemeId')).toBe('custom-dark');
|
||||
expect(JSON.parse(url.searchParams.get('currentTheme') || '{}').metadata.id).toBe('custom-dark');
|
||||
});
|
||||
|
||||
test('freezes bootstrap src per tab so live theme changes do not reload iframe', () => {
|
||||
const cache = new Map<string, EmbeddedSessionChatURLCacheEntry>();
|
||||
const first = getOrCreateEmbeddedSessionChatURL(cache, 'tab-1', 'ses_1', '/repo', false, {
|
||||
mode: 'system',
|
||||
lightThemeId: 'light-a',
|
||||
darkThemeId: 'dark-a',
|
||||
currentTheme: makeTheme('dark-a', 'dark'),
|
||||
});
|
||||
|
||||
const second = getOrCreateEmbeddedSessionChatURL(cache, 'tab-1', 'ses_1', '/repo', false, {
|
||||
mode: 'light',
|
||||
lightThemeId: 'light-b',
|
||||
darkThemeId: 'dark-b',
|
||||
currentTheme: makeTheme('light-b', 'light'),
|
||||
});
|
||||
|
||||
expect(second).toBe(first);
|
||||
expect(new URL(second).searchParams.get('themeVariant')).toBe('dark');
|
||||
});
|
||||
|
||||
test('rebuilds cached src when readOnly changes for an existing tab', () => {
|
||||
const cache = new Map<string, EmbeddedSessionChatURLCacheEntry>();
|
||||
const theme = {
|
||||
mode: 'system' as const,
|
||||
lightThemeId: 'light-a',
|
||||
darkThemeId: 'dark-a',
|
||||
currentTheme: makeTheme('dark-a', 'dark'),
|
||||
};
|
||||
|
||||
const writable = getOrCreateEmbeddedSessionChatURL(cache, 'tab-1', 'ses_1', '/repo', false, theme);
|
||||
const readOnly = getOrCreateEmbeddedSessionChatURL(cache, 'tab-1', 'ses_1', '/repo', true, theme);
|
||||
|
||||
expect(readOnly).not.toBe(writable);
|
||||
expect(new URL(writable).searchParams.get('readOnly')).toBeNull();
|
||||
expect(new URL(readOnly).searchParams.get('readOnly')).toBe('1');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user