venetian 0.2.0-aarch64-linux → 0.2.3-aarch64-linux

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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/exe/aarch64-linux/LICENSE +204 -204
  4. data/exe/aarch64-linux/node +2 -2
  5. data/exe/aarch64-linux/package/browsers.json +10 -39
  6. data/exe/aarch64-linux/package/lib/bootstrap.js +1 -1
  7. data/exe/aarch64-linux/package/lib/coreBundle.js +14708 -12281
  8. data/exe/aarch64-linux/package/lib/server/electron/loader.js +5 -4
  9. data/exe/aarch64-linux/package/lib/serverRegistry.js +1674 -7078
  10. data/exe/aarch64-linux/package/lib/serverRegistry.js.LICENSE +8 -297
  11. data/exe/aarch64-linux/package/lib/tools/cli-client/help.json +39 -11
  12. data/exe/aarch64-linux/package/lib/tools/cli-client/minimist.js +1 -1
  13. data/exe/aarch64-linux/package/lib/tools/cli-client/output.js +9 -1
  14. data/exe/aarch64-linux/package/lib/tools/cli-client/program.js +18 -4
  15. data/exe/aarch64-linux/package/lib/tools/cli-client/registry.js +9 -5
  16. data/exe/aarch64-linux/package/lib/tools/cli-client/session.js +6 -1
  17. data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/SKILL.md +26 -5
  18. data/exe/aarch64-linux/package/lib/tools/{cli-client/skill/references/spec-driven-testing.md → skills/playwright-cli/references/test-generation.md} +135 -7
  19. data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/references/tracing.md +1 -1
  20. data/exe/aarch64-linux/package/lib/tools/skills/playwright-component-testing/SKILL.md +136 -0
  21. data/exe/aarch64-linux/package/lib/tools/skills/playwright-component-testing/references/gallery-spec.md +144 -0
  22. data/exe/aarch64-linux/package/lib/tools/skills/playwright-component-testing/references/migration.md +89 -0
  23. data/exe/aarch64-linux/package/lib/tools/skills/playwright-component-testing/references/react.md +69 -0
  24. data/exe/aarch64-linux/package/lib/tools/skills/playwright-component-testing/references/typing.md +173 -0
  25. data/exe/aarch64-linux/package/lib/tools/skills/playwright-component-testing/references/vue.md +77 -0
  26. data/exe/aarch64-linux/package/lib/tools/{trace → skills/playwright-trace}/SKILL.md +6 -3
  27. data/exe/aarch64-linux/package/lib/tools/utils/extension.js +44 -10
  28. data/exe/aarch64-linux/package/lib/utilsBundle.js +48939 -50318
  29. data/exe/aarch64-linux/package/lib/utilsBundle.js.LICENSE +359 -525
  30. data/exe/aarch64-linux/package/lib/vite/dashboard/assets/codeMirrorModule--QdMvsKi.css +1 -0
  31. data/exe/aarch64-linux/package/lib/vite/dashboard/assets/codeMirrorModule-CQ8RZGBm.js +32 -0
  32. data/exe/aarch64-linux/package/lib/vite/dashboard/assets/index-AwgwcYie.css +1 -0
  33. data/exe/aarch64-linux/package/lib/vite/dashboard/assets/index-hRvO4yU2.js +12 -0
  34. data/exe/aarch64-linux/package/lib/vite/dashboard/index.html +2 -2
  35. data/exe/aarch64-linux/package/lib/vite/htmlReport/report.css +2 -1
  36. data/exe/aarch64-linux/package/lib/vite/htmlReport/report.js +15 -55
  37. data/exe/aarch64-linux/package/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
  38. data/exe/aarch64-linux/package/lib/vite/recorder/assets/codeMirrorModule-CVQWJZAA.js +32 -0
  39. data/exe/aarch64-linux/package/lib/vite/recorder/assets/index-BZpYJZ-P.css +1 -0
  40. data/exe/aarch64-linux/package/lib/vite/recorder/assets/index-hrlLqLtq.js +129 -0
  41. data/exe/aarch64-linux/package/lib/vite/recorder/index.html +2 -2
  42. data/exe/aarch64-linux/package/lib/vite/traceViewer/assets/codeMirrorModule-BbkfBe3n.js +32 -0
  43. data/exe/aarch64-linux/package/lib/vite/traceViewer/assets/defaultSettingsView-Ds6CBOo0.js +182 -0
  44. data/exe/aarch64-linux/package/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
  45. data/exe/aarch64-linux/package/lib/vite/traceViewer/assets/xtermModule-DywYcAf8.js +7 -0
  46. data/exe/aarch64-linux/package/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
  47. data/exe/aarch64-linux/package/lib/vite/traceViewer/defaultSettingsView.Bqk9acqE.css +1 -0
  48. data/exe/aarch64-linux/package/lib/vite/traceViewer/index.B4cLoZK3.js +1 -0
  49. data/exe/aarch64-linux/package/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
  50. data/exe/aarch64-linux/package/lib/vite/traceViewer/index.html +5 -5
  51. data/exe/aarch64-linux/package/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
  52. data/exe/aarch64-linux/package/lib/vite/traceViewer/snapshot.html +2 -2
  53. data/exe/aarch64-linux/package/lib/vite/traceViewer/sw.bundle.js +3 -4
  54. data/exe/aarch64-linux/package/lib/vite/traceViewer/uiMode.CU5KtEkS.js +5 -0
  55. data/exe/aarch64-linux/package/lib/vite/traceViewer/uiMode.CyMfwkXJ.css +1 -0
  56. data/exe/aarch64-linux/package/lib/vite/traceViewer/uiMode.html +5 -5
  57. data/exe/aarch64-linux/package/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
  58. data/exe/aarch64-linux/package/lib/webp_codec.LICENSE +173 -0
  59. data/exe/aarch64-linux/package/lib/webp_codec.wasm +0 -0
  60. data/exe/aarch64-linux/package/lib/xdg-open +338 -137
  61. data/exe/aarch64-linux/package/package.json +2 -2
  62. data/exe/aarch64-linux/package/types/protocol.d.ts +446 -430
  63. data/exe/aarch64-linux/package/types/structs.d.ts +8 -1
  64. data/exe/aarch64-linux/package/types/types.d.ts +2627 -440
  65. data/lib/venetian/executable.rb +6 -2
  66. data/lib/venetian/upstream.rb +35 -18
  67. data/lib/venetian/version.rb +2 -2
  68. metadata +45 -39
  69. data/exe/aarch64-linux/package/api.json +0 -1
  70. data/exe/aarch64-linux/package/lib/server/deviceDescriptorsSource.json +0 -2739
  71. data/exe/aarch64-linux/package/lib/tools/cli-client/skill/references/test-generation.md +0 -134
  72. data/exe/aarch64-linux/package/lib/vite/dashboard/assets/index-BY2S1tHT.css +0 -1
  73. data/exe/aarch64-linux/package/lib/vite/dashboard/assets/index-C_5TMfeg.js +0 -52
  74. data/exe/aarch64-linux/package/lib/vite/recorder/assets/codeMirrorModule-DYBRYzYX.css +0 -1
  75. data/exe/aarch64-linux/package/lib/vite/recorder/assets/codeMirrorModule-DeBYQozu.js +0 -32
  76. data/exe/aarch64-linux/package/lib/vite/recorder/assets/index-4ZiSSCmn.css +0 -1
  77. data/exe/aarch64-linux/package/lib/vite/recorder/assets/index-Bq-mQf8S.js +0 -193
  78. data/exe/aarch64-linux/package/lib/vite/traceViewer/assets/codeMirrorModule-LEHpjmcn.js +0 -32
  79. data/exe/aarch64-linux/package/lib/vite/traceViewer/assets/defaultSettingsView-BNmKHKpQ.js +0 -264
  80. data/exe/aarch64-linux/package/lib/vite/traceViewer/assets/urlMatch-BYQrIQwR.js +0 -1
  81. data/exe/aarch64-linux/package/lib/vite/traceViewer/assets/xtermModule-CsJ4vdCR.js +0 -9
  82. data/exe/aarch64-linux/package/lib/vite/traceViewer/codeMirrorModule.DYBRYzYX.css +0 -1
  83. data/exe/aarch64-linux/package/lib/vite/traceViewer/defaultSettingsView.CjdS-WJx.css +0 -1
  84. data/exe/aarch64-linux/package/lib/vite/traceViewer/index.CzXZzn5A.css +0 -1
  85. data/exe/aarch64-linux/package/lib/vite/traceViewer/index.DMMX1gXU.js +0 -2
  86. data/exe/aarch64-linux/package/lib/vite/traceViewer/snapshot.v8KI4P3m.js +0 -2
  87. data/exe/aarch64-linux/package/lib/vite/traceViewer/uiMode.BZQ54Kgt.css +0 -1
  88. data/exe/aarch64-linux/package/lib/vite/traceViewer/uiMode.Ut8wwJNp.js +0 -6
  89. data/exe/aarch64-linux/package/lib/vite/traceViewer/xtermModule.DYP7pi_n.css +0 -32
  90. data/exe/aarch64-linux/package/protocol.yml +0 -4991
  91. /data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/references/element-attributes.md +0 -0
  92. /data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/references/playwright-tests.md +0 -0
  93. /data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/references/request-mocking.md +0 -0
  94. /data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/references/running-code.md +0 -0
  95. /data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/references/session-management.md +0 -0
  96. /data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/references/storage-state.md +0 -0
  97. /data/exe/aarch64-linux/package/lib/tools/{cli-client/skill → skills/playwright-cli}/references/video-recording.md +0 -0
@@ -0,0 +1,69 @@
1
+ # React setup
2
+
3
+ Follow the setup workflow in `SKILL.md`. Implement the gallery per `references/gallery-spec.md` (which has a React worked example); this page covers React-specific details.
4
+
5
+ ## Files
6
+
7
+ - `playwright/gallery/` — the gallery you implement to `references/gallery-spec.md` (an `index.html` + a `main.tsx` module). Requires `react` and `react-dom` 18+ (`createRoot`).
8
+ - Stories: `src/**/*.story.tsx` (the glob also picks up `.story.jsx`); example in `templates/react/Button.story.tsx`.
9
+
10
+ ## StrictMode
11
+
12
+ Wrap the rendered story in `<React.StrictMode>` in your gallery to match how most apps render. In development builds StrictMode intentionally double-invokes render functions and effects. This matters for stories that record events with counters set in effects — recording via state updates from event handlers (like the `CountsClicks` example story) is unaffected. If a story misbehaves under StrictMode, that is usually a real finding about the component; drop the wrapper only if the app itself does not use StrictMode.
13
+
14
+ ## Global providers
15
+
16
+ If components require context (theme, store, i18n, router), create one shared decorator and use it in stories, so each story states its scenario and nothing more:
17
+
18
+ ```tsx
19
+ // src/stories/decorators.tsx
20
+ import { ThemeProvider } from '../theme';
21
+ import { MemoryRouter } from 'react-router-dom';
22
+
23
+ export function AppScaffold({ children, route = '/' }: { children: React.ReactNode, route?: string }) {
24
+ return (
25
+ <ThemeProvider theme="light">
26
+ <MemoryRouter initialEntries={[route]}>{children}</MemoryRouter>
27
+ </ThemeProvider>
28
+ );
29
+ }
30
+ ```
31
+
32
+ ```tsx
33
+ // src/components/ProfilePage.story.tsx
34
+ export const LoggedIn = () => (
35
+ <AppScaffold route="/profile/42">
36
+ <ProfilePage user={{ id: 42, name: 'Test User' }} />
37
+ </AppScaffold>
38
+ );
39
+ ```
40
+
41
+ Do not build the decorator into the gallery — keeping it in story files makes the wrapping visible and lets stories opt out.
42
+
43
+ ## Typed props
44
+
45
+ `mount` is generic over the story: pass the story type as a template argument to type-check per-test props (and `update()`). Props are inferred from the component signature; function and class components both work.
46
+
47
+ ```tsx
48
+ // src/components/Button.story.tsx
49
+ export const WithTitle = ({ title = 'Default' }: { title?: string }) =>
50
+ <Button title={title} />;
51
+ ```
52
+
53
+ ```ts
54
+ // src/components/button.spec.ts
55
+ import type { WithTitle } from './Button.story';
56
+
57
+ const component = await mount<typeof WithTitle>('components/Button/WithTitle', { title: 'Hello' });
58
+ ```
59
+
60
+ Alternatively, generate gallery types so the id itself is typed and no type import is needed: `mount('acme-ui/components/Button/WithTitle', { title: 'Hello' })` — see `references/typing.md`.
61
+
62
+ ## CSS
63
+
64
+ - Global stylesheets: import them in your gallery entry (`playwright/gallery/main.tsx`, e.g. `import '../../src/index.css'`), mirroring the app's own entry point.
65
+ - Tailwind: if content scanning is path-based, make sure `*.story.tsx` files are covered.
66
+
67
+ ## Data fetching
68
+
69
+ For libraries with client objects (React Query, Apollo), create the client inside the story or decorator so each navigation starts fresh.
@@ -0,0 +1,173 @@
1
+ # Typing `mount()`
2
+
3
+ `mount(storyId, props?)` accepts any string id and any serializable props. Two optional layers
4
+ add type checking on top; both are supported and can be mixed in one project.
5
+
6
+ | | Explicit story type | Gallery types |
7
+ |---|---|---|
8
+ | Call | `mount<typeof WithTitle>('components/Button/WithTitle', { title })` | `mount('acme-ui/components/Button/WithTitle', { title })` |
9
+ | Checks | props and `update()` | props, `update()`, and the id itself (autocomplete, rename safety) |
10
+ | Needs | `import type { WithTitle } from './Button.story'` in the spec | a generated `stories.d.ts` kept in sync by a gallery plugin |
11
+ | Id grammar | any suffix the gallery resolves | full id, prefixed with the package name |
12
+
13
+ ## Explicit story type
14
+
15
+ Pass the story type as a template argument. Nothing to set up; works in every project.
16
+
17
+ ```ts
18
+ import type { WithTitle } from './Button.story';
19
+
20
+ const component = await mount<typeof WithTitle>('components/Button/WithTitle', { title: 'Hello' });
21
+ await component.update({ title: 'Again' });
22
+ ```
23
+
24
+ Use `import type` so the story (and with it React/Vue and CSS imports) is never loaded into the
25
+ Node test process. Function components, class components and `defineComponent` stories all infer
26
+ their props; see the `Typed props` sections in `react.md` / `vue.md` for framework details.
27
+
28
+ ## Gallery types
29
+
30
+ `@playwright/test` exports an empty `interface Stories {}`. When a story id is a key of `Stories`,
31
+ `mount` types the props from that entry; any other string keeps untyped props, so adoption can be
32
+ partial. A tiny Vite plugin next to the gallery generates `stories.d.ts`, which fills `Stories` in
33
+ via module augmentation:
34
+
35
+ ```ts
36
+ // playwright/gallery/stories.d.ts (generated)
37
+ type StoriesOf<Prefix extends string, Mod> = { [K in keyof Mod & string as `${Prefix}/${K}`]: Mod[K] };
38
+
39
+ declare module '@playwright/test' {
40
+ interface Stories extends
41
+ StoriesOf<'acme-ui/components/Button', typeof import('../../src/components/Button.story')>,
42
+ StoriesOf<'acme-ui/components/Expandable', typeof import('../../src/components/Expandable.story')> {}
43
+ }
44
+
45
+ export {};
46
+ ```
47
+
48
+ One line per story file; export names and prop types come from the story module itself, so the
49
+ file only changes when a story file is added, removed or moved. Specs then need no type imports:
50
+
51
+ ```ts
52
+ const component = await mount('acme-ui/components/Button/WithTitle', { title: 'Hello' });
53
+ // ^ autocompletes registered ids ^ checked against WithTitle's props
54
+ ```
55
+
56
+ ### Namespace ids with the package name
57
+
58
+ `Stories` is merged per TypeScript program. In a monorepo whose packages share one `tsconfig`,
59
+ two packages both registering `components/Button/Default` with different props fail with
60
+ `TS2320: Interface 'Stories' cannot simultaneously extend types ...` at the `Stories` declaration,
61
+ and even distinct ids leak into each other's autocomplete. Prefix every id with the package name,
62
+ `<package>/<path under src>/<Export>`, from the start, so the convention holds when a project
63
+ becomes a package. Read the name from `package.json` in both places that derive ids, so they
64
+ cannot drift:
65
+
66
+ ```ts
67
+ // playwright/gallery/main.tsx
68
+ import packageJSON from '../../package.json';
69
+
70
+ const id = (f: string) => packageJSON.name + '/' + f.replace(/^(\.\.\/)+src\//, '').replace(/\.story\.\w+$/, '');
71
+ ```
72
+
73
+ Suffix resolution keeps working at runtime, so `mount('Button/Primary')` still renders; only the
74
+ full prefixed id is typed.
75
+
76
+ ### The plugin
77
+
78
+ Framework-agnostic: it only lists story files. Adjust `storyFile` to match the gallery's glob.
79
+
80
+ ```ts
81
+ // playwright/gallery/storyTypes.ts
82
+ import fs from 'fs';
83
+ import path from 'path';
84
+ import type { Plugin } from 'vite';
85
+
86
+ const storyFile = /\.story\.(tsx|jsx)$/;
87
+
88
+ export function storyTypes(options: { prefix: string, src: string, outFile: string }): Plugin {
89
+ const generate = () => {
90
+ const content = render(listStoryFiles(options.src), options);
91
+ if (fs.existsSync(options.outFile) && fs.readFileSync(options.outFile, 'utf8') === content)
92
+ return;
93
+ fs.writeFileSync(options.outFile, content);
94
+ };
95
+ return {
96
+ name: 'story-types',
97
+ buildStart() {
98
+ this.addWatchFile(options.src);
99
+ generate();
100
+ },
101
+ configureServer(server) {
102
+ const onFile = (file: string) => {
103
+ if (storyFile.test(file))
104
+ generate();
105
+ };
106
+ server.watcher.on('add', onFile);
107
+ server.watcher.on('unlink', onFile);
108
+ },
109
+ };
110
+ }
111
+
112
+ function listStoryFiles(dir: string): string[] {
113
+ const result: string[] = [];
114
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
115
+ const file = path.join(dir, entry.name);
116
+ if (entry.isDirectory())
117
+ result.push(...listStoryFiles(file));
118
+ else if (storyFile.test(entry.name))
119
+ result.push(file);
120
+ }
121
+ return result.sort();
122
+ }
123
+
124
+ function render(files: string[], { prefix, src, outFile }: { prefix: string, src: string, outFile: string }): string {
125
+ const outDir = path.dirname(outFile);
126
+ const posix = (p: string) => p.split(path.sep).join('/');
127
+ const entries = files.map(file => {
128
+ const id = prefix + '/' + posix(path.relative(src, file)).replace(storyFile, '');
129
+ const specifier = posix(path.relative(outDir, file)).replace(/\.\w+$/, '');
130
+ return ` StoriesOf<'${id}', typeof import('${specifier.startsWith('.') ? specifier : './' + specifier}')>`;
131
+ });
132
+ const stories = entries.length ? `interface Stories extends\n${entries.join(',\n')} {}` : 'interface Stories {}';
133
+ return `// Generated by storyTypes.ts, do not edit.
134
+
135
+ type StoriesOf<Prefix extends string, Mod> = { [K in keyof Mod & string as \`\${Prefix}/\${K}\`]: Mod[K] };
136
+
137
+ declare module '@playwright/test' {
138
+ ${stories}
139
+ }
140
+
141
+ export {};
142
+ `;
143
+ }
144
+ ```
145
+
146
+ Register it on whichever Vite server serves the gallery (the app's `vite.config.ts`, or the
147
+ standalone `playwright/vite.config.ts`):
148
+
149
+ ```ts
150
+ import packageJSON from './package.json';
151
+ import { storyTypes } from './playwright/gallery/storyTypes';
152
+
153
+ export default defineConfig({
154
+ plugins: [
155
+ react(),
156
+ storyTypes({
157
+ prefix: packageJSON.name,
158
+ src: path.resolve(__dirname, 'src'),
159
+ outFile: path.resolve(__dirname, 'playwright/gallery/stories.d.ts'),
160
+ }),
161
+ ],
162
+ });
163
+ ```
164
+
165
+ The file is regenerated on every dev-server start and build, and while the server runs, whenever
166
+ a story file appears or disappears. Its content is deterministic, so **commit it**: type-checking
167
+ in CI or an editor must not depend on a running dev server. Nothing imports the file, so list it
168
+ explicitly in the project's `tsconfig` (`"files": ["playwright/gallery/stories.d.ts"]`) so that
169
+ `tsc` and editors load it.
170
+
171
+ For `.story.vue` single-file components, map the `default` export to the bare path in
172
+ `StoriesOf` (`K extends 'default' ? Prefix : \`${Prefix}/${K}\``) and rely on `vue-tsc` for the
173
+ SFC's types; a story without inferable props types as `unknown` props, which accepts anything.
@@ -0,0 +1,77 @@
1
+ # Vue setup
2
+
3
+ Follow the setup workflow in `SKILL.md`. Implement the gallery per `references/gallery-spec.md`, exposing `window.mount`/`window.unmount` — in Vue, mount with `app = createApp(h(story, props)); app.mount('#root')` and unmount with `app.unmount()`; this page covers Vue-specific details.
4
+
5
+ ## Files
6
+
7
+ - `playwright/gallery/` — the gallery you implement to `references/gallery-spec.md` (an `index.html` + a `main.ts` module). Requires Vue 3.
8
+ - Stories: `src/**/*.story.{ts,js,vue}`; example in `templates/vue/Button.story.ts`.
9
+
10
+ ## Two ways to write stories
11
+
12
+ **Render-function stories** (`Button.story.ts`) — several scenarios per file, one named export each; see `templates/vue/Button.story.ts`. Uses `defineComponent` + `h()`, no SFC compilation involved.
13
+
14
+ **Single-file-component stories** (`Button.primary.story.vue`) — one story per file, full template syntax:
15
+
16
+ ```vue
17
+ <script setup lang="ts">
18
+ import { ref } from 'vue';
19
+ import Button from './Button.vue';
20
+ const clicks = ref(0);
21
+ </script>
22
+
23
+ <template>
24
+ <Button title="Submit" @click="clicks++" />
25
+ <form hidden><input data-testid="click-count" readonly :value="String(clicks)" /></form>
26
+ </template>
27
+ ```
28
+
29
+ An SFC story is addressed by its path without the extension: `mount('components/Button.primary')`. Prefer SFC stories when the scenario needs slots or non-trivial templates.
30
+
31
+ ## Global plugins
32
+
33
+ Apps that rely on plugins (Pinia, vue-router, i18n) should wrap components with a decorator story helper that creates a fresh instance per story:
34
+
35
+ ```ts
36
+ // src/stories/decorators.ts
37
+ import { defineComponent, h, type Component } from 'vue';
38
+ import { createPinia } from 'pinia';
39
+
40
+ export function withStore(story: Component) {
41
+ return defineComponent(() => {
42
+ const pinia = createPinia();
43
+ return () => h(story, { pinia });
44
+ });
45
+ }
46
+ ```
47
+
48
+ For plugins that must be installed on the app instance (`app.use(...)`), add them in your gallery right after `createApp(...)` — that is the equivalent of the app's own bootstrap.
49
+
50
+ ## Typed props
51
+
52
+ A story that takes per-test props declares them twice: in the setup signature (for the type) and in the `props` option (so Vue delivers them as props rather than `attrs`):
53
+
54
+ ```ts
55
+ // src/components/Button.story.ts
56
+ export const WithTitle = defineComponent(
57
+ (props: { title?: string }) => () => h(Button, { title: props.title ?? 'Default' }),
58
+ { props: ['title'] },
59
+ );
60
+ ```
61
+
62
+ `mount` is generic over the story: pass the story type as a template argument to type-check the props (and `update()`):
63
+
64
+ ```ts
65
+ // src/components/button.spec.ts
66
+ import type { WithTitle } from './Button.story';
67
+
68
+ const component = await mount<typeof WithTitle>('components/Button/WithTitle', { title: 'Hello' });
69
+ ```
70
+
71
+ Alternatively, generate gallery types so the id itself is typed and no type import is needed: `mount('acme-ui/components/Button/WithTitle', { title: 'Hello' })` — see `references/typing.md`.
72
+
73
+ Options-API stories (`defineComponent({ props: { ... } })`) infer props the same way. For `.story.vue` SFC stories, prop types are only inferable when the setup generates SFC types (Volar/vue-tsc); otherwise pass the props type directly: `mount<{ title?: string }>('components/Button.primary', { title: 'Hello' })`.
74
+
75
+ ## CSS
76
+
77
+ Import global stylesheets in your gallery entry (`playwright/gallery/main.ts`, e.g. `import '../../src/assets/main.css'`), mirroring the app's entry point.
@@ -55,12 +55,12 @@ npx playwright trace actions --errors-only
55
55
  npx playwright trace action <action-id>
56
56
  ```
57
57
 
58
- The `action` command displays available snapshot phases (before, input, after) and the exact command to extract them.
58
+ The `action` command displays available snapshot phases (before, action, after) and the exact command to extract them.
59
59
 
60
60
  ### Requests
61
61
 
62
62
  ```bash
63
- # All network requests: method, status, URL, duration, size
63
+ # All network requests: start time (on the `trace actions` clock), method, status, URL, duration, size
64
64
  npx playwright trace requests
65
65
 
66
66
  # Filter by URL pattern
@@ -94,6 +94,9 @@ npx playwright trace console --browser
94
94
 
95
95
  # Only stdout/stderr (no browser console)
96
96
  npx playwright trace console --stdio
97
+
98
+ # Filter by message text pattern
99
+ npx playwright trace console --grep "failed to fetch"
97
100
  ```
98
101
 
99
102
  ### Errors
@@ -112,7 +115,7 @@ The `snapshot` command loads the DOM snapshot for an action into a headless brow
112
115
  npx playwright trace snapshot <action-id>
113
116
 
114
117
  # Use a specific phase
115
- npx playwright trace snapshot <action-id> --name before
118
+ npx playwright trace snapshot <action-id> --phase before
116
119
 
117
120
  # Run eval to query the DOM
118
121
  npx playwright trace snapshot <action-id> -- eval "document.title"
@@ -28,6 +28,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var extension_exports = {};
30
30
  __export(extension_exports, {
31
+ findPlaywrightExtensionProfile: () => findPlaywrightExtensionProfile,
32
+ isExtensionInstalledInProfile: () => isExtensionInstalledInProfile,
31
33
  isPlaywrightExtensionInstalled: () => isPlaywrightExtensionInstalled,
32
34
  playwrightExtensionId: () => playwrightExtensionId,
33
35
  playwrightExtensionInstallUrl: () => playwrightExtensionInstallUrl
@@ -37,30 +39,60 @@ var import_fs = __toESM(require("fs"));
37
39
  var import_path = __toESM(require("path"));
38
40
  const playwrightExtensionId = "mmlmfjhmonkocbjadbfplnigmagldckm";
39
41
  const playwrightExtensionInstallUrl = `https://chromewebstore.google.com/detail/playwright-extension/${playwrightExtensionId}`;
40
- async function isPlaywrightExtensionInstalled(userDataDir) {
42
+ async function findPlaywrightExtensionProfile(userDataDir) {
43
+ const profiles = await listProfileDirectories(userDataDir);
44
+ const lastUsed = await readLastUsedProfile(userDataDir);
45
+ const ordered = lastUsed && profiles.includes(lastUsed) ? [lastUsed, ...profiles.filter((profile) => profile !== lastUsed)] : profiles;
46
+ for (const profile of ordered) {
47
+ if (await isExtensionInstalledInProfile(import_path.default.join(userDataDir, profile)))
48
+ return profile;
49
+ }
50
+ return void 0;
51
+ }
52
+ async function listProfileDirectories(userDataDir) {
41
53
  let entries;
42
54
  try {
43
55
  entries = await import_fs.default.promises.readdir(userDataDir);
44
56
  } catch {
45
- return false;
57
+ return [];
46
58
  }
47
- for (const entry of entries) {
48
- if (entry !== "Default" && !entry.startsWith("Profile "))
49
- continue;
50
- if (await isExtensionInstalledInProfile(import_path.default.join(userDataDir, entry)))
51
- return true;
59
+ const profiles = entries.filter((entry) => entry === "Default" || /^Profile \d+$/.test(entry));
60
+ profiles.sort((a, b) => profileRank(a) - profileRank(b));
61
+ return profiles;
62
+ }
63
+ function profileRank(profile) {
64
+ return profile === "Default" ? -1 : parseInt(profile.slice("Profile ".length), 10);
65
+ }
66
+ async function readLastUsedProfile(userDataDir) {
67
+ try {
68
+ const localState = JSON.parse(await import_fs.default.promises.readFile(import_path.default.join(userDataDir, "Local State"), "utf-8"));
69
+ const lastUsed = localState?.profile?.last_used;
70
+ return typeof lastUsed === "string" ? lastUsed : void 0;
71
+ } catch {
72
+ return void 0;
52
73
  }
53
- return false;
74
+ }
75
+ async function isPlaywrightExtensionInstalled(userDataDir) {
76
+ return await findPlaywrightExtensionProfile(userDataDir) !== void 0;
54
77
  }
55
78
  async function isExtensionInstalledInProfile(profileDir) {
56
79
  if (await pathExists(import_path.default.join(profileDir, "Extensions", playwrightExtensionId)))
57
80
  return true;
81
+ for (const fileName of ["Preferences", "Secure Preferences"]) {
82
+ if (await hasExtensionSettingsRecord(import_path.default.join(profileDir, fileName)))
83
+ return true;
84
+ }
85
+ return false;
86
+ }
87
+ async function hasExtensionSettingsRecord(prefsPath) {
88
+ let prefs;
58
89
  try {
59
- const prefs = await import_fs.default.promises.readFile(import_path.default.join(profileDir, "Preferences"), "utf-8");
60
- return prefs.includes(`"${playwrightExtensionId}"`);
90
+ prefs = JSON.parse(await import_fs.default.promises.readFile(prefsPath, "utf-8"));
61
91
  } catch {
62
92
  return false;
63
93
  }
94
+ const record = prefs?.extensions?.settings?.[playwrightExtensionId];
95
+ return !!record && typeof record === "object" && Object.keys(record).length > 0;
64
96
  }
65
97
  async function pathExists(p) {
66
98
  try {
@@ -72,6 +104,8 @@ async function pathExists(p) {
72
104
  }
73
105
  // Annotate the CommonJS export names for ESM import in node:
74
106
  0 && (module.exports = {
107
+ findPlaywrightExtensionProfile,
108
+ isExtensionInstalledInProfile,
75
109
  isPlaywrightExtensionInstalled,
76
110
  playwrightExtensionId,
77
111
  playwrightExtensionInstallUrl