@sit-onyx/playwright-utils 1.0.0-beta.4 → 1.0.0-dev-20250912111044

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.
@@ -0,0 +1,28 @@
1
+ import type { Component } from "vue";
2
+ import type { ComponentEmitProps } from "./types.js";
3
+ export declare const EMIT_SPY_SYMBOL: unique symbol;
4
+ /**
5
+ * Creates a simple, typed spy for recording emits.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * // create spy
10
+ * const onUpdateOpen = createEmitSpy<typeof OnyxColorSchemeDialog, "onUpdate:open">();
11
+ * // add spy
12
+ * const component = await mount(<OnyxColorSchemeDialog onUpdate:open={onUpdateOpen} />);
13
+ * // check spy
14
+ * expectEmit(onUpdateOpen, 1, [false]);
15
+ * ```
16
+ */
17
+ export declare const createEmitSpy: <C extends Component, Key extends keyof Emits, Emits = ComponentEmitProps<C>, Handler = NonNullable<Emits[Key]>, Args extends unknown[] = Handler extends (...args: infer _Args) => unknown ? _Args : unknown[]>() => {
18
+ (...args: Args): void;
19
+ [EMIT_SPY_SYMBOL]: Args[];
20
+ };
21
+ /**
22
+ * Asserts the emits recorded from the spy created by `createEmitSpy`.
23
+ * Expects the spy to have recorded `n` calls, and `matches` to match the arguments of the last call.
24
+ * @see `createEmitSpy` documentation for example usage.
25
+ */
26
+ export declare const expectEmit: <Handler extends {
27
+ [EMIT_SPY_SYMBOL]: unknown[][];
28
+ }>(emitSpy: Handler, n: number, matches?: unknown[]) => unknown[] | undefined;
@@ -0,0 +1,23 @@
1
+ import type { Component } from "vue";
2
+ import type { ComponentExposed } from "vue-component-type-helpers";
3
+ /**
4
+ * Picks the emits from an components property type.
5
+ *
6
+ * Unlike the `ComponentEmit` type utility from *vue-component-type-helpers*, it provides the emits as `Record<EmitName, EmitHandler>`, rather than a type intersection of the emit functions.
7
+ *
8
+ * e.g.:
9
+ * ```ts
10
+ * import MyInput from "./MyInput.vue";
11
+ * import type { ComponentExposed } from "vue-component-type-helpers";
12
+ *
13
+ * type MyInputPublicProps = ComponentExposed<typeof MyInput>["$props"];
14
+ * type MyInputVModelEmits = VModelEmits<MyInputPublicProps>; // => { 'onUpdate:modelValue': (newValue: string) => void }
15
+ * ```
16
+ */
17
+ export type PickEmitsFromProps<T> = {
18
+ -readonly [key in keyof T as key extends `on${string}` ? key extends `onVnode${string}` ? never : key : never]: NonNullable<T[key]>;
19
+ };
20
+ /**
21
+ * Unwraps the declared emits from a Vue component.
22
+ */
23
+ export type ComponentEmitProps<C extends Component> = PickEmitsFromProps<ComponentExposed<C>["$props"]>;
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
+ export * from "./emits/index.js";
2
+ export * from "./emits/types.js";
1
3
  export * from "./screenshots/index.js";
2
4
  export * from "./screenshots/types.js";
package/dist/index.js CHANGED
@@ -1,13 +1,24 @@
1
+ import { expect as g } from "@playwright/test";
1
2
  import { jsxs as m, jsx as d } from "playwright/jsx-runtime";
2
- import { expect as f, test as g } from "@playwright/experimental-ct-vue";
3
- const l = (t) => t.replace(/\W/g, "-"), B = (t) => {
4
- const o = () => {
3
+ import { expect as v, test as x } from "@playwright/experimental-ct-vue";
4
+ const b = Symbol("EMIT_SPY_SYMBOL"), O = () => {
5
+ const t = [], n = (...e) => {
6
+ t.push(e);
7
+ };
8
+ return n[b] = t, n;
9
+ }, C = (t, n, e) => {
10
+ const r = t[b];
11
+ g(r).toHaveLength(n);
12
+ const a = r[n - 1];
13
+ return e && g(a).toMatchObject(e), a;
14
+ }, l = (t) => t.replace(/\W/g, "-"), k = (t) => {
15
+ const n = () => {
5
16
  const e = [
6
- `"blank ${t.columns.map((s) => `column-${l(s)}`).join(" ")}"`
17
+ `"blank ${t.columns.map((r) => `column-${l(r)}`).join(" ")}"`
7
18
  ];
8
- return t.rows.forEach((s) => {
19
+ return t.rows.forEach((r) => {
9
20
  e.push(
10
- `"row-${l(s)} ${t.columns.map((n) => `${l(s)}-${l(n)}`).join(" ")}"`
21
+ `"row-${l(r)} ${t.columns.map((a) => `${l(r)}-${l(a)}`).join(" ")}"`
11
22
  );
12
23
  }), e.join(`
13
24
  `);
@@ -34,7 +45,7 @@ const l = (t) => t.replace(/\W/g, "-"), B = (t) => {
34
45
  alignItems: "center",
35
46
  justifyContent: "center",
36
47
  gridTemplateColumns: `auto repeat(${t.columns.length}, 1fr)`,
37
- gridTemplateAreas: o()
48
+ gridTemplateAreas: n()
38
49
  },
39
50
  children: [
40
51
  /* @__PURE__ */ d("div", { style: { gridArea: "blank" } }),
@@ -43,85 +54,88 @@ const l = (t) => t.replace(/\W/g, "-"), B = (t) => {
43
54
  }
44
55
  )
45
56
  ] });
46
- }, H = ({
57
+ }, I = ({
47
58
  defaults: t
48
59
  }) => ({
49
60
  /**
50
61
  * Creates a single matrix screenshot that includes the screenshots for every column-row combination.
51
62
  */
52
63
  executeMatrixScreenshotTest: async (e) => {
53
- g(`${e.name}`, async ({ mount: s, page: n, browserName: v, context: $ }) => {
54
- g.setTimeout(e.columns.length * e.rows.length * 25e3);
55
- const b = async (r, a, i) => {
56
- await n.getByRole("document").focus(), await n.getByRole("document").hover({ position: { x: 0, y: 0 }, force: !0 }), await n.mouse.up();
57
- const c = await s(r);
58
- await t?.hooks?.beforeEach?.(c, n, a, i, e.context), await e.hooks?.beforeEach?.(c, n, a, i, e.context);
59
- const y = await c.screenshot({ animations: "disabled" }), h = await c.boundingBox(), k = `${l(i)}-${l(a)}`;
60
- return await t?.hooks?.afterEach?.(c, n, a, i, e.context), await e.hooks?.afterEach?.(c, n, a, i, e.context), { box: h, id: k, screenshot: y };
64
+ x(`${e.name}`, async ({ mount: r, page: a, browserName: S, context: $ }) => {
65
+ x.setTimeout(e.columns.length * e.rows.length * 25e3);
66
+ const E = async (c, s, i) => {
67
+ await a.getByRole("document").focus(), await a.getByRole("document").hover({ position: { x: 0, y: 0 }, force: !0 }), await a.mouse.up();
68
+ const o = await r(c);
69
+ await t?.hooks?.beforeEach?.(o, a, s, i, e.context), await e.hooks?.beforeEach?.(o, a, s, i, e.context);
70
+ const y = await o.screenshot({ animations: "disabled" }), h = await o.boundingBox(), P = `${l(i)}-${l(s)}`;
71
+ return await t?.hooks?.afterEach?.(o, a, s, i, e.context), await e.hooks?.afterEach?.(o, a, s, i, e.context), { box: h, id: P, screenshot: y };
61
72
  }, u = /* @__PURE__ */ new Map();
62
- for (const r of e.rows)
63
- for (const a of e.columns) {
64
- const i = e.component(a, r), c = e.removePadding ?? t?.removePadding, h = await b(/* @__PURE__ */ d(
73
+ for (const c of e.rows)
74
+ for (const s of e.columns) {
75
+ const i = e.component(s, c), o = e.removePadding ?? t?.removePadding, h = await E(/* @__PURE__ */ d(
65
76
  "div",
66
77
  {
67
78
  style: {
68
79
  display: "grid",
69
80
  width: "max-content",
70
- padding: c ? void 0 : "1rem"
81
+ padding: o ? void 0 : "1rem"
71
82
  },
72
83
  children: i
73
84
  }
74
- ), a, r);
85
+ ), s, c);
75
86
  u.set(h.id, h);
76
87
  }
77
88
  const w = "/_playwright-matrix-screenshot";
78
- await $.route(`${w}*`, (r, a) => {
79
- const c = new URL(a.url()).searchParams.get("id") ?? "";
80
- return r.fulfill({
89
+ await $.route(`${w}*`, (c, s) => {
90
+ const o = new URL(s.url()).searchParams.get("id") ?? "";
91
+ return c.fulfill({
81
92
  status: 200,
82
93
  contentType: "image/png",
83
- body: u.get(c)?.screenshot
94
+ body: u.get(o)?.screenshot
84
95
  });
85
96
  });
86
- const S = Array.from(u.values()).map(({ box: r, id: a }) => /* @__PURE__ */ d(
97
+ const T = Array.from(u.values()).map(({ box: c, id: s }) => /* @__PURE__ */ d(
87
98
  "img",
88
99
  {
89
- width: r?.width,
90
- height: r?.height,
91
- style: { gridArea: a },
92
- src: `${w}?id=${a}`,
93
- alt: a
100
+ width: c?.width,
101
+ height: c?.height,
102
+ style: { gridArea: s },
103
+ src: `${w}?id=${s}`,
104
+ alt: s
94
105
  }
95
- )), T = e.rows.map((r) => x({ name: r, type: "row" })), E = e.columns.map(
96
- (r) => x({ name: r, type: "column" })
97
- ), A = B({
106
+ )), M = e.rows.map((c) => f({ name: c, type: "row" })), A = e.columns.map(
107
+ (c) => f({ name: c, type: "column" })
108
+ ), j = k({
98
109
  columns: e.columns,
99
110
  rows: e.rows,
100
111
  name: e.name,
101
- browserName: v,
102
- children: [...S, ...T, ...E]
103
- }), j = await s(A);
104
- await f(j).toHaveScreenshot(`${e.name}.png`), await n.unroute(`${w}*`);
112
+ browserName: S,
113
+ children: [...T, ...M, ...A]
114
+ }), B = await r(j);
115
+ await v(B).toHaveScreenshot(`${e.name}.png`), await a.unroute(`${w}*`);
105
116
  });
106
117
  }
107
- }), L = async (t) => {
108
- await f(t).toBeVisible(), await t.evaluate((o) => {
109
- o.style.height = `${o.scrollHeight}px`, o.style.width = `${o.scrollWidth}px`;
118
+ }), Y = async (t) => {
119
+ await v(t).toBeVisible(), await t.evaluate((n) => {
120
+ n.style.height = `${n.scrollHeight}px`, n.style.width = `${n.scrollWidth}px`;
110
121
  });
111
- }, x = (t) => /* @__PURE__ */ d(
122
+ }, f = (t) => /* @__PURE__ */ d(
112
123
  "div",
113
124
  {
114
125
  style: { textAlign: "center", gridArea: `${t.type}-${l(t.name)}` },
115
126
  children: t.name
116
127
  }
117
- ), C = async ({ component: t, page: o, state: e }) => {
118
- if (e === "hover" && await t.hover(), e === "focus-visible" && await o.keyboard.press("Tab"), e === "active") {
119
- const s = await t.boundingBox(), n = { x: s.x + s.width / 2, y: s.y + s.height / 2 };
120
- await o.mouse.move(n.x, n.y), await o.mouse.down();
128
+ ), p = async ({ component: t, page: n, state: e }) => {
129
+ if (e === "hover" && await t.hover(), e === "focus-visible" && await n.keyboard.press("Tab"), e === "active") {
130
+ const r = await t.boundingBox(), a = { x: r.x + r.width / 2, y: r.y + r.height / 2 };
131
+ await n.mouse.move(a.x, a.y), await n.mouse.down();
121
132
  }
122
133
  };
123
134
  export {
124
- L as adjustSizeToAbsolutePosition,
125
- C as useFocusStateHooks,
126
- H as useMatrixScreenshotTest
135
+ b as EMIT_SPY_SYMBOL,
136
+ Y as adjustSizeToAbsolutePosition,
137
+ O as createEmitSpy,
138
+ C as expectEmit,
139
+ p as useFocusStateHooks,
140
+ I as useMatrixScreenshotTest
127
141
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sit-onyx/playwright-utils",
3
3
  "description": "Utilities for Vue component testing with Playwright",
4
- "version": "1.0.0-beta.4",
4
+ "version": "1.0.0-dev-20250912111044",
5
5
  "type": "module",
6
6
  "author": "Schwarz IT KG",
7
7
  "license": "Apache-2.0",
@@ -10,11 +10,11 @@
10
10
  },
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "https://github.com/schwarzit/onyx",
13
+ "url": "https://github.com/SchwarzIT/onyx",
14
14
  "directory": "packages/playwright-utils"
15
15
  },
16
16
  "bugs": {
17
- "url": "https://github.com/schwarzit/onyx/issues"
17
+ "url": "https://github.com/SchwarzIT/onyx/issues"
18
18
  },
19
19
  "files": [
20
20
  "dist"
@@ -30,12 +30,13 @@
30
30
  "@playwright/experimental-ct-vue": ">= 1",
31
31
  "@playwright/test": ">= 1",
32
32
  "playwright": ">= 1",
33
- "vue": ">= 3"
33
+ "vue": ">= 3",
34
+ "vue-component-type-helpers": ">= 3"
34
35
  },
35
36
  "devDependencies": {
36
- "typescript": "5.8.3",
37
- "vite": "7.0.0",
38
- "@sit-onyx/shared": "1.0.0-beta.4"
37
+ "typescript": "5.9.2",
38
+ "vite": "7.1.5",
39
+ "@sit-onyx/shared": "0.1.0-dev-20250912111044"
39
40
  },
40
41
  "scripts": {
41
42
  "build": "vite build && vue-tsc --emitDeclarationOnly"