open-design/e2e/ui/design-systems-manager.test.ts
Amy 1c2a1c4459
Add launch review regression coverage and stabilize daemon tests (#3207)
* Add launch review E2E regression coverage

* Harden daemon launch review regressions

* Stabilize daemon runtime tests

* fix(tests): restore e2e preflight typing

Generated-By: looper 0.8.1 (runner=fixer, agent=codex)

* fix(tests): make fake plugin runtime ESM-safe

Generated-By: looper 0.8.1 (runner=fixer, agent=codex)

* Stabilize e2e fake agent and regression tests

* fix(tests): repair fake agent cjs runtime

Generated-By: looper 0.8.1 (runner=fixer, agent=codex)

* fix(review): harden plugin authoring checks

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)

* fix(tests): bind plugin authoring run to seeded conversation

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)
2026-05-29 02:39:33 +00:00

349 lines
11 KiB
TypeScript

import { expect, test } from '@playwright/test';
import type { Page } from '@playwright/test';
const STORAGE_KEY = 'open-design:config';
type UserSystem = {
id: string;
title: string;
category: string;
summary: string;
surface: 'web' | 'image' | 'video' | 'audio';
source: 'user';
status: 'draft' | 'published';
updatedAt: string;
};
function requireSystem(system: UserSystem | undefined): UserSystem {
if (!system) throw new Error('design system fixture missing');
return system;
}
function baseConfig(): Record<string, unknown> {
return {
mode: 'daemon',
apiKey: '',
apiProtocol: 'anthropic',
apiVersion: '',
baseUrl: 'https://api.anthropic.com',
model: 'claude-sonnet-4-5',
apiProviderBaseUrl: 'https://api.anthropic.com',
agentId: 'codex',
skillId: null,
designSystemId: null,
onboardingCompleted: true,
mediaProviders: {},
agentModels: {},
agentCliEnv: {},
};
}
async function seedEntryBase(page: Page, override?: Record<string, unknown>) {
await page.addInitScript(
({ key, value }) => {
window.localStorage.setItem(key, JSON.stringify(value));
},
{ key: STORAGE_KEY, value: { ...baseConfig(), ...override } },
);
}
async function waitForLoadingToClear(page: Page) {
await expect(page.getByText('Loading Open Design…')).toHaveCount(0, { timeout: 15_000 });
}
async function gotoEntryHome(page: Page) {
await page.goto('/', { waitUntil: 'domcontentloaded' });
await waitForLoadingToClear(page);
const privacyDialog = page.getByRole('dialog').filter({ hasText: 'Help us improve Open Design' });
if (await privacyDialog.isVisible().catch(() => false)) {
await privacyDialog.getByRole('button', { name: /not now/i }).click();
}
await expect(page.getByTestId('home-hero')).toBeVisible();
}
async function routeDesignSystemsManager(
page: Page,
systems: UserSystem[],
{
initialConfig,
}: {
initialConfig?: Partial<Record<string, unknown>>;
} = {},
) {
const persistedConfigs: Array<{ designSystemId?: string | null }> = [];
let currentConfig = { ...baseConfig(), ...(initialConfig ?? {}) };
await page.route('**/api/**', async (route) => {
const url = new URL(route.request().url());
const method = route.request().method();
const path = url.pathname;
if (path === '/api/health') {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"ok":true}' });
return;
}
if (path === '/api/agents') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
agents: [
{
id: 'codex',
name: 'Codex CLI',
bin: 'codex',
available: true,
version: '0.130.0',
models: [{ id: 'default', label: 'Default' }],
},
],
}),
});
return;
}
if (path === '/api/app-config') {
if (method === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ config: currentConfig }),
});
return;
}
if (method === 'PUT') {
const body = route.request().postDataJSON() as { designSystemId?: string | null };
persistedConfigs.push(body);
currentConfig = { ...currentConfig, ...body };
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"ok":true}' });
return;
}
}
if (path === '/api/connectors/composio/config') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: '{"configured":false,"apiKeyTail":""}',
});
return;
}
if (path === '/api/media/config' && method === 'GET') {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"providers":{}}' });
return;
}
if (path === '/api/media/config' && method === 'PUT') {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"ok":true}' });
return;
}
if (path === '/api/skills') {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"skills":[]}' });
return;
}
if (path === '/api/design-systems' && method === 'GET') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({ designSystems: systems }),
});
return;
}
if (/^\/api\/design-systems\/[^/]+$/.test(path) && method === 'PATCH') {
const id = decodeURIComponent(path.split('/').at(-1) ?? '');
const body = route.request().postDataJSON() as { status?: 'draft' | 'published' };
const system = systems.find((entry) => entry.id === id);
if (system && body.status) {
system.status = body.status;
}
const responseSystem = requireSystem(system ?? systems[0]);
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
designSystem: {
...responseSystem,
body: `# ${responseSystem.title}`,
},
}),
});
return;
}
if (/^\/api\/design-systems\/[^/]+$/.test(path) && method === 'DELETE') {
const id = decodeURIComponent(path.split('/').at(-1) ?? '');
const index = systems.findIndex((entry) => entry.id === id);
if (index >= 0) systems.splice(index, 1);
await route.fulfill({
status: 200,
contentType: 'application/json',
body: '{"ok":true}',
});
return;
}
if (/^\/api\/design-systems\/[^/]+$/.test(path) && method === 'GET') {
const id = decodeURIComponent(path.split('/').at(-1) ?? '');
const system = requireSystem(systems.find((entry) => entry.id === id) ?? systems[0]);
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
designSystem: {
...system,
body: `# ${system.title}`,
},
}),
});
return;
}
if (path === '/api/projects') {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"projects":[]}' });
return;
}
if (path === '/api/plugins') {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"plugins":[]}' });
return;
}
if (path === '/api/prompt-templates') {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"promptTemplates":[]}' });
return;
}
if (path === '/api/templates') {
await route.fulfill({ status: 200, contentType: 'application/json', body: '{"templates":[]}' });
return;
}
await route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
});
return { persistedConfigs };
}
test('publishing a user design system promotes it to the default system in the manager', async ({ page }) => {
await seedEntryBase(page);
const systems: UserSystem[] = [
{
id: 'brand-alpha',
title: 'Brand Alpha',
category: 'Productivity & SaaS',
summary: 'Draft internal design system.',
surface: 'web',
source: 'user',
status: 'draft',
updatedAt: '2026-05-28T01:00:00.000Z',
},
{
id: 'brand-beta',
title: 'Brand Beta',
category: 'Productivity & SaaS',
summary: 'Published baseline system.',
surface: 'web',
source: 'user',
status: 'published',
updatedAt: '2026-05-28T00:00:00.000Z',
},
];
const { persistedConfigs } = await routeDesignSystemsManager(page, systems);
await gotoEntryHome(page);
await page.getByTestId('entry-nav-design-systems').click();
await expect(page).toHaveURL(/\/design-systems$/);
await page.getByRole('tab', { name: 'Your systems' }).click();
const manager = page.locator('section[aria-label="Your design systems"]');
const alphaRow = manager.locator('.ds-user-row').filter({ hasText: 'Brand Alpha' });
await expect(alphaRow.getByRole('button', { name: 'Make default' })).toHaveCount(0);
await alphaRow.locator('.ds-status-toggle').click();
await expect(alphaRow.locator('.ds-status-toggle')).toContainText('Published');
await expect(alphaRow.getByText('Default')).toBeVisible();
await expect
.poll(() => persistedConfigs.at(-1)?.designSystemId)
.toBe('brand-alpha');
});
test('filters user design systems by draft and published status in the manager', async ({ page }) => {
await seedEntryBase(page);
const systems: UserSystem[] = [
{
id: 'brand-alpha',
title: 'Brand Alpha',
category: 'Productivity & SaaS',
summary: 'Draft internal design system.',
surface: 'web',
source: 'user',
status: 'draft',
updatedAt: '2026-05-28T01:00:00.000Z',
},
{
id: 'brand-beta',
title: 'Brand Beta',
category: 'Productivity & SaaS',
summary: 'Published baseline system.',
surface: 'web',
source: 'user',
status: 'published',
updatedAt: '2026-05-28T00:00:00.000Z',
},
];
await routeDesignSystemsManager(page, systems);
await gotoEntryHome(page);
await page.getByTestId('entry-nav-design-systems').click();
await expect(page).toHaveURL(/\/design-systems$/);
await page.getByRole('tab', { name: 'Your systems' }).click();
const manager = page.locator('section[aria-label="Your design systems"]');
const filter = manager.getByRole('combobox', { name: 'Filter design systems' });
await filter.selectOption('published');
await expect(manager.getByText('Brand Beta')).toBeVisible();
await expect(manager.getByText('Brand Alpha')).toHaveCount(0);
await filter.selectOption('draft');
await expect(manager.getByText('Brand Alpha')).toBeVisible();
await expect(manager.getByText('Brand Beta')).toHaveCount(0);
});
test('deleting the active design system falls back to another user system', async ({ page }) => {
await seedEntryBase(page, { designSystemId: 'brand-alpha' });
const systems: UserSystem[] = [
{
id: 'brand-alpha',
title: 'Brand Alpha',
category: 'Productivity & SaaS',
summary: 'Primary published system.',
surface: 'web',
source: 'user',
status: 'published',
updatedAt: '2026-05-28T01:00:00.000Z',
},
{
id: 'brand-beta',
title: 'Brand Beta',
category: 'Productivity & SaaS',
summary: 'Fallback published system.',
surface: 'web',
source: 'user',
status: 'published',
updatedAt: '2026-05-28T00:00:00.000Z',
},
];
const { persistedConfigs } = await routeDesignSystemsManager(page, systems, {
initialConfig: { designSystemId: 'brand-alpha' },
});
await gotoEntryHome(page);
await page.getByTestId('entry-nav-design-systems').click();
await expect(page).toHaveURL(/\/design-systems$/);
await page.getByRole('tab', { name: 'Your systems' }).click();
page.once('dialog', (dialog) => dialog.accept());
const manager = page.locator('section[aria-label="Your design systems"]');
const alphaRow = manager.locator('.ds-user-row').filter({ hasText: 'Brand Alpha' });
await alphaRow.getByRole('button', { name: 'Delete Brand Alpha' }).click();
await expect(alphaRow).toHaveCount(0);
await expect
.poll(() => persistedConfigs.at(-1)?.designSystemId)
.toBe('brand-beta');
const betaRow = manager.locator('.ds-user-row').filter({ hasText: 'Brand Beta' });
await expect(betaRow.getByText('Default')).toBeVisible();
});