diff --git a/apps/docs/src/components/example-block.browser.test.tsx b/apps/docs/src/components/example-block.browser.test.tsx index 7defb1e4..7feb192e 100644 --- a/apps/docs/src/components/example-block.browser.test.tsx +++ b/apps/docs/src/components/example-block.browser.test.tsx @@ -34,14 +34,6 @@ test('shows a named loading state in a frame that reserves the preview space', ( expect(playgroundPlaceholder.closest('[inert]')?.inert).toBe(true); }); -test('keeps docs block spacing on the example frame', () => { - renderExample(exampleTitle); - - const frameStyles = getComputedStyle(page.getByRole('region', { name: loadingLabel }).element()); - expect(frameStyles.marginTop).toBe('16px'); - expect(frameStyles.marginBottom).toBe('16px'); -}); - function renderExample(title: string) { container = document.body.appendChild(document.createElement('div')); container.className = `luke-ui-theme ${tactileThemeClassName}`; diff --git a/apps/docs/src/components/page-actions.browser.test.tsx b/apps/docs/src/components/page-actions.browser.test.tsx index 1e361f02..6a9f3743 100644 --- a/apps/docs/src/components/page-actions.browser.test.tsx +++ b/apps/docs/src/components/page-actions.browser.test.tsx @@ -122,17 +122,6 @@ test('does not claim success when the markdown fetch 404s', async () => { } }); -test('does not announce the brand marks as separate content', async () => { - renderActions({ githubUrl, markdownUrl, reactAriaUrl, sourceUrl, storybookUrl }); - - // Each pill's accessible name comes from its visible label alone — the - // brand mark inside it is `aria-hidden`, not a second named element. - await expect.element(page.getByRole('link', { name: 'Storybook' })).toBeVisible(); - expect(page.getByRole('img', { name: /storybook/i })).not.toBeInTheDocument(); - expect(page.getByRole('img', { name: /react aria/i })).not.toBeInTheDocument(); - expect(page.getByRole('img', { name: /github/i })).not.toBeInTheDocument(); -}); - function renderActions(props: { githubUrl: string; markdownUrl: string; diff --git a/apps/docs/src/lib/example-block-sources.test.ts b/apps/docs/src/lib/example-block-sources.test.ts index 074f5800..3bc7d907 100644 --- a/apps/docs/src/lib/example-block-sources.test.ts +++ b/apps/docs/src/lib/example-block-sources.test.ts @@ -1,5 +1,3 @@ -import { readFileSync } from 'node:fs'; -import { resolve } from 'node:path'; import { expect, test } from 'vite-plus/test'; import { exampleBlockSources } from './example-block-sources.js'; @@ -12,21 +10,6 @@ test('reads src from a multi-line ExampleBlock tag', () => { ).toEqual(['overview/concentric-radius']); }); -test('reads every ExampleBlock src on the token-reference page', () => { - const contents = readFileSync( - resolve(import.meta.dirname, '../../content/docs/docs/token-reference.mdx'), - 'utf8', - ); - - expect(exampleBlockSources(contents)).toEqual([ - 'theming/semantic-variables', - 'overview/spacing-scale', - 'overview/radius-roles', - 'overview/concentric-radius', - 'overview/depth', - ]); -}); - test('does not take src from later markup after an ExampleBlock with no src', () => { expect( exampleBlockSources(` diff --git a/packages/@luke-ui/react/src/conformance/manifest.test.ts b/packages/@luke-ui/react/src/conformance/manifest.test.ts index d2c864be..73dc721d 100644 --- a/packages/@luke-ui/react/src/conformance/manifest.test.ts +++ b/packages/@luke-ui/react/src/conformance/manifest.test.ts @@ -167,24 +167,3 @@ test('accepts a conformance helper when path is not the first property', () => { `; expect(getBrowserCoverageErrors([button], () => source)).toEqual([]); }); - -test('accepts the generated helper shape', () => { - const [button] = componentTestManifest.filter((entry) => entry.path === 'button'); - if (button == null) throw new Error('Expected the Button manifest entry.'); - - const source = ` - testConformance({ - path: 'button', - getTarget: (result) => { - const target = result.locator.getByRole('button').element(); - if (!(target instanceof HTMLElement)) throw new Error('Expected a button.'); - return target; - }, - render: (props = {}) => { - return render(); - }, - }); - testIntegration('button', async () => {}); - `; - expect(getBrowserCoverageErrors([button], () => source)).toEqual([]); -}); diff --git a/packages/@luke-ui/react/src/heading/heading.browser.test.tsx b/packages/@luke-ui/react/src/heading/heading.browser.test.tsx index a1b57b24..324cd2e6 100644 --- a/packages/@luke-ui/react/src/heading/heading.browser.test.tsx +++ b/packages/@luke-ui/react/src/heading/heading.browser.test.tsx @@ -1,4 +1,4 @@ -import { expect, test } from 'vite-plus/test'; +import { test } from 'vite-plus/test'; import { testConformance } from '../conformance/helpers.js'; import { render } from '../test-utils/render.js'; import { Heading, HeadingLevels, useHeadingLevel } from './index.js'; @@ -13,6 +13,8 @@ testConformance({ render: (props = {}) => render(Section title), }); +// `getByRole` throws when the heading is missing; `.element()` forces the query to run. +// oxlint-disable-next-line vitest/expect-expect test('keeps semantic heading level independent of visual type style', () => { const { locator } = render( @@ -20,12 +22,12 @@ test('keeps semantic heading level independent of visual type style', () => { , ); - const styled = locator.getByRole('heading', { level: 2, name: 'Styled as heading3' }).element(); - - expect(styled.tagName).toBe('H2'); + locator.getByRole('heading', { level: 2, name: 'Styled as heading3' }).element(); }); -test('useHeadingLevel reads the current level without advancing it', async () => { +// Nested `HeadingLevels` must advance; `useHeadingLevel` must not. +// oxlint-disable-next-line vitest/expect-expect +test('useHeadingLevel reads the current level without advancing it', () => { function CurrentLevel({ label }: { label: string }) { const { element: Element, level } = useHeadingLevel(); return {`${label} h${level}`}; @@ -40,10 +42,6 @@ test('useHeadingLevel reads the current level without advancing it', async () => , ); - expect(locator.getByRole('heading', { level: 2, name: 'current h2' }).element().tagName).toBe( - 'H2', - ); - expect(locator.getByRole('heading', { level: 3, name: 'nested h3' }).element().tagName).toBe( - 'H3', - ); + locator.getByRole('heading', { level: 2, name: 'current h2' }).element(); + locator.getByRole('heading', { level: 3, name: 'nested h3' }).element(); }); diff --git a/packages/@luke-ui/react/src/theme/contract.test.ts b/packages/@luke-ui/react/src/theme/contract.test.ts index 8b58c7d0..bdb90e81 100644 --- a/packages/@luke-ui/react/src/theme/contract.test.ts +++ b/packages/@luke-ui/react/src/theme/contract.test.ts @@ -110,13 +110,10 @@ describe('theme contract', () => { } }); - it('exposes overlay backdrop as the only overlay leaf, and no longer has scrim', () => { - const byPath = new Map(flattenThemeContract()); + it('exposes overlay backdrop as the only overlay leaf', () => { expect(vars.color.overlay).toEqual({ backdrop: 'var(--luke-color-overlay-backdrop)', }); - expect(byPath.get('color.overlay.backdrop')).toBe('--luke-color-overlay-backdrop'); - expect(Object.hasOwn(vars.color, 'scrim')).toBe(false); }); it('derives the spacing contract keys from the spacing scale', () => { diff --git a/packages/@luke-ui/react/src/theme/define-theme.test.ts b/packages/@luke-ui/react/src/theme/define-theme.test.ts index d999fa16..a23968b2 100644 --- a/packages/@luke-ui/react/src/theme/define-theme.test.ts +++ b/packages/@luke-ui/react/src/theme/define-theme.test.ts @@ -283,7 +283,6 @@ describe('normalizeTheme resolves source colours once onto the foundation', () = expect(light.danger).toEqual(gamutMapOklch(parseColor(defaultSourceColors.light.danger))); expect(light.focus).toEqual(gamutMapOklch(parseColor(defaultSourceColors.light.focus))); expect(light.backdrop).toBe(defaultBackdrop.light); - expect(typeof light.backdrop).toBe('string'); }); it('keeps the adapted accent hue without a format-parse round trip', () => { @@ -309,18 +308,11 @@ describe('defineTheme emits the full contract for the bundled themes', () => { const css = defineTheme(input); const emitted = emittedVarNames(css); - it(`${name} emits exactly the contract variables, including overlay backdrop and disabled text`, () => { + it(`${name} emits exactly the contract variables`, () => { // Derived from the contract, not hardcoded: `contract.test.ts` already asserts the typed // `vars` tree has exactly as many leaves as `flattenThemeContract()`, so this only needs to - // check that a bundled theme's emitted CSS matches that same list, not restate its length. - expect(emitted.size).toBe(contractNames.length); + // check that a bundled theme's emitted CSS matches that same list. expect([...emitted].sort()).toEqual([...contractNames].sort()); - expect(emitted.has('--luke-color-overlay-backdrop')).toBe(true); - expect(emitted.has('--luke-color-overlay-hover')).toBe(false); - expect(emitted.has('--luke-color-overlay-pressed')).toBe(false); - expect(emitted.has('--luke-color-overlay-tint')).toBe(false); - expect(emitted.has('--luke-color-scrim')).toBe(false); - expect(emitted.has('--luke-color-text-disabled')).toBe(true); }); it(`${name} paints info, success, and warning with a real interactive ramp`, () => { diff --git a/packages/@luke-ui/react/src/theme/token-board.test.ts b/packages/@luke-ui/react/src/theme/token-board.test.ts index e611a51b..b12f0dd3 100644 --- a/packages/@luke-ui/react/src/theme/token-board.test.ts +++ b/packages/@luke-ui/react/src/theme/token-board.test.ts @@ -9,80 +9,27 @@ function collectLeaves(node: TokenTreeNode): Array<{ path: string; varName: stri } describe('buildTokenTree', () => { - const contractPairs = flattenThemeContract(); - - it('produces exactly one leaf per contract path, derived from the contract', () => { - const leaves = collectLeaves(buildTokenTree()); - expect(leaves).toHaveLength(contractPairs.length); - }); - - it('carries every contract path and var name through unchanged', () => { - const byPath = (a: [string, string], b: [string, string]) => a[0].localeCompare(b[0]); - const leaves = collectLeaves(buildTokenTree()); - const leavesByPath = new Map(leaves.map((leaf) => [leaf.path, leaf.varName])); - expect([...leavesByPath.entries()].sort(byPath)).toEqual([...contractPairs].sort(byPath)); - }); - - it('nests overlay colour leaves under the overlay group, with backdrop as the only leaf', () => { - const tree = buildTokenTree(); - const color = tree.children.color; - if (color?.kind !== 'group') throw new Error('expected a color group'); - expect(color.children.overlay).toEqual({ - kind: 'group', - children: { - backdrop: { - kind: 'leaf', - path: 'color.overlay.backdrop', - varName: '--luke-color-overlay-backdrop', - }, - }, - }); - }); - - it('nests the deepest semantic-role leaf under its full chain of contract path segments', () => { - // `color.background..subtle.rest` is the contract's deepest leaf: four group levels, which is - // exactly what `HEADING_TAGS` in token-board.tsx caps at. The board needs no role list of its own — - // walking the contract is what makes the six roles appear. + it('nests each contract path as groups ending in the matching leaf', () => { + const contractPairs = flattenThemeContract(); const tree = buildTokenTree(); - const color = tree.children.color; - if (color?.kind !== 'group') throw new Error('expected a color group'); - const background = color.children.background; - if (background?.kind !== 'group') throw new Error('expected a background group'); - const danger = background.children.danger; - if (danger?.kind !== 'group') throw new Error('expected a danger group'); - const subtle = danger.children.subtle; - if (subtle?.kind !== 'group') throw new Error('expected a subtle group'); - - expect(subtle.children.rest).toEqual({ - kind: 'leaf', - path: 'color.background.danger.subtle.rest', - varName: '--luke-color-background-danger-subtle-rest', - }); - }); - it('groups every non-colour family at the top level too', () => { - const tree = buildTokenTree(); - const nonColorFamilies = new Set( - contractPairs - .map(([path]) => path.split('.')[0]) - .filter((family): family is string => family !== undefined && family !== 'color'), - ); - for (const family of nonColorFamilies) { - expect(Object.keys(tree.children)).toContain(family); + for (const [path, varName] of contractPairs) { + const segments = path.split('.'); + let node: TokenTreeNode = tree; + for (const segment of segments.slice(0, -1)) { + if (node.kind !== 'group') throw new Error(`expected a group on the way to ${path}`); + const next: TokenTreeNode | undefined = node.children[segment]; + if (next == null) throw new Error(`missing ${segment} for ${path}`); + node = next; + } + if (node.kind !== 'group') throw new Error(`expected a group before ${path}`); + expect(node.children[segments.at(-1) ?? '']).toEqual({ + kind: 'leaf', + path, + varName, + }); } - }); - - it('nests a motion leaf under its duration or easing group', () => { - const tree = buildTokenTree(); - const motion = tree.children.motion; - if (motion?.kind !== 'group') throw new Error('expected a motion group'); - const duration = motion.children.duration; - if (duration?.kind !== 'group') throw new Error('expected a duration group'); - expect(duration.children.feedback).toEqual({ - kind: 'leaf', - path: 'motion.duration.feedback', - varName: '--luke-motion-duration-feedback', - }); + expect(collectLeaves(tree)).toHaveLength(contractPairs.length); }); }); diff --git a/packages/turbo-generators/src/component-creation-plan.test.ts b/packages/turbo-generators/src/component-creation-plan.test.ts index 56ad2534..9a21ba93 100644 --- a/packages/turbo-generators/src/component-creation-plan.test.ts +++ b/packages/turbo-generators/src/component-creation-plan.test.ts @@ -107,7 +107,7 @@ describe('createComponentPlan', () => { ); }); - it('generates a browser test file that parses as valid TSX', () => { + it('generates a valid browser test for the default DOM contract', () => { const plan = createComponentPlan(validAnswers); const testFile = plan.files.find((file) => file.path.endsWith('.browser.test.tsx')); @@ -115,6 +115,10 @@ describe('createComponentPlan', () => { const parsed = parseSync(testFile.path, testFile.contents, { lang: 'tsx' }); expect(parsed.errors).toEqual([]); + expect(testFile.contents).toContain('testConformance'); + expect(testFile.contents).toContain('getTarget'); + expect(testFile.contents).not.toContain('getControl'); + expect(testFile.contents).not.toContain('testUniversalConformance'); }); it('generates a valid browser test for an empty conformance list', () => { @@ -141,16 +145,4 @@ describe('createComponentPlan', () => { expect(testFile.contents).toContain('getControl'); expect(testFile.contents).toContain('getTarget'); }); - - it('generates a conformance helper call from the default DOM contract', () => { - const plan = createComponentPlan(validAnswers); - - const testFile = plan.files.find((file) => file.path.endsWith('.browser.test.tsx')); - if (testFile === undefined) throw new Error('Expected the scaffold to write a browser test.'); - - expect(testFile.contents).toContain('testConformance'); - expect(testFile.contents).toContain('getTarget'); - expect(testFile.contents).not.toContain('getControl'); - expect(testFile.contents).not.toContain('testUniversalConformance'); - }); });