From 1c9a55936201db54aab405e86603a86840d4b69d Mon Sep 17 00:00:00 2001 From: "Ashley Engelund (weedySeaDragon @ github)" Date: Wed, 7 Dec 2022 10:19:30 -0800 Subject: [PATCH] common function for a11y; add to renderAsync; + renderAsync spec --- docs/config/setup/modules/mermaidAPI.md | 2 +- packages/mermaid/src/mermaidAPI.spec.ts | 52 +++++++++++++++++++++++++ packages/mermaid/src/mermaidAPI.ts | 23 ++++++++++- 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/docs/config/setup/modules/mermaidAPI.md b/docs/config/setup/modules/mermaidAPI.md index 7902c1be9..1b840dcd3 100644 --- a/docs/config/setup/modules/mermaidAPI.md +++ b/docs/config/setup/modules/mermaidAPI.md @@ -90,7 +90,7 @@ mermaid.initialize(config); #### Defined in -[mermaidAPI.ts:949](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L949) +[mermaidAPI.ts:968](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/mermaidAPI.ts#L968) ## Functions diff --git a/packages/mermaid/src/mermaidAPI.spec.ts b/packages/mermaid/src/mermaidAPI.spec.ts index dd36b1d0c..f9bad66d7 100644 --- a/packages/mermaid/src/mermaidAPI.spec.ts +++ b/packages/mermaid/src/mermaidAPI.spec.ts @@ -734,4 +734,56 @@ describe('mermaidAPI', function () { }); }); }); + + describe('renderAsync', () => { + // Be sure to add async before each test (anonymous) method + + // These are more like integration tests right now because nothing is mocked. + // But it is faster that a cypress test and there's no real reason to actually evaluate an image pixel by pixel. + + // render(id, text, cb?, svgContainingElement?) + + // Test all diagram types. Note that old flowchart 'graph' type will invoke the flowRenderer-v2. (See the flowchart v2 detector.) + // We have to have both the specific textDiagramType and the expected type name because the expected type may be slightly different than was is put in the diagram text (ex: in -v2 diagrams) + const diagramTypesAndExpectations = [ + { textDiagramType: 'C4Context', expectedType: 'c4' }, + { textDiagramType: 'classDiagram', expectedType: 'classDiagram' }, + { textDiagramType: 'classDiagram-v2', expectedType: 'classDiagram' }, + { textDiagramType: 'erDiagram', expectedType: 'er' }, + { textDiagramType: 'graph', expectedType: 'flowchart-v2' }, + { textDiagramType: 'flowchart', expectedType: 'flowchart-v2' }, + { textDiagramType: 'gitGraph', expectedType: 'gitGraph' }, + { textDiagramType: 'gantt', expectedType: 'gantt' }, + { textDiagramType: 'journey', expectedType: 'journey' }, + { textDiagramType: 'pie', expectedType: 'pie' }, + { textDiagramType: 'requirementDiagram', expectedType: 'requirement' }, + { textDiagramType: 'sequenceDiagram', expectedType: 'sequence' }, + { textDiagramType: 'stateDiagram-v2', expectedType: 'stateDiagram' }, + ]; + + describe('accessibility', () => { + const id = 'mermaid-fauxId'; + const a11yTitle = 'a11y title'; + const a11yDescr = 'a11y description'; + + diagramTypesAndExpectations.forEach((testedDiagram) => { + describe(`${testedDiagram.textDiagramType}`, () => { + const diagramType = testedDiagram.textDiagramType; + const diagramText = `${diagramType}\n accTitle: ${a11yTitle}\n accDescr: ${a11yDescr}\n`; + const expectedDiagramType = testedDiagram.expectedType; + + it('aria-roledscription is set to the diagram type, addSVGa11yTitleDescription is called', async () => { + const a11yDiagramInfo_spy = vi.spyOn(accessibility, 'setA11yDiagramInfo'); + const a11yTitleDesc_spy = vi.spyOn(accessibility, 'addSVGa11yTitleDescription'); + await mermaidAPI.renderAsync(id, diagramText); + expect(a11yDiagramInfo_spy).toHaveBeenCalledWith( + expect.anything(), + expectedDiagramType + ); + expect(a11yTitleDesc_spy).toHaveBeenCalled(); + }); + }); + }); + }); + }); }); diff --git a/packages/mermaid/src/mermaidAPI.ts b/packages/mermaid/src/mermaidAPI.ts index 1ac03c4f6..a77aed96d 100644 --- a/packages/mermaid/src/mermaidAPI.ts +++ b/packages/mermaid/src/mermaidAPI.ts @@ -519,10 +519,9 @@ const render = function ( // This is the d3 node for the svg element const svgNode = root.select(`${enclosingDivID_selector} svg`); - setA11yDiagramInfo(svgNode, graphType); const a11yTitle = diag.db.getAccTitle?.(); const a11yDescr = diag.db.getAccDescription?.(); - addSVGa11yTitleDescription(svgNode, a11yTitle, a11yDescr, svgNode.attr('id')); + addA11yInfo(graphType, svgNode, a11yTitle, a11yDescr); // ------------------------------------------------------------------------------- // Clean up SVG code @@ -720,6 +719,12 @@ const renderAsync = async function ( throw e; } + // This is the d3 node for the svg element + const svgNode = root.select(`${enclosingDivID_selector} svg`); + const a11yTitle = diag.db.getAccTitle?.(); + const a11yDescr = diag.db.getAccDescription?.(); + addA11yInfo(graphType, svgNode, a11yTitle, a11yDescr); + // ------------------------------------------------------------------------------- // Clean up SVG code root.select(`[id="${id}"]`).selectAll('foreignobject > *').attr('xmlns', XMLNS_XHTML_STD); @@ -884,6 +889,20 @@ function initialize(options: MermaidConfig = {}) { addDiagrams(); } +/** + * Add accessibility (a11y) information to the diagram. + * + */ +function addA11yInfo( + graphType: string, + svgNode: D3Element, + a11yTitle: string | undefined, + a11yDescr: string | undefined +) { + setA11yDiagramInfo(svgNode, graphType); + addSVGa11yTitleDescription(svgNode, a11yTitle, a11yDescr, svgNode.attr('id')); +} + /** * ## mermaidAPI configuration defaults *