@ingcreators/annot-playwright 0.1.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # @ingcreators/annot-playwright
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 35e3ad7: `annotateScreenshot()` now accepts the annotation DSL added in `@ingcreators/annot-annotator@0.2.0`:
8
+
9
+ ```ts
10
+ import {
11
+ test,
12
+ expect,
13
+ type BboxAnnotation,
14
+ } from "@ingcreators/annot-playwright";
15
+
16
+ test("login form", async ({ page, annotator }, testInfo) => {
17
+ const submit = page.getByRole("button", { name: "Sign in" });
18
+ const box = (await submit.boundingBox())!;
19
+ const annotated = await annotator.annotateScreenshot(page, {
20
+ annotations: [
21
+ { type: "rect", bbox: box, intent: "error" },
22
+ {
23
+ type: "callout",
24
+ at: { x: 50, y: 50 },
25
+ targetBbox: box,
26
+ content: "Failing",
27
+ },
28
+ ] satisfies BboxAnnotation[],
29
+ });
30
+ await testInfo.attach("failure.png", { body: annotated });
31
+ });
32
+ ```
33
+
34
+ The existing `annotationsSvg: string` shape still works; the new `annotations: BboxAnnotation[]` is an additive overload. `intent` shorthand (`"info"` / `"warning"` / `"error"` / `"success"` / `"neutral"`) maps to the Annot design system's semantic colours so callers no longer think in raw hex values, and `callout` composes the rect + arrow + caption in a single entry.
35
+
36
+ `rectForBoundingBox` / `arrowBetween` / `textAt` are now thin re-exports from `@ingcreators/annot-annotator` rather than local helpers. Cosmetic delta: `arrowBetween`'s marker id prefix changed from `annot-pw-arrow-N` to `annot-arrow-N`; snapshot-on-SVG tests should expect this.
37
+
38
+ Also re-exports the bbox-flavour DSL types (`BboxAnnotation`, `BBox`, `Point`, `Intent`, `AnnotationStyle`, `BboxRedactRegion`, `RedactStyle`, …) from `@ingcreators/annot-annotator` so callers keep a single import line.
39
+
40
+ ### Patch Changes
41
+
42
+ - Updated dependencies [92378f9]
43
+ - @ingcreators/annot-annotator@0.2.0
44
+
3
45
  ## 0.1.0
4
46
 
5
47
  ### Minor Changes
package/README.md CHANGED
@@ -1,21 +1,22 @@
1
1
  # `@ingcreators/annot-playwright`
2
2
 
3
- Playwright fixture for [`@ingcreators/annot-annotator`](../annotator/README.md).
3
+ [![npm](https://img.shields.io/npm/v/@ingcreators/annot-playwright.svg)](https://www.npmjs.com/package/@ingcreators/annot-playwright)
4
+ [![license](https://img.shields.io/npm/l/@ingcreators/annot-playwright.svg)](https://github.com/ingcreators/annot/blob/main/LICENSE)
5
+
6
+ Playwright fixture for [`@ingcreators/annot-annotator`](https://www.npmjs.com/package/@ingcreators/annot-annotator).
4
7
  Emit annotated screenshots from test failures without leaving the
5
8
  test file.
6
9
 
7
- > **Status:** Workspace package, not yet published to npm. Becomes
8
- > installable in Phase 3 of the headless-annotator track (gated on
9
- > Changesets). The Phase 1 annotator it depends on is also
10
- > workspace-only until then.
11
-
12
- ## Install (post-publish)
10
+ ## Install
13
11
 
14
12
  ```sh
15
13
  pnpm add -D @playwright/test @ingcreators/annot-playwright
14
+ # or
15
+ npm install --save-dev @playwright/test @ingcreators/annot-playwright
16
16
  ```
17
17
 
18
- (`@playwright/test` is a peer dependency.)
18
+ `@playwright/test` is a peer dependency — bring your own pinned
19
+ version.
19
20
 
20
21
  ## Usage
21
22
 
package/dist/fixture.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Annotator } from '@ingcreators/annot-annotator';
1
+ import { Annotator, BboxAnnotation } from '@ingcreators/annot-annotator';
2
2
  /**
3
3
  * Minimal Playwright `Page` surface the fixture relies on. The full
4
4
  * `@playwright/test` `Page` type is much wider, but importing it
@@ -22,12 +22,29 @@ export interface PageLike {
22
22
  * Playwright `Page`, captures a screenshot, and overlays the
23
23
  * caller-supplied annotation SVG.
24
24
  */
25
+ /**
26
+ * Annotation input for `annotateScreenshot`. Either flavour works:
27
+ *
28
+ * - `annotationsSvg: string` — raw SVG fragment, useful for the
29
+ * `rectForBoundingBox` / `arrowBetween` / `textAt` primitives
30
+ * and any custom SVG you compose yourself.
31
+ * - `annotations: BboxAnnotation[]` — the DSL flavour added in
32
+ * 0.2.0. Each entry is a typed shape (`rect` / `circle` /
33
+ * `arrow` / `text` / `callout` / `raw`) with an optional
34
+ * `intent` shorthand mapping to design-system colours.
35
+ */
36
+ export type AnnotateScreenshotOptions = {
37
+ annotationsSvg: string;
38
+ annotations?: never;
39
+ fullPage?: boolean;
40
+ } | {
41
+ annotations: readonly BboxAnnotation[];
42
+ annotationsSvg?: never;
43
+ fullPage?: boolean;
44
+ };
25
45
  export interface PlaywrightAnnotator {
26
46
  raw: Annotator;
27
- annotateScreenshot(page: PageLike, opts: {
28
- annotationsSvg: string;
29
- fullPage?: boolean;
30
- }): Promise<Uint8Array>;
47
+ annotateScreenshot(page: PageLike, opts: AnnotateScreenshotOptions): Promise<Uint8Array>;
31
48
  }
32
49
  /**
33
50
  * `test = base.extend({ annotator })` — drop-in replacement for
@@ -42,8 +59,8 @@ export declare const test: import('@playwright/test').TestType<import('@playwrig
42
59
  * — exported so callers who build their own Playwright fixture
43
60
  * (e.g. with extra fixtures composed on top) can still use the
44
61
  * one-call screenshot+annotate flow.
62
+ *
63
+ * Accepts either an `annotationsSvg: string` (raw SVG path) or an
64
+ * `annotations: BboxAnnotation[]` (DSL path added in 0.2.0).
45
65
  */
46
- export declare function annotateScreenshot(annotator: Annotator, page: PageLike, opts: {
47
- annotationsSvg: string;
48
- fullPage?: boolean;
49
- }): Promise<Uint8Array>;
66
+ export declare function annotateScreenshot(annotator: Annotator, page: PageLike, opts: AnnotateScreenshotOptions): Promise<Uint8Array>;
package/dist/helpers.d.ts CHANGED
@@ -1,43 +1 @@
1
- export interface BoundingBox {
2
- x: number;
3
- y: number;
4
- width: number;
5
- height: number;
6
- }
7
- export interface Point {
8
- x: number;
9
- y: number;
10
- }
11
- export interface RectOptions {
12
- stroke?: string;
13
- strokeWidth?: number;
14
- fill?: string;
15
- }
16
- export interface ArrowOptions {
17
- color?: string;
18
- strokeWidth?: number;
19
- }
20
- export interface TextOptions {
21
- color?: string;
22
- fontSize?: number;
23
- anchor?: "start" | "middle" | "end";
24
- }
25
- /**
26
- * Outline a bounding box (e.g. from `locator.boundingBox()`) with
27
- * an SVG `<rect>`. Defaults: red stroke, 2px width, no fill.
28
- */
29
- export declare function rectForBoundingBox(bbox: BoundingBox, opts?: RectOptions): string;
30
- /**
31
- * Draw an arrow from `from` to `to`. Inlines a unique-id `<marker>`
32
- * definition so the helper is self-contained — call it twice and
33
- * each call produces a distinct arrowhead marker (no collision
34
- * across uses on the same SVG).
35
- *
36
- * Defaults: red color, 2px stroke.
37
- */
38
- export declare function arrowBetween(from: Point, to: Point, opts?: ArrowOptions): string;
39
- /**
40
- * Drop a text label at a position. Defaults: red, 14px,
41
- * start-anchored.
42
- */
43
- export declare function textAt(at: Point, content: string, opts?: TextOptions): string;
1
+ export { type ArrowOptions, arrowBetween, type BoundingBox, type RectOptions, rectForBoundingBox, type TextOptions, textAt, } from '@ingcreators/annot-annotator';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export type { AnnotationStyle, BBox, BboxAnnotation, BboxArrowAnnotation, BboxCalloutAnnotation, BboxCircleAnnotation, BboxRectAnnotation, BboxRedactRegion, BboxTextAnnotation, Intent, Point, RawAnnotation, RedactStyle, } from '@ingcreators/annot-annotator';
2
+ export { bboxAnnotationsToSvg } from '@ingcreators/annot-annotator';
1
3
  export { expect } from '@playwright/test';
2
- export { annotateScreenshot, type PageLike, type PlaywrightAnnotator, test, } from './fixture.js';
3
- export { type ArrowOptions, arrowBetween, type BoundingBox, type Point, type RectOptions, rectForBoundingBox, type TextOptions, textAt, } from './helpers.js';
4
+ export { type AnnotateScreenshotOptions, annotateScreenshot, type PageLike, type PlaywrightAnnotator, test, } from './fixture.js';
5
+ export { type ArrowOptions, arrowBetween, type BoundingBox, type RectOptions, rectForBoundingBox, type TextOptions, textAt, } from './helpers.js';
package/dist/index.js CHANGED
@@ -1,53 +1,38 @@
1
- import { expect as e, test as t } from "@playwright/test";
2
- import { createAnnotator as n } from "@ingcreators/annot-annotator";
3
- //#region src/fixture.ts
4
- var r = t.extend({ annotator: async ({}, e) => {
5
- let t = n();
6
- await e({
7
- raw: t,
8
- annotateScreenshot: (e, n) => i(t, e, n)
9
- });
10
- } });
11
- async function i(e, t, n) {
12
- let r = await t.screenshot({ fullPage: n.fullPage }), { width: i, height: o } = a(r), s = `data:image/png;base64,${r.toString("base64")}`;
13
- return e.toPng({
14
- originalDataUrl: s,
15
- annotationsSvg: n.annotationsSvg,
16
- width: i,
17
- height: o
18
- });
19
- }
20
- function a(e) {
21
- if (e.length < 24) throw Error("PNG too short to contain IHDR chunk");
22
- let t = new DataView(e.buffer, e.byteOffset, e.byteLength);
23
- return {
24
- width: t.getUint32(16, !1),
25
- height: t.getUint32(20, !1)
26
- };
27
- }
28
- //#endregion
29
- //#region src/helpers.ts
30
- function o(e, t = {}) {
31
- let n = t.stroke ?? "red", r = t.strokeWidth ?? 2, i = t.fill ?? "none";
32
- return `<rect x="${e.x}" y="${e.y}" width="${e.width}" height="${e.height}" fill="${d(i)}" stroke="${d(n)}" stroke-width="${r}"/>`;
33
- }
34
- function s(e, t, n = {}) {
35
- let r = n.color ?? "red", i = n.strokeWidth ?? 2, a = `annot-pw-arrow-${u()}`;
36
- return `<defs><marker id="${a}" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto" markerUnits="strokeWidth"><path d="M 0 0 L 10 5 L 0 10 z" fill="${d(r)}"/></marker></defs><line x1="${e.x}" y1="${e.y}" x2="${t.x}" y2="${t.y}" stroke="${d(r)}" stroke-width="${i}" marker-end="url(#${a})"/>`;
37
- }
38
- function c(e, t, n = {}) {
39
- let r = n.color ?? "red", i = n.fontSize ?? 14, a = n.anchor ?? "start";
40
- return `<text x="${e.x}" y="${e.y}" fill="${d(r)}" font-size="${i}" text-anchor="${a}">` + f(t) + "</text>";
41
- }
42
- var l = 0;
43
- function u() {
44
- return l = l + 1 | 0, l;
45
- }
46
- function d(e) {
47
- return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
48
- }
49
- function f(e) {
50
- return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
51
- }
52
- //#endregion
53
- export { i as annotateScreenshot, s as arrowBetween, e as expect, o as rectForBoundingBox, r as test, c as textAt };
1
+ import { createAnnotator as c, bboxAnnotationsToSvg as g } from "@ingcreators/annot-annotator";
2
+ import { arrowBetween as m, bboxAnnotationsToSvg as S, rectForBoundingBox as v, textAt as P } from "@ingcreators/annot-annotator";
3
+ import { test as f } from "@playwright/test";
4
+ import { expect as A } from "@playwright/test";
5
+ const u = f.extend({
6
+ // biome-ignore lint/correctness/noEmptyPattern: Playwright fixture signature requires the empty destructure.
7
+ annotator: async ({}, n) => {
8
+ const o = c();
9
+ await n({
10
+ raw: o,
11
+ annotateScreenshot: (t, e) => h(o, t, e)
12
+ });
13
+ }
14
+ });
15
+ async function h(n, o, t) {
16
+ const e = await o.screenshot({ fullPage: t.fullPage }), { width: a, height: r } = w(e), i = `data:image/png;base64,${e.toString("base64")}`, s = "annotations" in t && t.annotations !== void 0 ? g(t.annotations) : t.annotationsSvg ?? "";
17
+ return n.toPng({
18
+ originalDataUrl: i,
19
+ annotationsSvg: s,
20
+ width: a,
21
+ height: r
22
+ });
23
+ }
24
+ function w(n) {
25
+ if (n.length < 24)
26
+ throw new Error("PNG too short to contain IHDR chunk");
27
+ const o = new DataView(n.buffer, n.byteOffset, n.byteLength), t = o.getUint32(16, !1), e = o.getUint32(20, !1);
28
+ return { width: t, height: e };
29
+ }
30
+ export {
31
+ h as annotateScreenshot,
32
+ m as arrowBetween,
33
+ S as bboxAnnotationsToSvg,
34
+ A as expect,
35
+ v as rectForBoundingBox,
36
+ u as test,
37
+ P as textAt
38
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingcreators/annot-playwright",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Playwright fixture for annotated screenshots — emit annotated PNGs from failing tests without leaving the test file. Pairs `test.extend({ annotator })` with the headless renderer from @ingcreators/annot-annotator.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "ingcreators",
@@ -44,11 +44,11 @@
44
44
  "devDependencies": {
45
45
  "@playwright/test": "^1.50.0",
46
46
  "typescript": "^6.0.3",
47
- "vite": "^8.0.13",
47
+ "vite": "^6.4.2",
48
48
  "vite-plugin-dts": "^5.0.0"
49
49
  },
50
50
  "dependencies": {
51
- "@ingcreators/annot-annotator": "0.1.0"
51
+ "@ingcreators/annot-annotator": "0.2.0"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "@playwright/test": "^1.40.0"