From 28840ebd8464896b21db359791fa19f8cf92a998 Mon Sep 17 00:00:00 2001 From: quilicicf Date: Sun, 22 Jun 2025 13:45:24 +0200 Subject: [PATCH] test(refactor): Provide SVG selection in `jsdomIt` function --- packages/mermaid/src/accessibility.spec.ts | 114 +++++++++------------ packages/mermaid/src/tests/util.ts | 11 +- 2 files changed, 59 insertions(+), 66 deletions(-) diff --git a/packages/mermaid/src/accessibility.spec.ts b/packages/mermaid/src/accessibility.spec.ts index 7dbdf6c7f..8e4a268df 100644 --- a/packages/mermaid/src/accessibility.spec.ts +++ b/packages/mermaid/src/accessibility.spec.ts @@ -1,27 +1,23 @@ import { addSVGa11yTitleDescription, setA11yDiagramInfo } from './accessibility.js'; import { ensureNodeFromSelector, jsdomIt } from './tests/util.js'; -import { select } from 'd3'; import { expect } from 'vitest'; describe('accessibility', () => { describe('setA11yDiagramInfo', () => { - jsdomIt('should set svg element role to "graphics-document document"', () => { - const svgSelection = select('svg'); - setA11yDiagramInfo(svgSelection, 'flowchart'); + jsdomIt('should set svg element role to "graphics-document document"', ({ svg }) => { + setA11yDiagramInfo(svg, 'flowchart'); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('role')).toBe('graphics-document document'); }); - jsdomIt('should set aria-roledescription to the diagram type', () => { - const svgSelection = select('svg'); - setA11yDiagramInfo(svgSelection, 'flowchart'); + jsdomIt('should set aria-roledescription to the diagram type', ({ svg }) => { + setA11yDiagramInfo(svg, 'flowchart'); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('aria-roledescription')).toBe('flowchart'); }); - jsdomIt('should not set aria-roledescription if the diagram type is empty', () => { - const svgSelection = select('svg'); - setA11yDiagramInfo(svgSelection, ''); + jsdomIt('should not set aria-roledescription if the diagram type is empty', ({ svg }) => { + setA11yDiagramInfo(svg, ''); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('aria-roledescription')).toBeNull(); }); @@ -46,25 +42,25 @@ describe('accessibility', () => { describe('with a11y description', () => { const a11yDesc = 'a11y description'; - jsdomIt('should set aria-labelledby to the title id inserted as a child', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should set aria-labelledby to the title id inserted as a child', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('aria-labelledby')).toBe(`chart-title-${givenId}`); }); - jsdomIt('should set aria-describedby to the description id inserted as a child', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); - const svgNode = ensureNodeFromSelector('svg'); - expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${givenId}`); - }); + jsdomIt( + 'should set aria-describedby to the description id inserted as a child', + ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); + const svgNode = ensureNodeFromSelector('svg'); + expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${givenId}`); + } + ); jsdomIt( 'should insert title tag as the first child with the text set to the accTitle given', - () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); const titleNode = ensureNodeFromSelector('title', svgNode); expect(titleNode?.innerHTML).toBe(a11yTitle); @@ -73,9 +69,8 @@ describe('accessibility', () => { jsdomIt( 'should insert desc tag as the 2nd child with the text set to accDescription given', - () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); const descNode = ensureNodeFromSelector('desc', svgNode); expect(descNode?.innerHTML).toBe(a11yDesc); @@ -86,34 +81,30 @@ describe('accessibility', () => { describe(`without a11y description`, {}, () => { const a11yDesc = undefined; - jsdomIt('should set aria-labelledby to the title id inserted as a child', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should set aria-labelledby to the title id inserted as a child', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('aria-labelledby')).toBe(`chart-title-${givenId}`); }); - jsdomIt('should not set aria-describedby', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should not set aria-describedby', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('aria-describedby')).toBeNull(); }); jsdomIt( 'should insert title tag as the first child with the text set to the accTitle given', - () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); const titleNode = ensureNodeFromSelector('title', svgNode); expect(titleNode?.innerHTML).toBe(a11yTitle); } ); - jsdomIt('should not insert description tag', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should not insert description tag', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); const descNode = svgNode.querySelector('desc'); expect(descNode).toBeNull(); @@ -127,33 +118,32 @@ describe('accessibility', () => { describe('with a11y description', () => { const a11yDesc = 'a11y description'; - jsdomIt('should not set aria-labelledby', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should not set aria-labelledby', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('aria-labelledby')).toBeNull(); }); - jsdomIt('should not insert title tag', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should not insert title tag', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); const titleNode = svgNode.querySelector('title'); expect(titleNode).toBeNull(); }); - jsdomIt('should set aria-describedby to the description id inserted as a child', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); - const svgNode = ensureNodeFromSelector('svg'); - expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${givenId}`); - }); + jsdomIt( + 'should set aria-describedby to the description id inserted as a child', + ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); + const svgNode = ensureNodeFromSelector('svg'); + expect(svgNode.getAttribute('aria-describedby')).toBe(`chart-desc-${givenId}`); + } + ); jsdomIt( 'should insert desc tag as the 2nd child with the text set to accDescription given', - () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); const descNode = ensureNodeFromSelector('desc', svgNode); expect(descNode?.innerHTML).toBe(a11yDesc); @@ -164,31 +154,27 @@ describe('accessibility', () => { describe('without a11y description', () => { const a11yDesc = undefined; - jsdomIt('should not set aria-labelledby', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should not set aria-labelledby', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('aria-labelledby')).toBeNull(); }); - jsdomIt('should not set aria-describedby', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should not set aria-describedby', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); expect(svgNode.getAttribute('aria-describedby')).toBeNull(); }); - jsdomIt('should not insert title tag', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should not insert title tag', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); const titleNode = svgNode.querySelector('title'); expect(titleNode).toBeNull(); }); - jsdomIt('should not insert description tag', () => { - const svgSelection = select('svg'); - addSVGa11yTitleDescription(svgSelection, a11yTitle, a11yDesc, givenId); + jsdomIt('should not insert description tag', ({ svg }) => { + addSVGa11yTitleDescription(svg, a11yTitle, a11yDesc, givenId); const svgNode = ensureNodeFromSelector('svg'); const descNode = svgNode.querySelector('desc'); expect(descNode).toBeNull(); diff --git a/packages/mermaid/src/tests/util.ts b/packages/mermaid/src/tests/util.ts index 8b3de4e9d..09f7da2d4 100644 --- a/packages/mermaid/src/tests/util.ts +++ b/packages/mermaid/src/tests/util.ts @@ -28,6 +28,7 @@ ${'2w'} | ${dayjs.duration(2, 'w')} import { JSDOM } from 'jsdom'; import { expect, it } from 'vitest'; +import { select, type Selection } from 'd3'; export const convert = (template: TemplateStringsArray, ...params: unknown[]) => { const header = template[0] @@ -61,6 +62,11 @@ export const MOCKED_BBOX = { height: 666, }; +interface JsdomItInput { + // eslint-disable-next-line + svg: Selection; // The `any` here comes from D3'as API. +} + /** * Test method borrowed from d3 : https://github.com/d3/d3-selection/blob/v3.0.0/test/jsdom.js * @@ -74,7 +80,7 @@ export const MOCKED_BBOX = { * * This makes it possible to make structural tests instead of mocking everything. */ -export function jsdomIt(message: string, run: () => void | Promise) { +export function jsdomIt(message: string, run: (input: JsdomItInput) => void | Promise) { return it(message, async (): Promise => { const oldWindow = global.window; const oldDocument = global.document; @@ -99,7 +105,8 @@ export function jsdomIt(message: string, run: () => void | Promise) { setOnProtectedConstant(global, 'document', dom.window.document); // Fool D3 into thinking it's in a browser setOnProtectedConstant(global, 'MutationObserver', undefined); // JSDOM doesn't like cytoscape elements - await run(); + const svgSelection = select('svg'); + await run({ svg: svgSelection }); } finally { setOnProtectedConstant(global, 'window', oldWindow); setOnProtectedConstant(global, 'document', oldDocument);