From c6ca988e403a05c9d4d80d4a5355853e7c1109c4 Mon Sep 17 00:00:00 2001 From: Oleh Omelchenko Date: Thu, 25 Jun 2026 01:08:56 +0300 Subject: [PATCH] Tests: drop change-detector component tests --- src/app/components/AboutModal.test.tsx | 75 ------------------- src/app/components/ChartBuilderModal.test.tsx | 29 ------- src/app/components/ColorControls.test.tsx | 24 ------ src/app/components/DonateModal.test.tsx | 55 -------------- src/app/components/Icon.test.tsx | 18 ----- src/app/components/LivePreview.test.tsx | 5 -- src/app/components/Onboarding.test.tsx | 13 ---- 7 files changed, 219 deletions(-) delete mode 100644 src/app/components/AboutModal.test.tsx delete mode 100644 src/app/components/DonateModal.test.tsx diff --git a/src/app/components/AboutModal.test.tsx b/src/app/components/AboutModal.test.tsx deleted file mode 100644 index 1c68f8f..0000000 --- a/src/app/components/AboutModal.test.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { afterEach, beforeEach, describe, expect, test } from 'vitest'; -import { act } from 'react'; -import { createRoot, type Root } from 'react-dom/client'; -import { AboutModal } from './AboutModal'; - -(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; - -let container: HTMLDivElement; -let root: Root; - -beforeEach(() => { - container = document.createElement('div'); - document.body.appendChild(container); - root = createRoot(container); - act(() => root.render()); -}); - -afterEach(() => { - act(() => root.unmount()); - container.remove(); -}); - -describe('AboutModal', () => { - test('renders the app name', () => { - expect(container.textContent).toContain('Astrolabe'); - }); - - test('renders the app version from __APP_VERSION__', () => { - // __APP_VERSION__ is injected by vite.config.ts `define` (shared with Vitest). - expect(container.textContent).toContain(__APP_VERSION__); - }); - - test('renders all five keyboard shortcuts from spec §01D', () => { - // Platform-specific modifier (Cmd on Mac, Ctrl elsewhere) + the five actions. - const text = container.textContent ?? ''; - // Key combinations — platform-aware modifier is either ⌘ or Ctrl - expect(text).toMatch(/(?:⌘|Ctrl)\+Shift\+N/); - expect(text).toMatch(/(?:⌘|Ctrl)\+K/); - expect(text).toMatch(/(?:⌘|Ctrl)\+S/); - expect(text).toMatch(/(?:⌘|Ctrl)\+,/); - expect(text).toContain('Esc'); - }); - - test('shortcuts are in an accessible table with an aria-label', () => { - const table = container.querySelector('table[aria-label]'); - expect(table).not.toBeNull(); - expect(table!.getAttribute('aria-label')).toBe('Keyboard shortcuts'); - }); - - test('renders a Privacy section that mentions local-first posture', () => { - const text = container.textContent ?? ''; - // Core privacy claims from SOUL.md / spec §10 - expect(text).toMatch(/no account/i); - expect(text).toMatch(/no telemetry|no analytics|no tracking/i); - expect(text).toMatch(/offline/i); - }); - - test('has labelled sections: identity, shortcuts, privacy, feedback', () => { - const headings = Array.from(container.querySelectorAll('h3')).map( - (h) => h.textContent?.toLowerCase() ?? '', - ); - expect(headings.some((h) => h.includes('astrolabe'))).toBe(true); - expect(headings.some((h) => h.includes('keyboard'))).toBe(true); - expect(headings.some((h) => h.includes('privacy'))).toBe(true); - expect(headings.some((h) => h.includes('feedback'))).toBe(true); - }); - - test('offers the feedback address as a mailto link', () => { - const mailto = Array.from(container.querySelectorAll('a')).find((a) => - a.getAttribute('href')?.startsWith('mailto:'), - ); - expect(mailto).toBeTruthy(); - expect(mailto!.getAttribute('href')).toContain('feedback@astrolabe-viz.com'); - }); -}); diff --git a/src/app/components/ChartBuilderModal.test.tsx b/src/app/components/ChartBuilderModal.test.tsx index fcc11d9..e28593e 100644 --- a/src/app/components/ChartBuilderModal.test.tsx +++ b/src/app/components/ChartBuilderModal.test.tsx @@ -157,35 +157,6 @@ describe('ChartBuilderModal', () => { vi.useRealTimers(); }); - test('shows the no-datasets empty state with its one next step (3D)', async () => { - await act(async () => { - root.render(); - await Promise.resolve(); - }); - expect(container.textContent).toContain('No datasets yet'); - const action = Array.from(container.querySelectorAll('button')).find( - (b) => b.textContent === 'Add a dataset', - ); - expect(action).toBeDefined(); - }); - - test('offers a dataset chooser when datasets exist but none is loaded', async () => { - const ds = createDataset({ - name: 'Waiting', - data: [{ a: 1 }], - format: 'json', - source: 'inline', - now: T, - }); - useDatasetStore.getState().add(ds); - - await act(async () => { - root.render(); - await Promise.resolve(); - }); - expect(container.textContent).toContain('Choose a dataset'); - }); - test('a complete filter row reaches the renderer as a top-level transform (1C)', async () => { vi.useFakeTimers(); const { renderSpec } = await import('../services/chart-renderer'); diff --git a/src/app/components/ColorControls.test.tsx b/src/app/components/ColorControls.test.tsx index 8578c5a..0f4346c 100644 --- a/src/app/components/ColorControls.test.tsx +++ b/src/app/components/ColorControls.test.tsx @@ -165,16 +165,6 @@ describe('ColorControls', () => { expect(range().ramp).toEqual(range().heatmap); }); - test('scheme dropdown options carry a color preview', () => { - render(); - open({}); - act(() => picker('Categorical color scheme')!.click()); - - const tableau = button('Tableau 10')!; - // The decorative swatch strip renders as spans inside the option button. - expect(tableau.querySelectorAll('span span').length).toBeGreaterThan(0); - }); - test('picking a scheme writes range.category as a Vega scheme object', () => { render(); open({}); @@ -217,20 +207,6 @@ describe('ColorControls', () => { expect(picker('Font family')).toBeTruthy(); }); - test('font options render their name in their own family', () => { - render(); - open({}); - - const typeTab = [...container.querySelectorAll('button')].find( - (b) => b.getAttribute('role') === 'tab' && b.textContent === 'Type', - )!; - act(() => typeTab.click()); - act(() => picker('Font family')!.click()); - - const georgia = button('Georgia')!; - expect(georgia.querySelector('span')!.style.fontFamily).toContain('Georgia'); - }); - test('the raw JSON is collapsed by default and toggles open', () => { render(); open({}); diff --git a/src/app/components/DonateModal.test.tsx b/src/app/components/DonateModal.test.tsx deleted file mode 100644 index 07145ab..0000000 --- a/src/app/components/DonateModal.test.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { afterEach, beforeEach, describe, expect, test } from 'vitest'; -import { act } from 'react'; -import { createRoot, type Root } from 'react-dom/client'; -import { DonateModal } from './DonateModal'; - -(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; - -let container: HTMLDivElement; -let root: Root; - -beforeEach(() => { - container = document.createElement('div'); - document.body.appendChild(container); - root = createRoot(container); - act(() => root.render()); -}); - -afterEach(() => { - act(() => root.unmount()); - container.remove(); -}); - -const links = () => Array.from(container.querySelectorAll('a')); - -describe('DonateModal (Support)', () => { - test('renders a sincere message referencing the project and feedback', () => { - const text = container.textContent ?? ''; - expect(text).toMatch(/astrolabe/i); - expect(text).toMatch(/feedback/i); - }); - - test('offers the feedback address as a mailto link', () => { - const mailto = links().find((a) => a.getAttribute('href')?.startsWith('mailto:')); - expect(mailto).toBeTruthy(); - expect(mailto!.getAttribute('href')).toContain('feedback@astrolabe-viz.com'); - expect(mailto!.textContent).toContain('feedback@astrolabe-viz.com'); - }); - - test('provides a copy-address button', () => { - const copy = Array.from(container.querySelectorAll('button')).find((b) => - /copy/i.test(b.textContent ?? ''), - ); - expect(copy).toBeTruthy(); - }); - - test('the donation CTA points to Ukraine-defense and opens safely in a new tab', () => { - const donate = links().find( - (a) => a.getAttribute('href') === 'https://savelife.in.ua/en/donate-en/', - ); - expect(donate).toBeTruthy(); - expect(donate!.getAttribute('target')).toBe('_blank'); - expect(donate!.getAttribute('rel')).toContain('noopener'); - expect((donate!.textContent ?? '').trim().length).toBeGreaterThan(0); - }); -}); diff --git a/src/app/components/Icon.test.tsx b/src/app/components/Icon.test.tsx index 3d661af..9891369 100644 --- a/src/app/components/Icon.test.tsx +++ b/src/app/components/Icon.test.tsx @@ -27,24 +27,6 @@ function render(node: React.ReactNode) { } describe('Icon', () => { - test('renders an SVG on the Carbon 32-grid, decorative and unfocusable', () => { - const svg = render(); - expect(svg.getAttribute('viewBox')).toBe('0 0 32 32'); - // Decorative by default: the enclosing control carries the accessible name. - expect(svg.getAttribute('aria-hidden')).toBe('true'); - expect(svg.getAttribute('focusable')).toBe('false'); - }); - - test('each name draws a distinct glyph from the registry', () => { - // close is a single polygon; delete (TrashCan) is rects + a path; dataset - // (DataTable) is six cells + a path. Distinct geometry ⇒ distinct meaning. - expect(render().querySelector('polygon')).not.toBeNull(); - const del = render(); - expect(del.querySelectorAll('rect').length).toBe(3); - expect(del.querySelector('path')).not.toBeNull(); - expect(render().querySelectorAll('rect').length).toBe(6); - }); - test('size maps to a single, changeable class token', () => { const sm = render(); // default const smClass = sm.getAttribute('class') ?? ''; diff --git a/src/app/components/LivePreview.test.tsx b/src/app/components/LivePreview.test.tsx index 866efb6..35551d9 100644 --- a/src/app/components/LivePreview.test.tsx +++ b/src/app/components/LivePreview.test.tsx @@ -110,11 +110,6 @@ describe('LivePreview busy overlay', () => { expect(overlay()).not.toBeNull(); }); - test('overlay carries a visible label for sighted users', () => { - act(() => usePreviewStore.setState({ busy: true })); - expect(overlay()?.textContent).toMatch(/rendering/i); - }); - test('the preview body carries aria-busy=true when busy', () => { act(() => usePreviewStore.setState({ busy: true })); // The body element has aria-busy when the store says busy. diff --git a/src/app/components/Onboarding.test.tsx b/src/app/components/Onboarding.test.tsx index 2b6b9c5..cac9eb5 100644 --- a/src/app/components/Onboarding.test.tsx +++ b/src/app/components/Onboarding.test.tsx @@ -51,19 +51,6 @@ function click(name: string) { } describe('Onboarding', () => { - test('greets the user and offers the primary create action', () => { - expect(container.textContent).toContain('Welcome to Astrolabe'); - expect(container.textContent).toContain('Create your first snippet'); - }); - - test('renders one card per example, each with an Add control', () => { - for (const example of CHART_EXAMPLES) { - expect(container.textContent).toContain(example.name); - expect(container.textContent).toContain(example.description); - expect(container.querySelector(`button[aria-label="Add ${example.name}"]`)).not.toBeNull(); - } - }); - test('"Create your first snippet" creates one snippet from the sample template', () => { click('Create your first snippet'); const { snippets, activeSnippetId } = useSnippetStore.getState();