From 4f6ae23d5ca97023aae82a5d42d69d65fdc8a4b2 Mon Sep 17 00:00:00 2001 From: Liliia Pelypenko Date: Tue, 7 Sep 2021 10:43:36 +0900 Subject: [PATCH] Added return of HTML file content and option to stop html file creation --- README.md | 24 + src/index.ts | 25 +- test/__snapshots__/index.test.ts.snap | 1710 +++++++++++++++++++++++++ test/index.test.ts | 23 +- 4 files changed, 1773 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 4e2f131..78fa639 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,30 @@ Notes: Please check [sample report output.](https://lpelypenko.github.io/axe-html-reporter/) +`createHtmlReport` returns HTML content that can be additionally used for specific integrations. + +If only HTML content needed, user can pass `doNotCreateReportFile: true` to stop report file creation. + +Suggestion on how to use this library if you don't need a report file but need only HTML it produces: + +```javascript +const reportHTML = createHtmlReport({ + results: rawAxeResults, + options: { + projectKey: 'I need only raw HTML', + doNotCreateReportFile: true, + }, +}); +console.log('reportHTML will have full content of HTML file.'); +// suggestion on how to create file by yourself +if (!fs.existsSync('build/reports/saveReportHere.html')) { + fs.mkdirSync('build/reports', { + recursive: true, + }); +} +fs.writeFileSync('build/reports/saveReportHere.html', reportHTML); +``` + ## Install ``` diff --git a/src/index.ts b/src/index.ts index 6b4f26b..7163389 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,8 @@ export interface Options { outputDir?: string; projectKey?: string; customSummary?: string; - outputDirPath?: string + outputDirPath?: string; + doNotCreateReportFile?: boolean; } export interface CreateReport { @@ -25,7 +26,7 @@ export interface PreparedResults { inapplicable?: Result[]; } -export function createHtmlReport({ results, options }: CreateReport): void { +export function createHtmlReport({ results, options }: CreateReport): string { if (!results.violations) { throw new Error( "'violations' is required for HTML accessibility report. Example: createHtmlReport({ results : { violations: Result[] } })" @@ -58,13 +59,21 @@ export function createHtmlReport({ results, options }: CreateReport): void { hasAxeRawResults: Boolean(results?.timestamp), rules: prepareAxeRules(results?.toolOptions?.rules || {}), }); - saveHtmlReport({ - htmlContent, - reportFileName: options?.reportFileName, - outputDir: options?.outputDir, - outputDirPath: options?.outputDirPath - }); + if (options?.doNotCreateReportFile === true) { + console.info('Report file will not be created because user passed options.doNotCreateReportFile = true. Use HTML output of the function to create report file'); + } else { + saveHtmlReport({ + htmlContent, + reportFileName: options?.reportFileName, + outputDir: options?.outputDir, + outputDirPath: options?.outputDirPath + }); + } + + return htmlContent; } catch (e) { console.warn(`HTML report was not created due to the error ${e.message}`); + + return `Failed to create HTML report due to an error ${e.message}`; } } diff --git a/test/__snapshots__/index.test.ts.snap b/test/__snapshots__/index.test.ts.snap index f497dee..5326e0a 100644 --- a/test/__snapshots__/index.test.ts.snap +++ b/test/__snapshots__/index.test.ts.snap @@ -6286,6 +6286,1716 @@ exports[`Successful tests Empty violations 1`] = ` " `; +exports[`Successful tests File will not be created and raw HTML result will be returned 1`] = ` +" + + + + + + + + + + + + + + + AXE Accessibility Results + + +
+

+ AXE Accessibility Results for I need only raw HTML project +

+
+
+ Page URL: + http://example.com/ +
+
+
Test Case: Full page analysis +
Steps:
+
    +
  1. Open https://dequeuniversity.com/demo/mars/
  2. +
  3. Analyze full page with all rules enabled
  4. +
+
+
axe-core found 6 violations
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#DescriptionAxe rule IDWCAGImpactCount
1<html> element must have a lang attributehtml-has-langWCAG 2 Level A, WCAG 3.1.1serious1
2Document must have one main landmarklandmark-one-mainBest practicemoderate1
3All page content must be contained by landmarksregionBest practicemoderate1
4Elements should not have tabindex greater than zerotabindexBest practiceserious3
+

Failed

+
+
+
+
+ 1. <html> element must have a lang attribute +
+ Learn more +
+
+
html-has-lang
+
+ WCAG 2 Level A, WCAG 3.1.1 +
+
+
+

Ensures every HTML document has a lang attribute

+
+ serious +
+
+
+
+ Issue Tags: + cat.language + + wcag2a + + wcag311 +
+
+
+ + + + + + + + + + + + + + + +
#Issue Description + To solve this violation, you need to... +
1 +

Element location

+
html
+

Element source

+
<html>
+
+
+

Fix any of the following:

+
    +
  • The <html> element does not have a lang attribute
  • +
+
+
+
+
+
+
+
+
+
+ 2. Document must have one main landmark +
+ Learn more +
+
+
landmark-one-main
+
+ Best practice +
+
+
+

Ensures the document has a main landmark

+
+ moderate +
+
+
+
+ Issue Tags: + cat.semantics + + best-practice +
+
+
+ + + + + + + + + + + + + + + +
#Issue Description + To solve this violation, you need to... +
1 +

Element location

+
html
+

Element source

+
<html>
+
+
+

Fix all of the following:

+
    +
  • Document does not have a main landmark
  • +
+
+
+
+
+
+
+
+
+
+ 3. All page content must be contained by landmarks +
+ Learn more +
+
+
region
+
+ Best practice +
+
+
+

Ensures all page content is contained by landmarks

+
+ moderate +
+
+
+
+ Issue Tags: + cat.keyboard + + best-practice +
+
+
+ + + + + + + + + + + + + + + +
#Issue Description + To solve this violation, you need to... +
1 +

Element location

+
div
+

Element source

+
<div>
+    <h1>Example Domain</h1>
+    <p>This domain is for use in illustrative examples in documents. You may use this
+    domain in literature without prior coordination or asking for permission.</p>
+    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
+</div>
+
+
+

Fix any of the following:

+
    +
  • Some page content is not contained by landmarks
  • +
+
+
+
+
+
+
+
+
+
+ 4. Elements should not have tabindex greater than zero +
+ Learn more +
+
+
tabindex
+
+ Best practice +
+
+
+

Ensures tabindex attribute values are not greater than 0

+
+ serious +
+
+
+
+ Issue Tags: + cat.keyboard + + best-practice +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
#Issue Description + To solve this violation, you need to... +
1 +

Element location

+
#from0
+

Element source

+
<input type="text" value="" class="city-input ac_input ui-autocomplete-input" autocomplete="off" id="from0" name="from0" tabindex="1" role="textbox" aria-autocomplete="list" aria-haspopup="true">
+
+
+

Fix any of the following:

+
    +
  • Element has a tabindex greater than 0
  • +
+
+
2 +

Element location

+
#to0
+

Element source

+
<input type="text" value="" class="city-input ac_input ui-autocomplete-input" autocomplete="off" id="to0" name="to0" tabindex="1" role="textbox" aria-autocomplete="list" aria-haspopup="true">
+
+
+

Fix any of the following:

+
    +
  • Element has a tabindex greater than 0
  • +
+
+
3 +

Element location

+
#deptDate0
+

Element source

+
<input size="10" id="deptDate0" name="deptDate0" placeholder="mm/dd/yyyy" value="" tabindex="3" class="hasDatepicker input-dept">
+
+
+

Fix any of the following:

+
    +
  • Element has a tabindex greater than 0
  • +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#DescriptionAxe rule IDWCAGNodes passed check
1aria-hidden='true' must not be present on the document bodyaria-hidden-bodyWCAG 2 Level A, WCAG 4.1.21
2Page must have means to bypass repeated blocksbypassWCAG 2 Level A, WCAG 2.4.11
3Elements must have sufficient color contrastcolor-contrastWCAG 2 Level AA, WCAG 1.4.33
4Documents must have <title> element to aid in navigationdocument-titleWCAG 2 Level A, WCAG 2.4.21
5Headings must not be emptyempty-headingBest practice1
6Heading levels should only increase by oneheading-orderBest practice1
7Hidden content on the page cannot be analyzedhidden-contentBest practice14
8Links must have discernible textlink-nameWCAG 2 Level A, WCAG 4.1.2, WCAG 2.4.41
9Users should be able to zoom and scale the text up to 500%meta-viewport-largeBest practice1
10Zooming and scaling must not be disabledmeta-viewportBest practice1
11Page must contain a level-one headingpage-has-heading-oneBest practice1
12All page content must be contained by landmarksregionBest practice4
+
+
+
+
+
+
+
+
+ +
+
+
+
+

What 'incomplete' axe checks means?

+

+ Incomplete results were aborted and require further testing. This + can happen either because of technical restrictions to what the rule + can test, or because a javascript error occurred. +

+

+ Visit axe API Documentation + to learn more. +

+
+
+
+
+
+
+
+
+ +
+
+
+
+

What 'inapplicable' axe checks means?

+

+ The inapplicable array lists all the rules for which no matching + elements were found on the page. +

+

+ Visit axe API Documentation + to learn more. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#DescriptionAxe rule IDWCAG
1accesskey attribute value must be uniqueaccesskeysBest practice
2Active <area> elements must have alternate textarea-altWCAG 2 Level A, WCAG 1.1.1, WCAG 2.4.4, WCAG 4.1.2
3Elements must only use allowed ARIA attributesaria-allowed-attrWCAG 2 Level A, WCAG 4.1.2
4ARIA role must be appropriate for the elementaria-allowed-roleBest practice
5ARIA hidden element must not contain focusable elementsaria-hidden-focusWCAG 2 Level A, WCAG 4.1.2, WCAG 1.3.1
6ARIA input fields must have an accessible namearia-input-field-nameWCAG 2 Level A, WCAG 4.1.2
7Required ARIA attributes must be providedaria-required-attrWCAG 2 Level A, WCAG 4.1.2
8Certain ARIA roles must contain particular childrenaria-required-childrenWCAG 2 Level A, WCAG 1.3.1
9Certain ARIA roles must be contained by particular parentsaria-required-parentWCAG 2 Level A, WCAG 1.3.1
10Use aria-roledescription on elements with a semantic rolearia-roledescriptionWCAG 2 Level A, WCAG 4.1.2
11ARIA roles used must conform to valid valuesaria-rolesWCAG 2 Level A, WCAG 4.1.2
12ARIA toggle fields have an accessible namearia-toggle-field-nameWCAG 2 Level A, WCAG 4.1.2
13ARIA attributes must conform to valid valuesaria-valid-attr-valueWCAG 2 Level A, WCAG 4.1.2
14ARIA attributes must conform to valid namesaria-valid-attrWCAG 2 Level A, WCAG 4.1.2
15<audio> elements must have a captions trackaudio-captionWCAG 2 Level A, WCAG 1.2.1
16autocomplete attribute must be used correctlyautocomplete-validWCAG 2.1 Level AA, WCAG 1.3.5
17Inline text spacing must be adjustable with custom stylesheetsavoid-inline-spacingWCAG 2.1 Level AA, WCAG 1.4.1.2
18<blink> elements are deprecated and must not be usedblinkWCAG 2 Level A, WCAG 2.2.2
19Buttons must have discernible textbutton-nameWCAG 2 Level A, WCAG 4.1.2
20<dl> elements must only directly contain properly-ordered <dt> and <dd> groups, <script>, <template> or <div> elementsdefinition-listWCAG 2 Level A, WCAG 1.3.1
21<dt> and <dd> elements must be contained by a <dl>dlitemWCAG 2 Level A, WCAG 1.3.1
22IDs of active elements must be uniqueduplicate-id-activeWCAG 2 Level A, WCAG 4.1.1
23IDs used in ARIA and labels must be uniqueduplicate-id-ariaWCAG 2 Level A, WCAG 4.1.1
24id attribute value must be uniqueduplicate-idWCAG 2 Level A, WCAG 4.1.1
25Elements in the focus order need a role appropriate for interactive contentfocus-order-semanticsBest practice
26Form field should not have multiple label elementsform-field-multiple-labelsWCAG 2 Level A, WCAG 3.3.2
27Frames must be tested with axe-coreframe-testedBest practice
28Frames must have a unique title attributeframe-title-uniqueBest practice
29Frames must have title attributeframe-titleWCAG 2 Level A, WCAG 2.4.1, WCAG 4.1.2
30<html> element must have a valid value for the lang attributehtml-lang-validWCAG 2 Level A, WCAG 3.1.1
31HTML elements with lang and xml:lang must have the same base languagehtml-xml-lang-mismatchWCAG 2 Level A, WCAG 3.1.1
32Images must have alternate textimage-altWCAG 2 Level A, WCAG 1.1.1
33Alternative text of images should not be repeated as textimage-redundant-altBest practice
34Input buttons must have discernible textinput-button-nameWCAG 2 Level A, WCAG 4.1.2
35Image buttons must have alternate textinput-image-altWCAG 2 Level A, WCAG 1.1.1
36Elements must have their visible text as part of their accessible namelabel-content-name-mismatchWCAG 2.1 Level A, WCAG 2.5.3
37Form elements should have a visible labellabel-title-onlyBest practice
38Form elements must have labelslabelWCAG 2 Level A, WCAG 4.1.2, WCAG 1.3.1
39Banner landmark must not be contained in another landmarklandmark-banner-is-top-levelBest practice
40Aside must not be contained in another landmarklandmark-complementary-is-top-levelBest practice
41Contentinfo landmark must not be contained in another landmarklandmark-contentinfo-is-top-levelBest practice
42Main landmark must not be contained in another landmarklandmark-main-is-top-levelBest practice
43Document must not have more than one banner landmarklandmark-no-duplicate-bannerBest practice
44Document must not have more than one contentinfo landmarklandmark-no-duplicate-contentinfoBest practice
45Document must not have more than one main landmarklandmark-no-duplicate-mainBest practice
46Ensures landmarks are uniquelandmark-uniqueBest practice
47Links must be distinguished from surrounding text in a way that does not rely on colorlink-in-text-blockWCAG 2 Level A, WCAG 1.4.1
48<ul> and <ol> must only directly contain <li>, <script> or <template> elementslistWCAG 2 Level A, WCAG 1.3.1
49<li> elements must be contained in a <ul> or <ol>listitemWCAG 2 Level A, WCAG 1.3.1
50<marquee> elements are deprecated and must not be usedmarqueeWCAG 2 Level A, WCAG 2.2.2
51Timed refresh must not existmeta-refreshWCAG 2 Level A, WCAG 2 Level AAA, WCAG 2.2.1, WCAG 2.2.4, WCAG 3.2.5
52<object> elements must have alternate textobject-altWCAG 2 Level A, WCAG 1.1.1
53Bold, italic text and font-size are not used to style p elements as a headingp-as-headingWCAG 2 Level A, WCAG 1.3.1
54[role='img'] elements have an alternative textrole-img-altWCAG 2 Level A, WCAG 1.1.1
55scope attribute should be used correctlyscope-attr-validBest practice
56Ensure that scrollable region has keyboard accessscrollable-region-focusableWCAG 2 Level A, WCAG 2.1.1
57Server-side image maps must not be usedserver-side-image-mapWCAG 2 Level A, WCAG 2.1.1
58The skip-link target should exist and be focusableskip-linkBest practice
59svg elements with an img role have an alternative textsvg-img-altWCAG 2 Level A, WCAG 1.1.1
60Elements should not have tabindex greater than zerotabindexBest practice
61The <caption> element should not contain the same text as the summary attributetable-duplicate-nameBest practice
62Data or header cells should not be used to give caption to a data table.table-fake-captionWCAG 2 Level A, WCAG 1.3.1
63All non-empty td element in table larger than 3 by 3 must have an associated table headertd-has-headerWCAG 2 Level A, WCAG 1.3.1
64All cells in a table element that use the headers attribute must only refer to other cells of that same tabletd-headers-attrWCAG 2 Level A, WCAG 1.3.1
65All th elements and elements with role=columnheader/rowheader must have data cells they describeth-has-data-cellsWCAG 2 Level A, WCAG 1.3.1
66lang attribute must have a valid valuevalid-langWCAG 2 Level AA, WCAG 3.1.2
67<video> elements must have captionsvideo-captionWCAG 2 Level A, WCAG 1.2.2
68<video> or <audio> elements do not autoplay audiono-autoplay-audioWCAG 2 Level A, WCAG 1.4.2
+
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#Rule IDEnabled
1object-alttrue
2role-img-alttrue
3input-image-alttrue
4image-alttrue
5svg-img-alttrue
6area-alttrue
7audio-captiontrue
8video-captiontrue
9definition-listtrue
10dlitemtrue
11listitemtrue
12listtrue
13th-has-data-cellstrue
14td-headers-attrtrue
15td-has-headertrue
16p-as-headingtrue
17aria-required-parenttrue
18aria-required-childrentrue
19table-fake-captiontrue
20css-orientation-lockfalse
21autocomplete-validtrue
22link-in-text-blocktrue
23no-autoplay-audiotrue
24color-contrasttrue
25meta-viewporttrue
26avoid-inline-spacingtrue
27server-side-image-maptrue
28meta-refreshtrue
29blinktrue
30marqueetrue
31bypasstrue
32frame-titletrue
33document-titletrue
34scrollable-region-focusabletrue
35identical-links-same-purposefalse
36label-content-name-mismatchtrue
37html-has-langtrue
38html-lang-validtrue
39html-xml-lang-mismatchtrue
40valid-langtrue
41form-field-multiple-labelstrue
42duplicate-id-activetrue
43duplicate-idtrue
44duplicate-id-ariatrue
45aria-valid-attrtrue
46aria-valid-attr-valuetrue
47aria-input-field-nametrue
48aria-rolestrue
49aria-toggle-field-nametrue
50aria-hidden-focustrue
51aria-hidden-bodytrue
52button-nametrue
53aria-allowed-attrtrue
54input-button-nametrue
55aria-required-attrtrue
56aria-roledescriptiontrue
57link-nametrue
58labeltrue
59accesskeystrue
60regiontrue
61aria-allowed-roletrue
62landmark-banner-is-top-leveltrue
63landmark-complementary-is-top-leveltrue
64landmark-contentinfo-is-top-leveltrue
65focus-order-semanticstrue
66tabindextrue
67landmark-no-duplicate-maintrue
68label-title-onlytrue
69frame-testedtrue
70frame-title-uniquetrue
71heading-ordertrue
72empty-headingtrue
73hidden-contenttrue
74landmark-uniquetrue
75landmark-main-is-top-leveltrue
76page-has-heading-onetrue
77landmark-one-maintrue
78landmark-no-duplicate-bannertrue
79landmark-no-duplicate-contentinfotrue
80scope-attr-validtrue
81image-redundant-alttrue
82table-duplicate-nametrue
83skip-linktrue
84meta-viewport-largetrue
+
+
+
+
+
+ + + + +" +`; + exports[`Successful tests Inapplicable present 1`] = ` " diff --git a/test/index.test.ts b/test/index.test.ts index d743a06..8c9589f 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -40,7 +40,7 @@ describe('Successful tests', () => { violations: [], }, options: { - reportFileName + reportFileName, }, }); expect( @@ -240,4 +240,25 @@ describe('Successful tests', () => { }) ).toMatchSnapshot(); }); + it('File will not be created and raw HTML result will be returned', async () => { + const customSummary = `Test Case: Full page analysis +
Steps:
+
    +
  1. Open https://dequeuniversity.com/demo/mars/
  2. +
  3. Analyze full page with all rules enabled
  4. +
`; + + const reportHTML = createHtmlReport({ + results: rawAxeResults, + options: { + projectKey: 'I need only raw HTML', + customSummary, + doNotCreateReportFile: true, + reportFileName: 'shouldNotBeSaved.html', + }, + }); + expect(reportHTML).toMatchSnapshot(); + const isReportFileExist = fs.existsSync(getPathToCreatedReport('shouldNotBeSaved.html')); + expect(isReportFileExist).toBe(false); + }); });