Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1165,9 +1165,16 @@ pages before a second post), load each in headless Chrome, run
[axe-core](https://github.com/dequelabs/axe-core) over it, and print one row
per success criterion: how many pages fail it, how many need a look, and the
rule with the most elements in violation. `report` turns that into the tool's
own evaluation file, which "Open evaluation" loads with the scope, the sample
and one assertion per page and criterion filled in, so the evaluator starts
at the judgement calls rather than at an empty form.
own evaluation file, which "Open report" on the Overview page loads with the
scope, the sample and one assertion per page and criterion filled in, so the
evaluator starts at the judgement calls rather than at an empty form.

In "4. Evaluate sample set", select the pages under "Add results for samples"
(or "Select all"), then expand "Show samples to enter individual results"
beneath a criterion to see its imported findings. The "Entire sample set"
outcomes remain "Not checked" for the evaluator to complete, so the tool's
overall progress starts at 0 even when page findings are present. Save with
"View report" > "Download report (JSON)".

**Nothing is ever marked passed.** axe can prove a failure — an image with no
alternative fails 1.1.1 wherever it is — but "no rule fired" proves nothing
Expand Down
2 changes: 1 addition & 1 deletion bin/wcag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ async function runReport(argv: string[]): Promise<number> {

const assertions = (evaluation.auditSample as unknown[]).length;
const sampled = ((evaluation.selectSample as { structuredSample: unknown[] }).structuredSample).length;
out(`${outFile}: ${sampled} pages in the sample, ${assertions} assertions. Open it at ${REPORT_TOOL_URL} with "Open evaluation".`);
out(`${outFile}: ${sampled} pages in the sample, ${assertions} assertions. Open it at ${REPORT_TOOL_URL} with "Open report" on the Overview page. Run \`wcag open\` for the full steps.`);
return 0;
}

Expand Down
17 changes: 12 additions & 5 deletions src/wcag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
* `reportFindings`, a `Webpage` subject per sampled page whose id is its
* URL, and an `Assertion` per page and criterion with `test` set to the
* tool's own criterion ids (`WCAG22:non-text-content`). A file of that
* shape goes through the tool's "Open evaluation" rather than the beta
* shape goes through the tool's "Open report" rather than the beta
* assertion import, which is the path that restores the sample as well.
*/

Expand Down Expand Up @@ -1363,7 +1363,7 @@ const describe = (outcome: CriterionOutcome, page: PageResult, report: Report):

/**
* The report tool's own evaluation file, with the sample and the automated
* results filled in. Open it in the tool with "Open evaluation".
* results filled in. Open it in the tool with "Open report".
*/
export function toEvaluation(report: Report, options: EvaluationOptions = {}): Record<string, unknown> {
const { wcagVersion: version } = report;
Expand Down Expand Up @@ -1456,7 +1456,9 @@ export function toEvaluation(report: Report, options: EvaluationOptions = {}): R
reportFindings: {
documentSteps: [{ '@id': '_:about' }, { '@id': '_:defineScope' }, { '@id': '_:exploreTarget' }, { '@id': '_:selectSample' }],
commissioner: options.commissioner ?? '',
date,
// The tool reads reportFindings.date['@value']; an untyped string is lost.
// Use a calendar date for the report and keep precise assertion timestamps.
date: { type: 'http://www.w3.org/TR/NOTE-datetime', '@value': date.slice(0, 10) },
evaluator: options.evaluator ?? '',
evaluationSpecifics: '',
summary,
Expand All @@ -1483,11 +1485,16 @@ export const OPEN_STEPS = `The WCAG-EM Report Tool is a web page with no command
1. wcag audit https://example.org --pages 8 writes wcag-report.json
2. wcag report wcag-report.json writes evaluation.json
3. open ${REPORT_TOOL_URL}
4. "Open evaluation" in the menu, choose evaluation.json
4. "Open report" on the Overview page, choose evaluation.json
5. In "4. Evaluate sample set", select the pages under "Add results for samples"
(or "Select all"), then expand "Show samples to enter individual results"
beneath a criterion to see its imported findings.

Steps 1 (scope) and 3 (sample) are then filled in, and step 4 (audit) holds
one assertion per page and criterion: "failed" where axe proved a failure,
"cannot tell" where it found something to look at or only checked a part.
Nothing is marked "passed" — that is the evaluator's call, made in the tool.
The "Entire sample set" outcomes stay "Not checked" for the evaluator to finish,
so the report's overall progress remains 0 until those outcomes are recorded.
The tool keeps the evaluation in the browser and saves it back out as JSON
from step 5.`;
with "View report" > "Download report (JSON)".`;
9 changes: 9 additions & 0 deletions test/wcag.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,15 @@ describe('toEvaluation', () => {
expect(evaluation.reportFindings.evaluator).toBe('Anthony');
});

it('preserves the evaluation date in the typed value the report tool imports', () => {
// W3C's importer reads reportFindings.date['@value']; a plain string
// silently becomes an empty date. Use YYYY-MM-DD for the report date.
expect(evaluation.reportFindings.date).toEqual({
type: 'http://www.w3.org/TR/NOTE-datetime',
'@value': '2026-09-13',
});
});

// The tool derives a sampled page's id from the URL in its description and
// finds it again by title, so both have to be exactly this.
it('puts every loaded page in the structured sample with its URL as id and description', () => {
Expand Down
Loading