@kinora/reporter 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/a11y.d.mts +15 -0
- package/dist/a11y.mjs +25 -0
- package/dist/ct.d.mts +4 -4
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +20 -4
- package/package.json +17 -9
package/README.md
CHANGED
|
@@ -37,8 +37,9 @@ Create an API token in the kinora dashboard (Settings → Workspace). Self-hosti
|
|
|
37
37
|
|
|
38
38
|
## Videos and screenshots without tracing
|
|
39
39
|
|
|
40
|
-
Traces are uploaded by default,
|
|
41
|
-
|
|
40
|
+
Traces are uploaded by default, along with the expected / actual / diff images of a failed
|
|
41
|
+
`toHaveScreenshot`, which kinora shows as a comparison. Playwright already embeds a test's other
|
|
42
|
+
screenshots and its video inside the trace.zip. If you run without tracing, upload them on their own:
|
|
42
43
|
|
|
43
44
|
```ts
|
|
44
45
|
reporter: [['@kinora/reporter', {
|
package/dist/a11y.d.mts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Page } from "@playwright/test";
|
|
2
|
+
import AxeBuilder from "@axe-core/playwright";
|
|
3
|
+
//#region src/a11y.d.ts
|
|
4
|
+
export type AxeResults = Awaited<ReturnType<AxeBuilder['analyze']>>;
|
|
5
|
+
export declare const A11Y_ATTACHMENT = "accessibility-scan-results";
|
|
6
|
+
/**
|
|
7
|
+
* Scans the page with axe (`@axe-core/playwright`) and attaches the result to the running test,
|
|
8
|
+
* which is where kinora reads it: without the attachment, a reporter only sees the test fail.
|
|
9
|
+
*
|
|
10
|
+
* Returns axe's result. Assert on `violations` to fail the test on them, or leave them be to
|
|
11
|
+
* record them as warnings. `configure` narrows or widens the scan, e.g.
|
|
12
|
+
* `axe => axe.withTags(['wcag2a', 'wcag2aa'])`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function scanA11y(page: Page, configure?: (axe: AxeBuilder) => AxeBuilder): Promise<AxeResults>;
|
|
15
|
+
//#endregion
|
package/dist/a11y.mjs
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { test } from "@playwright/test";
|
|
2
|
+
//#region src/a11y.ts
|
|
3
|
+
const A11Y_ATTACHMENT = "accessibility-scan-results";
|
|
4
|
+
/**
|
|
5
|
+
* Scans the page with axe (`@axe-core/playwright`) and attaches the result to the running test,
|
|
6
|
+
* which is where kinora reads it: without the attachment, a reporter only sees the test fail.
|
|
7
|
+
*
|
|
8
|
+
* Returns axe's result. Assert on `violations` to fail the test on them, or leave them be to
|
|
9
|
+
* record them as warnings. `configure` narrows or widens the scan, e.g.
|
|
10
|
+
* `axe => axe.withTags(['wcag2a', 'wcag2aa'])`.
|
|
11
|
+
*/
|
|
12
|
+
async function scanA11y(page, configure) {
|
|
13
|
+
const { default: Axe } = await import("@axe-core/playwright").catch(() => {
|
|
14
|
+
throw new Error("scanA11y needs @axe-core/playwright: add it to your dev dependencies.");
|
|
15
|
+
});
|
|
16
|
+
const axe = new Axe({ page });
|
|
17
|
+
const results = await (configure?.(axe) ?? axe).analyze();
|
|
18
|
+
await test.info().attach(A11Y_ATTACHMENT, {
|
|
19
|
+
body: JSON.stringify(results),
|
|
20
|
+
contentType: "application/json"
|
|
21
|
+
});
|
|
22
|
+
return results;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { A11Y_ATTACHMENT, scanA11y };
|
package/dist/ct.d.mts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { TestInfo, expect } from "@playwright/test";
|
|
2
2
|
//#region src/ct.d.ts
|
|
3
3
|
type Annotations = TestInfo['annotations'];
|
|
4
|
-
declare function recordStory(annotations: Annotations, storyId: string): void;
|
|
5
|
-
declare function withStoryAnnotations<M extends (storyId: string, ...rest: any[]) => unknown>(mount: M, annotations: Annotations): M;
|
|
4
|
+
export declare function recordStory(annotations: Annotations, storyId: string): void;
|
|
5
|
+
export declare function withStoryAnnotations<M extends (storyId: string, ...rest: any[]) => unknown>(mount: M, annotations: Annotations): M;
|
|
6
6
|
/**
|
|
7
7
|
* Drop-in replacement for `test` from `@playwright/test` in component tests: `mount` records
|
|
8
8
|
* the mounted story id on the test, which lets kinora group results by component and story.
|
|
9
9
|
*/
|
|
10
|
-
declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
10
|
+
export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
|
|
11
11
|
//#endregion
|
|
12
|
-
export { expect
|
|
12
|
+
export { expect };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AttachmentKind, CiMeta, GitMeta } from "@kinora/core";
|
|
2
2
|
import { FullConfig, FullResult, Reporter, Suite } from "@playwright/test/reporter";
|
|
3
3
|
//#region src/index.d.ts
|
|
4
|
-
interface KinoraReporterOptions {
|
|
4
|
+
export interface KinoraReporterOptions {
|
|
5
5
|
/** kinora server base URL. Defaults to env KINORA_URL, then the hosted cloud. Set for self-host. */
|
|
6
6
|
url?: string;
|
|
7
7
|
/** Project API token. Defaults to env KINORA_TOKEN (keep it out of the config file). */
|
|
@@ -23,13 +23,14 @@ interface KinoraReporterOptions {
|
|
|
23
23
|
policy?: 'always' | 'on-failure';
|
|
24
24
|
};
|
|
25
25
|
/**
|
|
26
|
-
* Which attachment kinds to upload. Defaults to `['trace'
|
|
26
|
+
* Which attachment kinds to upload. Defaults to `['trace', 'snapshot']` (`snapshot` = the images
|
|
27
|
+
* of a failed screenshot assertion, shown as a comparison). Add `'video'` / `'screenshot'`
|
|
27
28
|
* to host them on their own, which is what you want when `trace` is off (with tracing on,
|
|
28
29
|
* Playwright already embeds them in the trace.zip).
|
|
29
30
|
*/
|
|
30
31
|
uploadAttachments?: AttachmentKind[];
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
export default class KinoraReporter implements Reporter {
|
|
33
34
|
private readonly options;
|
|
34
35
|
private suite;
|
|
35
36
|
private config;
|
|
@@ -38,5 +39,4 @@ declare class KinoraReporter implements Reporter {
|
|
|
38
39
|
onEnd(result: FullResult): Promise<void>;
|
|
39
40
|
private maybePostPrComment;
|
|
40
41
|
}
|
|
41
|
-
//#endregion
|
|
42
|
-
export { KinoraReporterOptions, KinoraReporter as default };
|
|
42
|
+
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { readFileSync, statSync } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import process from "node:process";
|
|
4
|
-
import { DEFAULT_KINORA_URL, DEFAULT_UPLOAD_ATTACHMENTS, IngestError, createIngestClient, detectCiEnv, effectiveAttachments, isUploadableAttachment, makeTestKey, postPrComment, resolvePrContext } from "@kinora/core";
|
|
4
|
+
import { DEFAULT_KINORA_URL, DEFAULT_UPLOAD_ATTACHMENTS, IngestError, a11yFromScans, createIngestClient, detectCiEnv, effectiveAttachments, isUploadableAttachment, makeTestKey, parseAxeScan, postPrComment, resolvePrContext } from "@kinora/core";
|
|
5
5
|
//#region src/index.ts
|
|
6
6
|
function identity(test) {
|
|
7
7
|
let file = "";
|
|
@@ -24,9 +24,24 @@ function identity(test) {
|
|
|
24
24
|
projectName
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
+
const MAX_SCAN_BYTES = 20971520;
|
|
28
|
+
function axeScans(attachments) {
|
|
29
|
+
return attachments.flatMap((a) => {
|
|
30
|
+
if (!a.contentType.includes("json")) return [];
|
|
31
|
+
try {
|
|
32
|
+
const text = a.body ? a.body.length <= MAX_SCAN_BYTES ? a.body.toString("utf8") : void 0 : a.path && statSync(a.path).size <= MAX_SCAN_BYTES ? readFileSync(a.path, "utf8") : void 0;
|
|
33
|
+
const scan = text ? parseAxeScan(text) : void 0;
|
|
34
|
+
return scan ? [scan] : [];
|
|
35
|
+
} catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
27
40
|
function toNormTest(test) {
|
|
28
41
|
const { file, titlePath, projectName } = identity(test);
|
|
29
42
|
const last = test.results.at(-1);
|
|
43
|
+
const attachments = effectiveAttachments(test.results);
|
|
44
|
+
const a11y = a11yFromScans(axeScans(attachments), test.ok());
|
|
30
45
|
return {
|
|
31
46
|
testKey: makeTestKey(file, titlePath, projectName),
|
|
32
47
|
title: test.title,
|
|
@@ -49,12 +64,13 @@ function toNormTest(test) {
|
|
|
49
64
|
stack: e.stack,
|
|
50
65
|
location: e.location
|
|
51
66
|
}] : []),
|
|
52
|
-
attachments:
|
|
67
|
+
attachments: attachments.map((a) => ({
|
|
53
68
|
name: a.name,
|
|
54
69
|
contentType: a.contentType,
|
|
55
70
|
path: a.path,
|
|
56
71
|
hasBody: a.body != null
|
|
57
|
-
}))
|
|
72
|
+
})),
|
|
73
|
+
...a11y && { a11y }
|
|
58
74
|
};
|
|
59
75
|
}
|
|
60
76
|
function countsOf(tests) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kinora/reporter",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"description": "Playwright reporter that uploads test results to a kinora server",
|
|
6
6
|
"author": "Joris Gallot",
|
|
7
7
|
"license": "MIT",
|
|
@@ -21,31 +21,39 @@
|
|
|
21
21
|
],
|
|
22
22
|
"exports": {
|
|
23
23
|
".": "./dist/index.mjs",
|
|
24
|
-
"./ct": "./dist/ct.mjs"
|
|
24
|
+
"./ct": "./dist/ct.mjs",
|
|
25
|
+
"./a11y": "./dist/a11y.mjs"
|
|
25
26
|
},
|
|
26
27
|
"main": "./dist/index.mjs",
|
|
27
28
|
"files": [
|
|
28
29
|
"dist"
|
|
29
30
|
],
|
|
30
31
|
"engines": {
|
|
31
|
-
"node": ">=20"
|
|
32
|
+
"node": ">=20.20.2"
|
|
32
33
|
},
|
|
33
34
|
"publishConfig": {
|
|
34
35
|
"access": "public"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
38
|
+
"@axe-core/playwright": ">=4.7.0",
|
|
37
39
|
"@playwright/test": ">=1.40.0"
|
|
38
40
|
},
|
|
41
|
+
"peerDependenciesMeta": {
|
|
42
|
+
"@axe-core/playwright": {
|
|
43
|
+
"optional": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
39
46
|
"dependencies": {
|
|
40
|
-
"@kinora/core": "0.
|
|
47
|
+
"@kinora/core": "0.10.0"
|
|
41
48
|
},
|
|
42
49
|
"devDependencies": {
|
|
43
|
-
"@playwright
|
|
44
|
-
"@
|
|
45
|
-
"@
|
|
46
|
-
"
|
|
50
|
+
"@axe-core/playwright": "^4.13.0",
|
|
51
|
+
"@playwright/test": "^1.64.0",
|
|
52
|
+
"@types/node": "^26.6.5",
|
|
53
|
+
"@vitest/coverage-v8": "^5.0.3",
|
|
54
|
+
"tsdown": "^0.23.1",
|
|
47
55
|
"typescript": "~6.0.3",
|
|
48
|
-
"vitest": "^
|
|
56
|
+
"vitest": "^5.0.3"
|
|
49
57
|
},
|
|
50
58
|
"scripts": {
|
|
51
59
|
"build": "tsdown",
|