@hapergg/harness-comet-cli 0.1.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/bin/harness-comet.js +7 -0
- package/dist/commands/comet.d.ts +8 -0
- package/dist/commands/comet.d.ts.map +1 -0
- package/dist/commands/comet.js +500 -0
- package/dist/commands/comet.js.map +1 -0
- package/dist/commands/create.d.ts +16 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +69 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/impact.d.ts +8 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +108 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/init.d.ts +19 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +249 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/dev-bin.d.ts +2 -0
- package/dist/dev-bin.d.ts.map +1 -0
- package/dist/dev-bin.js +6 -0
- package/dist/dev-bin.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +393 -0
- package/dist/index.js.map +1 -0
- package/dist/package-info.d.ts +6 -0
- package/dist/package-info.d.ts.map +1 -0
- package/dist/package-info.js +6 -0
- package/dist/package-info.js.map +1 -0
- package/dist/templates/incident.d.ts +3 -0
- package/dist/templates/incident.d.ts.map +1 -0
- package/dist/templates/incident.js +26 -0
- package/dist/templates/incident.js.map +1 -0
- package/dist/templates/playwright-mode.d.ts +12 -0
- package/dist/templates/playwright-mode.d.ts.map +1 -0
- package/dist/templates/playwright-mode.js +225 -0
- package/dist/templates/playwright-mode.js.map +1 -0
- package/package.json +58 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
export function playwrightHarnessCometConfigTemplate(testDir = "tests") {
|
|
2
|
+
return `export default {
|
|
3
|
+
schemaVersion: 1,
|
|
4
|
+
mode: "playwright",
|
|
5
|
+
playwright: {
|
|
6
|
+
configFile: "playwright.config.ts",
|
|
7
|
+
testDir: "${testDir}",
|
|
8
|
+
testMatch: ["**/*.spec.ts"],
|
|
9
|
+
assetRoots: ["${testDir}"],
|
|
10
|
+
resultsFile: "test-results/harness-comet/results.json"
|
|
11
|
+
},
|
|
12
|
+
docs: {
|
|
13
|
+
testingDir: "docs/testing"
|
|
14
|
+
},
|
|
15
|
+
incidents: {
|
|
16
|
+
directory: "${testDir}/incidents",
|
|
17
|
+
requireIssueUrl: false,
|
|
18
|
+
requireReadme: true
|
|
19
|
+
},
|
|
20
|
+
validation: {
|
|
21
|
+
forbidOnly: true,
|
|
22
|
+
longWaitWarningMs: 5000
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
`;
|
|
26
|
+
}
|
|
27
|
+
export function playwrightConfigTemplate(testDir = "tests") {
|
|
28
|
+
return `import { defineConfig } from "@playwright/test";
|
|
29
|
+
|
|
30
|
+
export default defineConfig({
|
|
31
|
+
testDir: "${testDir}",
|
|
32
|
+
testMatch: ["**/*.spec.ts"],
|
|
33
|
+
fullyParallel: true,
|
|
34
|
+
forbidOnly: Boolean(process.env.CI),
|
|
35
|
+
retries: process.env.CI ? 2 : 0,
|
|
36
|
+
workers: process.env.CI ? 2 : undefined,
|
|
37
|
+
reporter: [["list"], ["html", { open: "never" }], ["@hapergg/harness-comet-playwright/reporter"]],
|
|
38
|
+
expect: {
|
|
39
|
+
timeout: 10_000
|
|
40
|
+
},
|
|
41
|
+
use: {
|
|
42
|
+
headless: true,
|
|
43
|
+
viewport: { width: 1440, height: 900 },
|
|
44
|
+
actionTimeout: 15_000,
|
|
45
|
+
navigationTimeout: 30_000,
|
|
46
|
+
baseURL: process.env.PLAYWRIGHT_BASE_URL ?? "http://localhost:3000",
|
|
47
|
+
trace: "on-first-retry",
|
|
48
|
+
screenshot: "only-on-failure",
|
|
49
|
+
video: "retain-on-failure"
|
|
50
|
+
},
|
|
51
|
+
projects: [
|
|
52
|
+
{
|
|
53
|
+
name: "chromium",
|
|
54
|
+
use: { browserName: "chromium" }
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
});
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
export function playwrightExampleSpecTemplate() {
|
|
61
|
+
return `import { expect, test } from "@playwright/test";
|
|
62
|
+
import input from "../data/example-input.json" with { type: "json" };
|
|
63
|
+
import expectedPayload from "../data/example-expected-payload.json" with { type: "json" };
|
|
64
|
+
import { attachJson } from "../support/attachments";
|
|
65
|
+
import { mockJson } from "../support/mock-api";
|
|
66
|
+
|
|
67
|
+
test(
|
|
68
|
+
"Example save flow",
|
|
69
|
+
{
|
|
70
|
+
tag: ["@harness", "@annotation-save"]
|
|
71
|
+
},
|
|
72
|
+
async ({ page }, testInfo) => {
|
|
73
|
+
const captured: unknown[] = [];
|
|
74
|
+
|
|
75
|
+
await mockJson(page, "**/api/bootstrap", {
|
|
76
|
+
featureFlags: { annotationSave: true }
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await page.route("**/api/annotations", async (route) => {
|
|
80
|
+
const request = route.request();
|
|
81
|
+
captured.push(JSON.parse(request.postData() ?? "{}"));
|
|
82
|
+
await route.fulfill({
|
|
83
|
+
status: 200,
|
|
84
|
+
contentType: "application/json",
|
|
85
|
+
body: JSON.stringify({ ok: true, saved: true })
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await page.setContent(\`
|
|
90
|
+
<main>
|
|
91
|
+
<h1>Annotation Editor</h1>
|
|
92
|
+
<label>
|
|
93
|
+
Label
|
|
94
|
+
<input data-testid="label" />
|
|
95
|
+
</label>
|
|
96
|
+
<label>
|
|
97
|
+
Comment
|
|
98
|
+
<textarea data-testid="comment"></textarea>
|
|
99
|
+
</label>
|
|
100
|
+
<button data-testid="save">Save</button>
|
|
101
|
+
<output data-testid="status"></output>
|
|
102
|
+
</main>
|
|
103
|
+
<script>
|
|
104
|
+
async function bootstrap() {
|
|
105
|
+
const response = await fetch('/api/bootstrap');
|
|
106
|
+
window.__bootstrap = await response.json();
|
|
107
|
+
}
|
|
108
|
+
document.querySelector('[data-testid="save"]').addEventListener('click', async () => {
|
|
109
|
+
const payload = {
|
|
110
|
+
id: "annotation-1",
|
|
111
|
+
label: document.querySelector('[data-testid="label"]').value,
|
|
112
|
+
comment: document.querySelector('[data-testid="comment"]').value
|
|
113
|
+
};
|
|
114
|
+
await fetch('/api/annotations', {
|
|
115
|
+
method: 'POST',
|
|
116
|
+
headers: { 'content-type': 'application/json' },
|
|
117
|
+
body: JSON.stringify(payload)
|
|
118
|
+
});
|
|
119
|
+
document.querySelector('[data-testid="status"]').textContent = 'Saved';
|
|
120
|
+
});
|
|
121
|
+
bootstrap();
|
|
122
|
+
</script>
|
|
123
|
+
\`);
|
|
124
|
+
|
|
125
|
+
await expect
|
|
126
|
+
.poll(() => page.evaluate(() => Boolean(window.__bootstrap?.featureFlags?.annotationSave)))
|
|
127
|
+
.toBe(true);
|
|
128
|
+
await page.getByTestId("label").fill((input as { label: string }).label);
|
|
129
|
+
await page.getByTestId("comment").fill((input as { comment: string }).comment);
|
|
130
|
+
await page.getByTestId("save").click();
|
|
131
|
+
|
|
132
|
+
await expect(page.getByTestId("status")).toHaveText("Saved");
|
|
133
|
+
expect(captured[0]).toEqual(expectedPayload);
|
|
134
|
+
await attachJson(testInfo, "captured-payload", captured[0]);
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
export function playwrightFixturesTemplate() {
|
|
140
|
+
return `export const harnessBaseUrl = process.env.PLAYWRIGHT_BASE_URL ?? "http://localhost:3000";
|
|
141
|
+
`;
|
|
142
|
+
}
|
|
143
|
+
export function playwrightMockApiTemplate() {
|
|
144
|
+
return `import type { Page } from "@playwright/test";
|
|
145
|
+
|
|
146
|
+
export async function mockJson(
|
|
147
|
+
page: Page,
|
|
148
|
+
url: string,
|
|
149
|
+
body: unknown,
|
|
150
|
+
status = 200
|
|
151
|
+
): Promise<void> {
|
|
152
|
+
await page.route(url, async (route) => {
|
|
153
|
+
await route.fulfill({
|
|
154
|
+
status,
|
|
155
|
+
contentType: "application/json",
|
|
156
|
+
body: JSON.stringify(body)
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
export function playwrightAttachmentsTemplate() {
|
|
163
|
+
return `import type { TestInfo } from "@playwright/test";
|
|
164
|
+
|
|
165
|
+
export async function attachJson(testInfo: TestInfo, name: string, value: unknown): Promise<void> {
|
|
166
|
+
await testInfo.attach(\`\${name}.json\`, {
|
|
167
|
+
body: Buffer.from(JSON.stringify(value, null, 2)),
|
|
168
|
+
contentType: "application/json"
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
export function playwrightIncidentReadmeTemplate() {
|
|
174
|
+
return `# Incident Tests
|
|
175
|
+
|
|
176
|
+
Store incident-focused Playwright assets here. Each incident should have:
|
|
177
|
+
|
|
178
|
+
- an incident metadata file
|
|
179
|
+
- a focused spec
|
|
180
|
+
- input and expected payload fixtures
|
|
181
|
+
- a README describing reproduction and verification notes
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
export function playwrightAuthoringGuideTemplate() {
|
|
185
|
+
return `# Authoring Guide
|
|
186
|
+
|
|
187
|
+
Prefer one business behavior per Playwright test file. Keep the test focused on:
|
|
188
|
+
|
|
189
|
+
- deterministic fixtures
|
|
190
|
+
- request mocking
|
|
191
|
+
- payload capture
|
|
192
|
+
- clear assertions
|
|
193
|
+
- attached JSON evidence
|
|
194
|
+
`;
|
|
195
|
+
}
|
|
196
|
+
export function playwrightIncidentGuideTemplate() {
|
|
197
|
+
return `# Incident Guide
|
|
198
|
+
|
|
199
|
+
Use \`harness-comet create incident <id>\` to scaffold incident assets, then keep the spec and fixture files close to the incident metadata.
|
|
200
|
+
`;
|
|
201
|
+
}
|
|
202
|
+
export function playwrightAcceptanceCriteriaTemplate() {
|
|
203
|
+
return `# Acceptance Criteria
|
|
204
|
+
|
|
205
|
+
Every Playwright Harness change should leave behind:
|
|
206
|
+
|
|
207
|
+
- declared target tests
|
|
208
|
+
- verification evidence
|
|
209
|
+
- results JSON
|
|
210
|
+
- a markdown verify report
|
|
211
|
+
- a receipt that archive-check can validate
|
|
212
|
+
`;
|
|
213
|
+
}
|
|
214
|
+
export function testingReadmeTemplate() {
|
|
215
|
+
return `# Testing
|
|
216
|
+
|
|
217
|
+
This project uses Playwright mode for Harness-Comet.
|
|
218
|
+
|
|
219
|
+
Playwright owns test execution through \`playwright.config.ts\`.
|
|
220
|
+
Harness-Comet owns business scenario metadata, Comet impact decisions, verification evidence, and archive checks.
|
|
221
|
+
|
|
222
|
+
Keep tests focused on business behavior. Add helper files and directories only when the project needs them.
|
|
223
|
+
`;
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=playwright-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-mode.js","sourceRoot":"","sources":["../../src/templates/playwright-mode.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oCAAoC,CAAC,OAAO,GAAG,OAAO;IACpE,OAAO;;;;;gBAKO,OAAO;;oBAEH,OAAO;;;;;;;kBAOT,OAAO;;;;;;;;;CASxB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,OAAO,GAAG,OAAO;IACxD,OAAO;;;cAGK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BpB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,6BAA6B;IAC3C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4ER,CAAC;AACF,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO;CACR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,OAAO;;;;;;;;;;;;;;;;CAgBR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,6BAA6B;IAC3C,OAAO;;;;;;;;CAQR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,gCAAgC;IAC9C,OAAO;;;;;;;;CAQR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,gCAAgC;IAC9C,OAAO;;;;;;;;;CASR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,+BAA+B;IAC7C,OAAO;;;CAGR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,oCAAoC;IAClD,OAAO;;;;;;;;;CASR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO;;;;;;;;CAQR,CAAC;AACF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hapergg/harness-comet-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Command line interface for initializing, validating, and running Harness Comet projects.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=20"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/HarperGG/harness-comet.git",
|
|
13
|
+
"directory": "packages/cli"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/HarperGG/harness-comet#readme",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/HarperGG/harness-comet/issues"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"bin"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public",
|
|
25
|
+
"registry": "https://registry.npmjs.org/"
|
|
26
|
+
},
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"import": "./dist/index.js",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"harness-comet": "./bin/harness-comet.js"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"commander": "^14.0.2",
|
|
41
|
+
"execa": "^9.6.0",
|
|
42
|
+
"picocolors": "^1.1.1",
|
|
43
|
+
"@hapergg/harness-comet-adapter-playwright": "0.1.0",
|
|
44
|
+
"@hapergg/harness-comet-schema": "0.1.0",
|
|
45
|
+
"@hapergg/harness-comet-adapter-memory": "0.1.0",
|
|
46
|
+
"@hapergg/harness-comet-core": "0.1.0",
|
|
47
|
+
"@hapergg/harness-comet-comet-adapter": "0.1.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
|
+
"vitest": "^4.0.14"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
55
|
+
"build": "tsc -b && chmod +x bin/harness-comet.js",
|
|
56
|
+
"test": "vitest run"
|
|
57
|
+
}
|
|
58
|
+
}
|