create-appraisejs 0.3.1-alpha.1 → 0.4.0-alpha.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.
Files changed (133) hide show
  1. package/package.json +1 -1
  2. package/templates/blank/.env.example +2 -2
  3. package/templates/blank/.prettierrc +13 -13
  4. package/templates/blank/cucumber.mjs +12 -1
  5. package/templates/blank/e2e/helpers/test-data.ts +10 -0
  6. package/templates/blank/next-env.d.ts +6 -6
  7. package/templates/blank/package-lock.json +2 -2
  8. package/templates/blank/package.json +1 -1
  9. package/templates/blank/packages/cucumber-runtime/package.json +2 -1
  10. package/templates/blank/packages/cucumber-runtime/src/paths.ts +22 -5
  11. package/templates/blank/packages/locator-picker-companion/package.json +2 -1
  12. package/templates/blank/prisma/dev.db +0 -0
  13. package/templates/blank/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  14. package/templates/blank/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  15. package/templates/blank/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  16. package/templates/blank/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  17. package/templates/blank/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  18. package/templates/blank/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  19. package/templates/blank/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  20. package/templates/blank/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  21. package/templates/blank/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  22. package/templates/blank/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  23. package/templates/blank/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  24. package/templates/blank/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  25. package/templates/blank/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  26. package/templates/blank/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -1
  27. package/templates/blank/scripts/setup-env.ts +0 -0
  28. package/templates/blank/scripts/sync-test-cases.ts +60 -10
  29. package/templates/blank/src/components/diagram/flow-diagram-node-search.tsx +9 -2
  30. package/templates/blank/src/components/diagram/flow-diagram-toolbar.tsx +37 -3
  31. package/templates/blank/src/components/diagram/flow-diagram.test.tsx +225 -0
  32. package/templates/blank/src/components/diagram/use-flow-diagram-search.ts +2 -0
  33. package/templates/blank/src/components/diagram/use-flow-diagram.ts +93 -0
  34. package/templates/blank/src/lib/appraise-test-case-metadata.test.ts +78 -0
  35. package/templates/blank/src/lib/appraise-test-case-metadata.ts +220 -0
  36. package/templates/blank/src/lib/automation/automation-path-roots.test.ts +14 -0
  37. package/templates/blank/src/lib/automation/automation-path-roots.ts +10 -2
  38. package/templates/blank/src/lib/database-sync.ts +166 -15
  39. package/templates/blank/src/lib/executor/local-executor-adapter.ts +6 -2
  40. package/templates/blank/src/lib/feature-file-generator.ts +54 -10
  41. package/templates/blank/src/lib/gherkin-parser.test.ts +52 -0
  42. package/templates/blank/src/lib/gherkin-parser.ts +39 -1
  43. package/templates/blank/src/lib/sync/projected-feature-utils.ts +5 -1
  44. package/templates/blank/src/lib/sync/sync-pending-counts.test.ts +115 -0
  45. package/templates/blank/src/lib/sync/sync-pending-counts.ts +108 -13
  46. package/templates/blank/src/services/test-run/test-run-service.test.ts +10 -0
  47. package/templates/blank/src/services/test-run/test-run-service.ts +41 -1
  48. package/templates/starter/.env.example +2 -2
  49. package/templates/starter/.prettierrc +13 -13
  50. package/templates/starter/cucumber.mjs +12 -1
  51. package/templates/starter/e2e/helpers/test-data.ts +10 -0
  52. package/templates/starter/next-env.d.ts +6 -6
  53. package/templates/starter/package-lock.json +2 -2
  54. package/templates/starter/package.json +1 -1
  55. package/templates/starter/packages/cucumber-runtime/package.json +2 -1
  56. package/templates/starter/packages/cucumber-runtime/src/paths.ts +22 -5
  57. package/templates/starter/packages/locator-picker-companion/package.json +2 -1
  58. package/templates/starter/prisma/dev.db +0 -0
  59. package/templates/starter/prisma/migrations/20251104113456_add_type_for_template_step_groups/migration.sql +16 -16
  60. package/templates/starter/prisma/migrations/20251104170946_add_tags_to_test_suite_and_test_case/migration.sql +27 -27
  61. package/templates/starter/prisma/migrations/20251112190024_add_cascade_delete_to_test_run_test_case/migration.sql +17 -17
  62. package/templates/starter/prisma/migrations/20251113181100_add_test_run_log/migration.sql +12 -12
  63. package/templates/starter/prisma/migrations/20251119191838_add_tag_type/migration.sql +28 -28
  64. package/templates/starter/prisma/migrations/20251121164059_add_conflict_resolution/migration.sql +12 -12
  65. package/templates/starter/prisma/migrations/20251223183400_add_report_model_to_db_schema/migration.sql +10 -10
  66. package/templates/starter/prisma/migrations/20251223183637_add_report_test_case_entity_for_storing_test_results_for_individual_test_cases/migration.sql +10 -10
  67. package/templates/starter/prisma/migrations/20251224083549_add_comprehensive_report_storage/migration.sql +108 -108
  68. package/templates/starter/prisma/migrations/20251229194422_migrate_duration_to_string/migration.sql +55 -55
  69. package/templates/starter/prisma/migrations/20251230124637_add_unique_constraint_to_test_run_name/migration.sql +27 -27
  70. package/templates/starter/prisma/migrations/20260115094436_add_dashboard_metrics/migration.sql +59 -59
  71. package/templates/starter/prisma/migrations/20260127172022_add_cascade_delete_to_step_parameters/migration.sql +34 -34
  72. package/templates/starter/prisma/migrations/20260313093000_add_report_step_screenshot_path/migration.sql +1 -1
  73. package/templates/starter/scripts/setup-env.ts +0 -0
  74. package/templates/starter/scripts/sync-test-cases.ts +60 -10
  75. package/templates/starter/src/components/diagram/flow-diagram-node-search.tsx +9 -2
  76. package/templates/starter/src/components/diagram/flow-diagram-toolbar.tsx +37 -3
  77. package/templates/starter/src/components/diagram/flow-diagram.test.tsx +225 -0
  78. package/templates/starter/src/components/diagram/use-flow-diagram-search.ts +2 -0
  79. package/templates/starter/src/components/diagram/use-flow-diagram.ts +93 -0
  80. package/templates/starter/src/lib/appraise-test-case-metadata.test.ts +78 -0
  81. package/templates/starter/src/lib/appraise-test-case-metadata.ts +220 -0
  82. package/templates/starter/src/lib/automation/automation-path-roots.test.ts +14 -0
  83. package/templates/starter/src/lib/automation/automation-path-roots.ts +10 -2
  84. package/templates/starter/src/lib/database-sync.ts +166 -15
  85. package/templates/starter/src/lib/executor/local-executor-adapter.ts +6 -2
  86. package/templates/starter/src/lib/feature-file-generator.ts +54 -10
  87. package/templates/starter/src/lib/gherkin-parser.test.ts +52 -0
  88. package/templates/starter/src/lib/gherkin-parser.ts +39 -1
  89. package/templates/starter/src/lib/sync/projected-feature-utils.ts +5 -1
  90. package/templates/starter/src/lib/sync/sync-pending-counts.test.ts +115 -0
  91. package/templates/starter/src/lib/sync/sync-pending-counts.ts +108 -13
  92. package/templates/starter/src/services/test-run/test-run-service.test.ts +10 -0
  93. package/templates/starter/src/services/test-run/test-run-service.ts +41 -1
  94. package/dist/cli.e2e.test.d.ts +0 -2
  95. package/dist/cli.e2e.test.d.ts.map +0 -1
  96. package/dist/cli.e2e.test.js +0 -75
  97. package/dist/cli.e2e.test.js.map +0 -1
  98. package/dist/config.test.d.ts +0 -2
  99. package/dist/config.test.d.ts.map +0 -1
  100. package/dist/config.test.js +0 -65
  101. package/dist/config.test.js.map +0 -1
  102. package/dist/copy-template.test.d.ts +0 -2
  103. package/dist/copy-template.test.d.ts.map +0 -1
  104. package/dist/copy-template.test.js +0 -71
  105. package/dist/copy-template.test.js.map +0 -1
  106. package/dist/download-repo.test.d.ts +0 -2
  107. package/dist/download-repo.test.d.ts.map +0 -1
  108. package/dist/download-repo.test.js +0 -16
  109. package/dist/download-repo.test.js.map +0 -1
  110. package/dist/install.test.d.ts +0 -2
  111. package/dist/install.test.d.ts.map +0 -1
  112. package/dist/install.test.js +0 -120
  113. package/dist/install.test.js.map +0 -1
  114. package/dist/prompts.test.d.ts +0 -2
  115. package/dist/prompts.test.d.ts.map +0 -1
  116. package/dist/prompts.test.js +0 -58
  117. package/dist/prompts.test.js.map +0 -1
  118. package/templates/default/next-env.d.ts +0 -6
  119. package/templates/default/packages/locator-picker-companion/dist/cli.d.ts +0 -1
  120. package/templates/default/packages/locator-picker-companion/dist/cli.js +0 -336
  121. package/templates/default/packages/locator-picker-companion/dist/index.d.ts +0 -3
  122. package/templates/default/packages/locator-picker-companion/dist/index.js +0 -3
  123. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.d.ts +0 -1
  124. package/templates/default/packages/locator-picker-companion/dist/injected-picker-script.js +0 -660
  125. package/templates/default/packages/locator-picker-companion/dist/launcher.d.ts +0 -14
  126. package/templates/default/packages/locator-picker-companion/dist/launcher.js +0 -58
  127. package/templates/default/packages/locator-picker-companion/dist/selector-generator.d.ts +0 -6
  128. package/templates/default/packages/locator-picker-companion/dist/selector-generator.js +0 -261
  129. package/templates/default/packages/locator-picker-companion/dist/session-file.d.ts +0 -30
  130. package/templates/default/packages/locator-picker-companion/dist/session-file.js +0 -162
  131. package/templates/default/packages/locator-picker-companion/dist/types.d.ts +0 -31
  132. package/templates/default/packages/locator-picker-companion/dist/types.js +0 -1
  133. package/templates/default/prisma/dev.db +0 -0
@@ -1,336 +0,0 @@
1
- import { chromium } from 'playwright'
2
- import {
3
- appendLocatorPickerCrashLog,
4
- createLocatorPickerCrashLog,
5
- ensureLocatorPickerDirectories,
6
- getLocatorPickerCrashLogPath,
7
- patchLocatorPickerSessionFile,
8
- readLocatorPickerSessionFile,
9
- writeLocatorPickerSessionFile,
10
- } from './session-file.js'
11
- import { generatePickedLocatorPayload } from './selector-generator.js'
12
- import { installLocatorPickerOverlay } from './injected-picker-script.js'
13
- function parseArgs(argv) {
14
- var _a, _b, _c, _d
15
- const values = new Map()
16
- for (let index = 0; index < argv.length; index += 1) {
17
- const token = argv[index]
18
- if (!token.startsWith('--')) {
19
- continue
20
- }
21
- values.set(token, (_a = argv[index + 1]) !== null && _a !== void 0 ? _a : '')
22
- index += 1
23
- }
24
- const sessionId = (_b = values.get('--session-id')) === null || _b === void 0 ? void 0 : _b.trim()
25
- const sessionFile = (_c = values.get('--session-file')) === null || _c === void 0 ? void 0 : _c.trim()
26
- const targetUrl = (_d = values.get('--target-url')) === null || _d === void 0 ? void 0 : _d.trim()
27
- if (!sessionId || !sessionFile || !targetUrl) {
28
- throw new Error('Missing required arguments: --session-id, --session-file, --target-url.')
29
- }
30
- return {
31
- sessionId,
32
- sessionFile,
33
- targetUrl,
34
- }
35
- }
36
- function normalizeRoute(value) {
37
- if (!value) {
38
- return '/'
39
- }
40
- try {
41
- return new URL(value).pathname || '/'
42
- } catch (_a) {
43
- return value.startsWith('/') ? value : `/${value}`
44
- }
45
- }
46
- class LocatorPickerCompanion {
47
- constructor(options) {
48
- this.browser = null
49
- this.context = null
50
- this.finalized = false
51
- this.shuttingDown = false
52
- this.requestedExitCode = 0
53
- this.sessionId = options.sessionId
54
- this.sessionFile = options.sessionFile
55
- this.targetUrl = options.targetUrl
56
- this.crashLogPath = getLocatorPickerCrashLogPath(options.sessionId)
57
- }
58
- get exitCode() {
59
- return this.requestedExitCode
60
- }
61
- getLaunchCandidates() {
62
- const sharedOptions = {
63
- args: [
64
- '--disable-background-networking',
65
- '--disable-component-update',
66
- '--disable-default-apps',
67
- '--disable-sync',
68
- '--no-default-browser-check',
69
- '--no-first-run',
70
- ],
71
- headless: false,
72
- }
73
- const bundledChromium = {
74
- label: 'playwright-chromium',
75
- options: sharedOptions,
76
- }
77
- const systemChrome = {
78
- label: 'google-chrome',
79
- options: Object.assign(Object.assign({}, sharedOptions), { channel: 'chrome' }),
80
- }
81
- const systemEdge = {
82
- label: 'microsoft-edge',
83
- options: Object.assign(Object.assign({}, sharedOptions), { channel: 'msedge' }),
84
- }
85
- return [bundledChromium, systemChrome, systemEdge]
86
- }
87
- async launchBrowser() {
88
- const failures = []
89
- for (const candidate of this.getLaunchCandidates()) {
90
- try {
91
- const browser = await chromium.launch(candidate.options)
92
- const context = await browser.newContext({
93
- ignoreHTTPSErrors: true,
94
- })
95
- return { browser, context }
96
- } catch (error) {
97
- const message = error instanceof Error ? error.message : String(error)
98
- failures.push(`${candidate.label}: ${message}`)
99
- }
100
- }
101
- throw new Error(failures.join('\n\n'))
102
- }
103
- async ensureOverlayInstalled(page) {
104
- if (page.isClosed()) {
105
- return
106
- }
107
- await page.evaluate(installLocatorPickerOverlay).catch(() => undefined)
108
- }
109
- async writeCrashLog(message) {
110
- await appendLocatorPickerCrashLog(this.crashLogPath, message).catch(() => undefined)
111
- }
112
- async run() {
113
- var _a
114
- await ensureLocatorPickerDirectories(process.cwd())
115
- await createLocatorPickerCrashLog(this.crashLogPath)
116
- await this.writeCrashLog(`Companion booting for ${this.targetUrl}.`)
117
- await patchLocatorPickerSessionFile(this.sessionFile, {
118
- companionPid: process.pid,
119
- crashLogPath: this.crashLogPath,
120
- error: undefined,
121
- })
122
- process.on('SIGTERM', () => {
123
- void this.writeCrashLog('Received SIGTERM.')
124
- void this.shutdown('closed')
125
- })
126
- process.on('SIGINT', () => {
127
- void this.writeCrashLog('Received SIGINT.')
128
- void this.shutdown('closed')
129
- })
130
- process.on('uncaughtException', error => {
131
- void this.writeCrashLog(
132
- `Uncaught exception: ${error instanceof Error ? error.stack || error.message : String(error)}`,
133
- )
134
- void this.shutdown('error')
135
- process.exitCode = 1
136
- })
137
- process.on('unhandledRejection', reason => {
138
- const details = reason instanceof Error ? reason.stack || reason.message : String(reason)
139
- void this.writeCrashLog(`Unhandled rejection: ${details}`)
140
- void this.shutdown('error')
141
- process.exitCode = 1
142
- })
143
- try {
144
- const launchedBrowser = await this.launchBrowser()
145
- this.browser = launchedBrowser.browser
146
- this.context = launchedBrowser.context
147
- await this.context.exposeBinding(
148
- '__appraiseLocatorPickerPreview',
149
- async ({ page }, elementHandle) => {
150
- return this.generatePreview(page, elementHandle)
151
- },
152
- { handle: true },
153
- )
154
- await this.context.exposeBinding('__appraiseLocatorPickerConfirm', async (_source, payload) => {
155
- await this.confirmSelection(payload)
156
- })
157
- await this.context.exposeBinding('__appraiseLocatorPickerCancel', async () => {
158
- await this.shutdown('closed')
159
- })
160
- await this.context.addInitScript(installLocatorPickerOverlay)
161
- this.context.on('page', page => {
162
- this.attachPage(page)
163
- })
164
- for (const page of this.context.pages()) {
165
- this.attachPage(page)
166
- }
167
- const page =
168
- (_a = this.context.pages().find(candidate => !candidate.isClosed())) !== null && _a !== void 0
169
- ? _a
170
- : await this.context.newPage()
171
- await page.goto(this.targetUrl, { waitUntil: 'domcontentloaded' })
172
- await this.ensureOverlayInstalled(page)
173
- await this.writePageState(page, 'ready')
174
- await this.context.waitForEvent('close', { timeout: 0 })
175
- if (!this.finalized) {
176
- await this.shutdown('closed')
177
- }
178
- await this.writeCrashLog(
179
- this.finalized
180
- ? 'Companion finished cleanly after locator selection.'
181
- : 'Companion closed cleanly without runtime errors.',
182
- )
183
- } catch (error) {
184
- this.requestedExitCode = 1
185
- await this.writeCrashLog(
186
- `Companion startup failed: ${error instanceof Error ? error.stack || error.message : String(error)}`,
187
- )
188
- await this.markError(
189
- error instanceof Error && error.message.includes("Executable doesn't exist")
190
- ? 'Playwright Chromium is not installed. Run `npm run install-playwright -- chromium` and retry.'
191
- : error instanceof Error
192
- ? error.message
193
- : 'Failed to start the locator picker companion.',
194
- )
195
- process.exitCode = 1
196
- }
197
- }
198
- attachPage(page) {
199
- const refresh = () => {
200
- void (async () => {
201
- await this.ensureOverlayInstalled(page)
202
- await this.writePageState(page, this.finalized ? 'picked' : 'ready')
203
- })()
204
- }
205
- page.on('domcontentloaded', refresh)
206
- page.on('load', refresh)
207
- page.on('framenavigated', frame => {
208
- if (frame === page.mainFrame()) {
209
- refresh()
210
- }
211
- })
212
- page.on('close', () => {
213
- void this.handlePageClose()
214
- })
215
- }
216
- async writePageState(page, status) {
217
- if (page.isClosed()) {
218
- return
219
- }
220
- const currentUrl = page.url()
221
- const pageTitle = await page.title().catch(() => '')
222
- await patchLocatorPickerSessionFile(this.sessionFile, current => ({
223
- status: current.status === 'saving' ? 'saving' : status,
224
- currentUrl,
225
- currentPathname: normalizeRoute(currentUrl),
226
- pageTitle,
227
- companionPid: process.pid,
228
- error: undefined,
229
- }))
230
- }
231
- async generatePreview(page, elementHandle) {
232
- if (!page || page.isClosed()) {
233
- throw new Error('The page is no longer available for picking.')
234
- }
235
- return generatePickedLocatorPayload(page, elementHandle)
236
- }
237
- async confirmSelection(payload) {
238
- this.finalized = true
239
- this.requestedExitCode = 0
240
- await patchLocatorPickerSessionFile(this.sessionFile, current => ({
241
- status: current.status === 'saving' ? 'saving' : 'picked',
242
- currentUrl: payload.currentUrl,
243
- currentPathname: payload.pathname,
244
- pageTitle: payload.pageTitle,
245
- pickedLocator: payload,
246
- error: undefined,
247
- companionPid: process.pid,
248
- }))
249
- await this.closeContext()
250
- }
251
- async handlePageClose() {
252
- if (this.finalized || this.shuttingDown || !this.context) {
253
- return
254
- }
255
- const openPages = this.context.pages().filter(page => !page.isClosed())
256
- if (openPages.length === 0) {
257
- await this.shutdown('closed')
258
- }
259
- }
260
- async closeContext() {
261
- const currentContext = this.context
262
- const currentBrowser = this.browser
263
- this.context = null
264
- this.browser = null
265
- await (currentContext === null || currentContext === void 0
266
- ? void 0
267
- : currentContext.close().catch(() => undefined))
268
- await (currentBrowser === null || currentBrowser === void 0
269
- ? void 0
270
- : currentBrowser.close().catch(() => undefined))
271
- }
272
- async markError(message) {
273
- this.finalized = false
274
- this.requestedExitCode = 1
275
- await this.writeCrashLog(`Marked session as error: ${message}`)
276
- await patchLocatorPickerSessionFile(this.sessionFile, {
277
- status: 'error',
278
- error: message,
279
- companionPid: process.pid,
280
- })
281
- }
282
- async shutdown(status) {
283
- if (this.shuttingDown) {
284
- return
285
- }
286
- this.shuttingDown = true
287
- this.requestedExitCode = status === 'error' ? 1 : 0
288
- await this.writeCrashLog(`Shutdown requested with status ${status}.`)
289
- if (!this.finalized) {
290
- await patchLocatorPickerSessionFile(this.sessionFile, current => ({
291
- status: current.status === 'saving' ? 'saving' : status,
292
- companionPid: process.pid,
293
- }))
294
- }
295
- await this.closeContext()
296
- }
297
- }
298
- async function main() {
299
- const options = parseArgs(process.argv.slice(2))
300
- const existingSession = await readLocatorPickerSessionFile(options.sessionFile)
301
- if (!existingSession) {
302
- throw new Error(`Locator picker session file not found: ${options.sessionFile}`)
303
- }
304
- await writeLocatorPickerSessionFile(
305
- options.sessionFile,
306
- Object.assign(Object.assign({}, existingSession), {
307
- companionPid: process.pid,
308
- crashLogPath: existingSession.crashLogPath || getLocatorPickerCrashLogPath(options.sessionId),
309
- error: undefined,
310
- }),
311
- )
312
- const companion = new LocatorPickerCompanion(options)
313
- await companion.run()
314
- process.exit(companion.exitCode)
315
- }
316
- void main().catch(async error => {
317
- const argv = process.argv.slice(2)
318
- const sessionFileIndex = argv.findIndex(token => token === '--session-file')
319
- const sessionFile = sessionFileIndex >= 0 ? argv[sessionFileIndex + 1] : undefined
320
- const sessionIdIndex = argv.findIndex(token => token === '--session-id')
321
- const sessionId = sessionIdIndex >= 0 ? argv[sessionIdIndex + 1] : undefined
322
- if (sessionFile) {
323
- await patchLocatorPickerSessionFile(sessionFile, {
324
- status: 'error',
325
- error: error instanceof Error ? error.message : 'Locator picker companion failed.',
326
- companionPid: process.pid,
327
- }).catch(() => undefined)
328
- }
329
- if (sessionId) {
330
- await appendLocatorPickerCrashLog(
331
- getLocatorPickerCrashLogPath(sessionId),
332
- `Main process catch: ${error instanceof Error ? error.stack || error.message : String(error)}`,
333
- ).catch(() => undefined)
334
- }
335
- process.exitCode = 1
336
- })
@@ -1,3 +0,0 @@
1
- export * from './launcher.js'
2
- export * from './session-file.js'
3
- export * from './types.js'
@@ -1,3 +0,0 @@
1
- export * from './launcher.js'
2
- export * from './session-file.js'
3
- export * from './types.js'
@@ -1 +0,0 @@
1
- export declare function installLocatorPickerOverlay(): void