@trylayout/qa 0.1.0 → 0.1.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Layout QA
2
2
 
3
- Layout QA is a local browser QA protocol and runner for AI-built frontends. It runs deterministic Playwright-style flows against a local or preview URL, captures the screenshot sequence, checks browser health, and writes a static HTML report.
3
+ Layout QA is a local browser QA protocol and runner for AI-built frontends. It runs deterministic flows against a local or preview URL, captures screenshots at meaningful checkpoints, checks browser health, and writes a static HTML report.
4
4
 
5
5
  The core loop is intentionally local:
6
6
 
@@ -9,16 +9,31 @@ npx @trylayout/qa init
9
9
  npx @trylayout/qa run --target-url http://localhost:5173 --scenario happy_path --open
10
10
  ```
11
11
 
12
- ## Why this exists
12
+ No account, upload, hosted service, or external docs are required.
13
+
14
+ Package names:
15
+
16
+ - Canonical npm package: `@trylayout/qa`
17
+ - Convenience npm alias: `layout-qa`
18
+ - CLI binaries: `trylayout` and `layout-qa`
19
+
20
+ These commands are equivalent:
21
+
22
+ ```bash
23
+ npx @trylayout/qa run --target-url http://localhost:5173 --scenario happy_path --open
24
+ npx layout-qa run --target-url http://localhost:5173 --scenario happy_path --open
25
+ ```
26
+
27
+ ## Why This Exists
13
28
 
14
29
  Frontend agents can move faster when they have a visual feedback loop they can run themselves. Layout gives the agent a small protocol:
15
30
 
16
- - Wire app mocks behind a local env flag such as `VITE_LAYOUT_QA_MOCKS=1`.
17
- - Keep deterministic API/auth scenarios in the app repo.
31
+ - Wire deterministic API/auth mocks behind a local env flag such as `VITE_LAYOUT_QA_MOCKS=1`.
32
+ - Switch mock states with `localStorage["layout.qa.scenario"]`.
18
33
  - Declare high-value browser flows in `.layout/qa-flows.json`.
19
34
  - Run the CLI locally and inspect the generated screenshots/report.
20
35
 
21
- Layout does not require uploading screenshots or source code. Hosted reports, PR comments, and AI review notes can be layered on later.
36
+ The goal is not to replace Playwright. The goal is to make the browser QA loop simple enough for a coding agent to set up, run, and iterate on while building a frontend branch.
22
37
 
23
38
  ## Install
24
39
 
@@ -28,6 +43,12 @@ Use it directly with `npx`:
28
43
  npx @trylayout/qa run --target-url http://localhost:5173
29
44
  ```
30
45
 
46
+ The package is also available under the unscoped alias `layout-qa` for agents and tools that infer the package name from this repository:
47
+
48
+ ```bash
49
+ npx layout-qa run --target-url http://localhost:5173
50
+ ```
51
+
31
52
  Or install it in a project:
32
53
 
33
54
  ```bash
@@ -35,21 +56,27 @@ npm install --save-dev @trylayout/qa
35
56
  npx trylayout run --target-url http://localhost:5173
36
57
  ```
37
58
 
38
- The package uses Playwright. If your environment does not already have the browser binaries, run:
59
+ The package uses Playwright. If your environment does not already have Chromium installed for Playwright, run:
39
60
 
40
61
  ```bash
41
62
  npx playwright install chromium
42
63
  ```
43
64
 
44
- ## Commands
65
+ ## Quick Start
45
66
 
46
- Initialize a starter flow file:
67
+ Create a starter flow manifest:
47
68
 
48
69
  ```bash
49
70
  npx @trylayout/qa init
50
71
  ```
51
72
 
52
- Run a flow:
73
+ Start your app with whatever mock flag your project uses:
74
+
75
+ ```bash
76
+ VITE_LAYOUT_QA_MOCKS=1 npm run dev
77
+ ```
78
+
79
+ Run a scenario:
53
80
 
54
81
  ```bash
55
82
  npx @trylayout/qa run \
@@ -58,19 +85,6 @@ npx @trylayout/qa run \
58
85
  --open
59
86
  ```
60
87
 
61
- Useful options:
62
-
63
- ```text
64
- --target-url <url> URL of the running frontend to test.
65
- --scenario <name> Mock scenario to activate. Defaults to happy_path.
66
- --flows <path> Flow manifest path. Defaults to .layout/qa-flows.json.
67
- --out <path> Artifact directory. Defaults to .layout/runs.
68
- --timeout <ms> Browser run timeout. Defaults to 60000.
69
- --headed Show the browser instead of running headless.
70
- --open Open the generated local HTML report after the run.
71
- --json Print machine-readable JSON.
72
- ```
73
-
74
88
  Each run writes:
75
89
 
76
90
  ```text
@@ -84,14 +98,34 @@ Each run writes:
84
98
 
85
99
  The process exits `0` on pass and `1` on failure, so the same command can run in CI.
86
100
 
101
+ ## Commands
102
+
103
+ ```text
104
+ trylayout init [options]
105
+ trylayout run --target-url <url> [options]
106
+ layout-qa run --target-url <url> [options]
107
+ ```
108
+
109
+ Options:
110
+
111
+ ```text
112
+ --target-url <url> URL of the running frontend to test.
113
+ --scenario <name> Mock scenario to activate. Defaults to happy_path.
114
+ --flows <path> Flow manifest path. Defaults to .layout/qa-flows.json.
115
+ --out <path> Artifact directory. Defaults to .layout/runs.
116
+ --timeout <ms> Browser run timeout. Defaults to 60000.
117
+ --headed Show the browser instead of running headless.
118
+ --open Open the generated local HTML report after the run.
119
+ --json Print machine-readable JSON.
120
+ --force Overwrite an existing flow file during init.
121
+ ```
122
+
87
123
  ## Flow Manifest
88
124
 
89
125
  Default path: `.layout/qa-flows.json`.
90
126
 
91
127
  ```json
92
128
  {
93
- "$schema": "https://trylayout.com/schemas/qa-flows.v1.json",
94
- "docsUrl": "https://trylayout.com/docs/qa",
95
129
  "schemaVersion": 1,
96
130
  "flows": [
97
131
  {
@@ -105,6 +139,12 @@ Default path: `.layout/qa-flows.json`.
105
139
  "type": "assert_visible_text",
106
140
  "text": "Dashboard",
107
141
  "screenshot": true
142
+ },
143
+ {
144
+ "id": "open_settings",
145
+ "type": "click",
146
+ "text": "Settings",
147
+ "screenshot": true
108
148
  }
109
149
  ]
110
150
  }
@@ -112,6 +152,27 @@ Default path: `.layout/qa-flows.json`.
112
152
  }
113
153
  ```
114
154
 
155
+ Top-level fields:
156
+
157
+ - `schemaVersion`: currently `1`.
158
+ - `flows`: array of flow definitions.
159
+
160
+ Flow fields:
161
+
162
+ - `id`: stable machine-readable flow id.
163
+ - `name`: human-readable report title.
164
+ - `startUrl`: path or absolute URL where the flow starts.
165
+ - `scenarios`: scenario names this flow can run against. Use an empty array to allow all scenarios.
166
+ - `steps`: ordered browser steps.
167
+
168
+ Step fields:
169
+
170
+ - `id`: stable machine-readable step id.
171
+ - `type`: step type.
172
+ - `label`: optional human-readable report label.
173
+ - `screenshot`: set `true` to capture a screenshot after the step.
174
+ - `timeoutMs`: optional per-step timeout.
175
+
115
176
  Supported step types:
116
177
 
117
178
  - `goto`: navigate to `url`.
@@ -122,14 +183,36 @@ Supported step types:
122
183
  - `assert_url`: require current URL to equal `url` or contain `contains`.
123
184
  - `screenshot`: capture a screenshot checkpoint.
124
185
 
125
- The runner sets these before the app loads:
186
+ Examples:
187
+
188
+ ```json
189
+ { "id": "open_settings", "type": "click", "text": "Settings" }
190
+ ```
191
+
192
+ ```json
193
+ { "id": "email", "type": "fill", "selector": "input[name='email']", "value": "layout@example.com" }
194
+ ```
195
+
196
+ ```json
197
+ { "id": "settings_url", "type": "assert_url", "contains": "/settings" }
198
+ ```
199
+
200
+ ## Mock Scenarios
201
+
202
+ Before the app loads, the runner sets:
126
203
 
127
204
  ```js
128
205
  localStorage.setItem("layout.qa.scenario", "<scenario>");
129
206
  sessionStorage.setItem("layout.qa.runner", "1");
130
207
  ```
131
208
 
132
- Your app can use `layout.qa.scenario` to switch deterministic mock states. The `layout.qa.runner` flag is useful for hiding local-only QA switchers from screenshots.
209
+ Your app can use `layout.qa.scenario` to switch deterministic mock states:
210
+
211
+ - `happy_path`: normal populated data.
212
+ - `empty`: successful responses with empty states.
213
+ - `error`: failed or error responses that should render recovery UI.
214
+
215
+ The `layout.qa.runner` flag is useful for hiding local-only QA switchers from screenshots.
133
216
 
134
217
  ## Agent Setup Prompt
135
218
 
@@ -138,24 +221,68 @@ Paste this into your coding agent inside the frontend repo:
138
221
  ```text
139
222
  Set up Layout QA for this web app.
140
223
 
141
- Docs: https://trylayout.com/docs/qa
142
- Flow schema: https://trylayout.com/schemas/qa-flows.v1.json
143
-
144
- Add deterministic mock API/auth states behind a local-only env flag such as VITE_LAYOUT_QA_MOCKS=1. Use the scenario key localStorage["layout.qa.scenario"] with at least happy_path, empty, and error states. Keep mocks inside the app test/dev setup; do not add a standalone mock server.
145
-
146
- Add .layout/qa-flows.json with one smoke flow for the highest-value page and screenshot checkpoints after meaningful user-visible states. Prefer visible text and stable selectors. Hide any local QA scenario switcher when sessionStorage["layout.qa.runner"] === "1".
147
-
148
- Then run:
224
+ Goal:
225
+ Create a local-only browser QA loop that an agent can run while changing frontend code.
226
+
227
+ Rules:
228
+ - Do not add a standalone mock server.
229
+ - Do not require a hosted Layout service.
230
+ - Keep all mock data local to this app.
231
+ - Gate mocks behind a local-only env flag such as VITE_LAYOUT_QA_MOCKS=1, NEXT_PUBLIC_LAYOUT_QA_MOCKS=1, or the framework-appropriate equivalent.
232
+ - Use localStorage["layout.qa.scenario"] to select at least happy_path, empty, and error mock states.
233
+ - Hide any local QA switcher or debug controls when sessionStorage["layout.qa.runner"] === "1".
234
+
235
+ Implementation:
236
+ - Add deterministic API fixtures for the highest-value frontend route.
237
+ - If the app has a central auth/session abstraction, add a deterministic mock user only when the Layout QA env flag is enabled.
238
+ - If auth is scattered or provider-SDK-only, leave a clear note in the PR/code comments and start with public or logged-out flows.
239
+ - Add .layout/qa-flows.json with one smoke flow for the most important page.
240
+ - Prefer visible text and stable selectors.
241
+ - Add screenshot checkpoints after meaningful user-visible states.
242
+
243
+ Run:
149
244
  npx @trylayout/qa run --target-url <local app url> --scenario happy_path --open
245
+ npx @trylayout/qa run --target-url <local app url> --scenario empty --open
246
+ npx @trylayout/qa run --target-url <local app url> --scenario error --open
150
247
  ```
151
248
 
152
- ## npm Publishing
249
+ ## CI Example
250
+
251
+ ```yaml
252
+ name: Layout QA
253
+
254
+ on:
255
+ pull_request:
256
+
257
+ jobs:
258
+ qa:
259
+ runs-on: ubuntu-latest
260
+ steps:
261
+ - uses: actions/checkout@v4
262
+ - uses: actions/setup-node@v4
263
+ with:
264
+ node-version: 20
265
+ cache: npm
266
+ - run: npm ci
267
+ - run: npx playwright install chromium
268
+ - run: VITE_LAYOUT_QA_MOCKS=1 npm run dev -- --host 127.0.0.1 --port 5173 &
269
+ - run: npx @trylayout/qa run --target-url http://127.0.0.1:5173 --scenario happy_path
270
+ - uses: actions/upload-artifact@v4
271
+ if: always()
272
+ with:
273
+ name: layout-qa-report
274
+ path: .layout/runs
275
+ ```
153
276
 
154
- This repo is configured for a public scoped npm package:
277
+ ## Current Scope
155
278
 
156
- ```bash
157
- npm login
158
- npm publish --access public
159
- ```
279
+ This package is intentionally small:
280
+
281
+ - It does run Playwright against an already-running frontend.
282
+ - It does write local screenshots and an HTML report.
283
+ - It does support deterministic scenario switching.
284
+ - It does not build or host your app.
285
+ - It does not upload results.
286
+ - It does not perform AI review by itself.
160
287
 
161
- If the `@trylayout` npm scope does not exist yet, create it in npm first, then rerun publish from this repo.
288
+ Those hosted/reporting layers can be added later without changing the local protocol.
@@ -15,7 +15,9 @@ function printHelp() {
15
15
  Usage:
16
16
  trylayout init [options]
17
17
  trylayout run --target-url <url> [options]
18
+ layout-qa run --target-url <url> [options]
18
19
  npx @trylayout/qa run --target-url <url> [options]
20
+ npx layout-qa run --target-url <url> [options]
19
21
 
20
22
  Commands:
21
23
  init Write a starter .layout/qa-flows.json.
package/build/flows.d.ts CHANGED
@@ -2,7 +2,7 @@ import { LoadedQaFlow, QaFlowDefinition } from './types';
2
2
  export declare const DEFAULT_TEST_TIMEOUT_MS: number;
3
3
  export declare const SCREENSHOT_LIMIT_BYTES: number;
4
4
  export declare const FLOW_MANIFEST_PATH = ".layout/qa-flows.json";
5
- export declare const QA_DOCS_URL = "https://trylayout.com/docs/qa";
5
+ export declare const QA_DOCS_URL = "https://github.com/Layout-App/layout-qa#readme";
6
6
  export declare function getTestTimeoutMs(): number;
7
7
  export declare function selectFlowFromManifest(raw: unknown, scenario: string): QaFlowDefinition | null;
8
8
  export declare function parseFlowManifestContent(content: string, scenario: string): LoadedQaFlow | null;
@@ -17,8 +17,6 @@ export declare function loadFlow(input: {
17
17
  manifestFound: boolean;
18
18
  }>;
19
19
  export declare function starterFlowManifest(): {
20
- $schema: string;
21
- docsUrl: string;
22
20
  schemaVersion: number;
23
21
  flows: {
24
22
  id: string;
package/build/flows.js CHANGED
@@ -16,7 +16,7 @@ const path_1 = __importDefault(require("path"));
16
16
  exports.DEFAULT_TEST_TIMEOUT_MS = 60 * 1000;
17
17
  exports.SCREENSHOT_LIMIT_BYTES = 300 * 1024;
18
18
  exports.FLOW_MANIFEST_PATH = '.layout/qa-flows.json';
19
- exports.QA_DOCS_URL = 'https://trylayout.com/docs/qa';
19
+ exports.QA_DOCS_URL = 'https://github.com/Layout-App/layout-qa#readme';
20
20
  function getTestTimeoutMs() {
21
21
  const value = Number(process.env.LAYOUT_QA_TEST_TIMEOUT_MS);
22
22
  return Number.isFinite(value) && value > 0 ? value : exports.DEFAULT_TEST_TIMEOUT_MS;
@@ -159,8 +159,6 @@ async function loadFlow(input) {
159
159
  }
160
160
  function starterFlowManifest() {
161
161
  return {
162
- $schema: 'https://trylayout.com/schemas/qa-flows.v1.json',
163
- docsUrl: exports.QA_DOCS_URL,
164
162
  schemaVersion: 1,
165
163
  flows: [
166
164
  {
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@trylayout/qa",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Local browser QA runner and HTML reports for AI-built frontends.",
5
5
  "license": "MIT",
6
6
  "author": "Layout",
7
- "homepage": "https://trylayout.com/docs/qa",
7
+ "homepage": "https://github.com/Layout-App/layout-qa#readme",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://github.com/Layout-App/layout-qa.git"
@@ -21,6 +21,7 @@
21
21
  "ai-agents"
22
22
  ],
23
23
  "bin": {
24
+ "layout-qa": "build/cli/layoutQa.js",
24
25
  "trylayout": "build/cli/layoutQa.js"
25
26
  },
26
27
  "files": [