Files
mermaid-live-editor/tests/history.spec.ts
T
Sidharth VinodandClaude Opus 4.8 64e8822e32 fix: Make svelte-check pass and resolve TS6/Svelte 5.56 type errors
Adding the `svelte-check` CI gate surfaced pre-existing type errors and
warnings under develop's TypeScript 6 / Svelte 5.56 bump. Fixes them so
`pnpm check` reports 0 errors / 0 warnings:

- Add `lang="ts"` to Share/Privacy (and a script to PrivacyPolicyLink) so
  importers get real declarations instead of implicit `any`.
- Replace the deprecated `monaco.languages.json` with the new top-level
  `monaco.json` namespace (proper API, no casts).
- Navbar: use `resolve('/', {})` instead of the deprecated `base`.
- Type the promo `component` as `Component<{ closeBanner: Snippet }>` and
  MainMenu's `renderer` as `Snippet<[Omit<MenuItem, 'renderer'>]>`.
- Index-by-string casts in state.ts / Preset / DiagramDocumentationButton.
- Make Actions' clipboard handler accept an optional event.
- toggle-group: expose variant/size via getters to fix the
  state_referenced_locally warning.
- Make the History e2e save/delete cases change state via a sample
  diagram (deterministic) instead of editor typing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 19:53:25 +05:30

129 lines
5.0 KiB
TypeScript

import { expect, test, type Page } from '@playwright/test';
const config = '{\n "theme": "default"\n}';
const entry = (id: string, name: string, type: 'manual' | 'auto', label: string) => ({
id,
name,
type,
time: Number(id.slice(2)),
state: {
code: `flowchart TD\n A[${label}]`,
mermaid: config,
autoSync: true,
updateDiagram: false
}
});
const manualHistory = [
entry('m-2', 'hollow-art', 'manual', 'Halloween'),
entry('m-1', 'helpful-ocean', 'manual', 'Pumpkin')
];
const autoHistory = [
entry('a-2', 'barking-dog', 'auto', 'NewYear'),
entry('a-1', 'needy-mosquito', 'auto', 'Fireworks')
];
const openHistory = (page: Page) => page.getByRole('button', { name: 'History' }).click();
test.describe('History', () => {
test.beforeEach(async ({ page }) => {
// Freeze time so auto-save snapshots are deterministic.
await page.addInitScript(() => {
Object.defineProperty(Date, 'now', { value: () => new Date(2022, 0, 1).getTime() });
});
await page.goto('/edit');
});
test('loads Saved and Timeline history from localStorage and restores entries', async ({
page
}) => {
await page.evaluate(
([manual, auto]) => {
localStorage.setItem('manualHistoryStore', manual);
localStorage.setItem('autoHistoryStore', auto);
},
[JSON.stringify(manualHistory), JSON.stringify(autoHistory)]
);
await page.reload();
await openHistory(page);
// Saved tab is active by default.
await expect(page.locator('#historyList li')).toHaveCount(2);
await expect(page.locator('#historyList')).toContainText('hollow-art');
await expect(page.locator('#historyList')).toContainText('helpful-ocean');
await page.getByRole('button', { name: 'Restore this version' }).first().click();
await expect(page.locator('#view')).toContainText('Halloween');
// Switching to the Timeline tab shows the auto entries only.
await page.getByRole('tab', { name: 'Timeline' }).click();
await expect(page.locator('#historyList li')).toHaveCount(2);
await expect(page.locator('#historyList')).toContainText('barking-dog');
await expect(page.locator('#historyList')).toContainText('needy-mosquito');
await expect(page.locator('#historyList')).not.toContainText('hollow-art');
await page.getByRole('button', { name: 'Restore this version' }).first().click();
await expect(page.locator('#view')).toContainText('NewYear');
});
test('keeps the active tab highlighted when switching modes', async ({ page }) => {
await openHistory(page);
const saved = page.getByRole('tab', { name: 'Saved' });
const timeline = page.getByRole('tab', { name: 'Timeline' });
await expect(saved).toHaveClass(/border-b-2/);
await expect(timeline).not.toHaveClass(/border-b-2/);
await timeline.click();
await expect(timeline).toHaveClass(/border-b-2/);
await expect(saved).not.toHaveClass(/border-b-2/);
});
test('saves the current state and reports duplicates', async ({ page }) => {
await openHistory(page);
await expect(page.locator('#historyList li')).toHaveCount(0);
await page.locator('#saveHistory').click();
await expect(page.locator('#historyList li')).toHaveCount(1);
// Saving again without changes does not add a duplicate and notifies the user.
await page.locator('#saveHistory').click();
await expect(page.getByText('State already saved.')).toBeVisible();
await expect(page.locator('#historyList li')).toHaveCount(1);
// Loading a different sample changes the state, so it saves as a new entry.
await page.getByRole('button', { name: 'Sequence', exact: true }).click();
await expect(page.locator('#view')).not.toContainText('Christmas');
await page.locator('#saveHistory').click();
await expect(page.locator('#historyList li')).toHaveCount(2);
});
test('auto-saves to the Timeline only, never the Saved list', async ({ page }) => {
await openHistory(page);
await page.locator('#saveHistory').click();
await expect(page.locator('#historyList li')).toHaveCount(1);
await page.getByRole('tab', { name: 'Timeline' }).click();
// A manual save must not appear under Timeline.
await expect(page.locator('#historyList')).toContainText('No timeline snapshots yet.');
});
test('deletes a single entry and clears all after confirmation', async ({ page }) => {
await openHistory(page);
await page.locator('#saveHistory').click();
await page.getByRole('button', { name: 'Sequence', exact: true }).click();
await expect(page.locator('#view')).not.toContainText('Christmas');
await page.locator('#saveHistory').click();
await expect(page.locator('#historyList li')).toHaveCount(2);
await page.getByRole('button', { name: 'Delete this version' }).first().click();
await expect(page.locator('#historyList li')).toHaveCount(1);
page.on('dialog', (dialog) => dialog.accept());
await page.locator('#clearHistory').click();
await expect(page.locator('#historyList li')).toHaveCount(0);
await expect(page.locator('#historyList')).toContainText('No saved states yet.');
});
});