@qulib/core 0.7.0 → 0.9.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/README.md +30 -5
- package/bin/qulib.js +2 -3
- package/dist/__tests__/fixtures/api-fixture-repo/app/api/orders/route.d.ts +7 -0
- package/dist/__tests__/fixtures/api-fixture-repo/app/api/orders/route.d.ts.map +1 -0
- package/dist/__tests__/fixtures/api-fixture-repo/app/api/orders/route.js +7 -0
- package/dist/__tests__/fixtures/api-fixture-repo/app/api/users/route.d.ts +10 -0
- package/dist/__tests__/fixtures/api-fixture-repo/app/api/users/route.d.ts.map +1 -0
- package/dist/__tests__/fixtures/api-fixture-repo/app/api/users/route.js +9 -0
- package/dist/__tests__/fixtures/api-fixture-repo/pages/api/health.d.ts +9 -0
- package/dist/__tests__/fixtures/api-fixture-repo/pages/api/health.d.ts.map +1 -0
- package/dist/__tests__/fixtures/api-fixture-repo/pages/api/health.js +10 -0
- package/dist/__tests__/playwright-available.d.ts +32 -0
- package/dist/__tests__/playwright-available.d.ts.map +1 -0
- package/dist/__tests__/playwright-available.js +35 -0
- package/dist/adapters/api-adapter.d.ts +26 -0
- package/dist/adapters/api-adapter.d.ts.map +1 -1
- package/dist/adapters/api-adapter.js +156 -2
- package/dist/adapters/ci-results-adapter.d.ts +67 -0
- package/dist/adapters/ci-results-adapter.d.ts.map +1 -0
- package/dist/adapters/ci-results-adapter.js +143 -0
- package/dist/adapters/cypress-e2e-adapter.d.ts.map +1 -1
- package/dist/adapters/cypress-e2e-adapter.js +25 -2
- package/dist/adapters/playwright-adapter.d.ts.map +1 -1
- package/dist/adapters/playwright-adapter.js +94 -2
- package/dist/adapters/pr-metadata-adapter.d.ts +75 -0
- package/dist/adapters/pr-metadata-adapter.d.ts.map +1 -0
- package/dist/adapters/pr-metadata-adapter.js +146 -0
- package/dist/adapters/validate-specs.d.ts +55 -0
- package/dist/adapters/validate-specs.d.ts.map +1 -0
- package/dist/adapters/validate-specs.js +67 -0
- package/dist/baseline/baseline.d.ts +54 -0
- package/dist/baseline/baseline.d.ts.map +1 -0
- package/dist/baseline/baseline.js +252 -0
- package/dist/baseline/baseline.schema.d.ts +233 -0
- package/dist/baseline/baseline.schema.d.ts.map +1 -0
- package/dist/baseline/baseline.schema.js +59 -0
- package/dist/cli/confidence-run.d.ts +16 -0
- package/dist/cli/confidence-run.d.ts.map +1 -0
- package/dist/cli/confidence-run.js +158 -0
- package/dist/cli/index.d.ts +11 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +80 -4
- package/dist/cli/scaffold-run.d.ts +86 -0
- package/dist/cli/scaffold-run.d.ts.map +1 -0
- package/dist/cli/scaffold-run.js +232 -0
- package/dist/cli/score-automation-run.d.ts +25 -0
- package/dist/cli/score-automation-run.d.ts.map +1 -0
- package/dist/cli/score-automation-run.js +123 -0
- package/dist/examples/notquality-dogfood/fixture.d.ts +166 -0
- package/dist/examples/notquality-dogfood/fixture.d.ts.map +1 -0
- package/dist/examples/notquality-dogfood/fixture.js +174 -0
- package/dist/examples/notquality-dogfood/run.d.ts +34 -0
- package/dist/examples/notquality-dogfood/run.d.ts.map +1 -0
- package/dist/examples/notquality-dogfood/run.js +139 -0
- package/dist/index.d.ts +18 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/recipes/a11y.d.ts +36 -0
- package/dist/recipes/a11y.d.ts.map +1 -0
- package/dist/recipes/a11y.js +118 -0
- package/dist/recipes/auth.d.ts +38 -0
- package/dist/recipes/auth.d.ts.map +1 -0
- package/dist/recipes/auth.js +156 -0
- package/dist/recipes/index.d.ts +26 -0
- package/dist/recipes/index.d.ts.map +1 -0
- package/dist/recipes/index.js +41 -0
- package/dist/recipes/nav.d.ts +34 -0
- package/dist/recipes/nav.d.ts.map +1 -0
- package/dist/recipes/nav.js +128 -0
- package/dist/recipes/seed.d.ts +34 -0
- package/dist/recipes/seed.d.ts.map +1 -0
- package/dist/recipes/seed.js +87 -0
- package/dist/scaffold-tests.d.ts +21 -0
- package/dist/scaffold-tests.d.ts.map +1 -1
- package/dist/scaffold-tests.js +12 -2
- package/dist/schemas/automation-maturity.schema.d.ts +8 -8
- package/dist/schemas/automation-maturity.schema.d.ts.map +1 -1
- package/dist/schemas/automation-maturity.schema.js +1 -0
- package/dist/schemas/confidence.schema.d.ts +526 -0
- package/dist/schemas/confidence.schema.d.ts.map +1 -0
- package/dist/schemas/confidence.schema.js +161 -0
- package/dist/schemas/gap-analysis.schema.d.ts +8 -8
- package/dist/schemas/gap-analysis.schema.js +1 -1
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +3 -0
- package/dist/schemas/public-surface.schema.d.ts +5 -5
- package/dist/schemas/recipe.schema.d.ts +66 -0
- package/dist/schemas/recipe.schema.d.ts.map +1 -0
- package/dist/schemas/recipe.schema.js +45 -0
- package/dist/schemas/repo-analysis.schema.d.ts +7 -7
- package/dist/schemas/views.schema.d.ts +234 -0
- package/dist/schemas/views.schema.d.ts.map +1 -0
- package/dist/schemas/views.schema.js +82 -0
- package/dist/tools/repo/api-surface.d.ts +59 -0
- package/dist/tools/repo/api-surface.d.ts.map +1 -0
- package/dist/tools/repo/api-surface.js +414 -0
- package/dist/tools/scoring/api-coverage.d.ts +74 -0
- package/dist/tools/scoring/api-coverage.d.ts.map +1 -0
- package/dist/tools/scoring/api-coverage.js +158 -0
- package/dist/tools/scoring/automation-maturity.d.ts +11 -1
- package/dist/tools/scoring/automation-maturity.d.ts.map +1 -1
- package/dist/tools/scoring/automation-maturity.js +43 -9
- package/dist/tools/scoring/confidence-from-qulib.d.ts +34 -0
- package/dist/tools/scoring/confidence-from-qulib.d.ts.map +1 -0
- package/dist/tools/scoring/confidence-from-qulib.js +206 -0
- package/dist/tools/scoring/confidence-views.d.ts +40 -0
- package/dist/tools/scoring/confidence-views.d.ts.map +1 -0
- package/dist/tools/scoring/confidence-views.js +163 -0
- package/dist/tools/scoring/confidence.d.ts +32 -0
- package/dist/tools/scoring/confidence.d.ts.map +1 -0
- package/dist/tools/scoring/confidence.js +180 -0
- package/dist/tools/scoring/levels.d.ts +15 -0
- package/dist/tools/scoring/levels.d.ts.map +1 -0
- package/dist/tools/scoring/levels.js +21 -0
- package/package.json +15 -7
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const DEFAULT_ROUTES = ['/', '/about', '/404'];
|
|
2
|
+
/**
|
|
3
|
+
* Generate NeutralScenarios for the nav recipe.
|
|
4
|
+
*
|
|
5
|
+
* Returns 3 scenarios:
|
|
6
|
+
* 1. Deep-link routes — direct navigation lands on the correct page
|
|
7
|
+
* 2. Browser-back — back button returns to the previous route
|
|
8
|
+
* 3. 404 handling — unknown routes show a user-friendly not-found page
|
|
9
|
+
*/
|
|
10
|
+
export function buildNavScenarios(config = {}) {
|
|
11
|
+
const routes = config.navRoutes ?? DEFAULT_ROUTES;
|
|
12
|
+
// Pick up to 3 routes (root + 1 deep + 404 fallback); guard against an empty list.
|
|
13
|
+
const root = routes[0] ?? '/';
|
|
14
|
+
const deep = routes[1] ?? '/about';
|
|
15
|
+
return [
|
|
16
|
+
{
|
|
17
|
+
id: 'recipe-nav-deep-link',
|
|
18
|
+
title: 'Direct navigation to a deep route lands on the correct page',
|
|
19
|
+
description: 'Visiting a non-root route directly (without clicking through) loads the right content — SPA routing and server-side routing both produce the expected page',
|
|
20
|
+
targetPath: deep,
|
|
21
|
+
steps: [
|
|
22
|
+
{
|
|
23
|
+
action: 'navigate',
|
|
24
|
+
target: deep,
|
|
25
|
+
description: `Navigate directly to ${deep}`,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
action: 'assert-visible',
|
|
29
|
+
target: 'main',
|
|
30
|
+
description: 'Main content region is visible — page loaded',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
action: 'assert-visible',
|
|
34
|
+
target: 'h1',
|
|
35
|
+
description: 'Page has a heading — correct content loaded, not an error page',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
tags: ['nav', 'smoke', 'recipe-nav'],
|
|
39
|
+
recommendations: [
|
|
40
|
+
{
|
|
41
|
+
adapter: 'playwright',
|
|
42
|
+
reason: 'Proven NQ-2 nav pattern — page.goto + toHaveURL + heading assertion',
|
|
43
|
+
confidence: 'high',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
adapter: 'cypress-e2e',
|
|
47
|
+
reason: 'Proven CaseLoom nav pattern — cy.visit + cy.url().should',
|
|
48
|
+
confidence: 'high',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
sourceGapIds: ['recipe-nav'],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'recipe-nav-browser-back',
|
|
55
|
+
title: 'Browser back button returns to the previous route',
|
|
56
|
+
description: 'After navigating from the root to a deep route, pressing browser-back returns the user to the root — history stack is correctly maintained',
|
|
57
|
+
targetPath: deep,
|
|
58
|
+
steps: [
|
|
59
|
+
{
|
|
60
|
+
action: 'navigate',
|
|
61
|
+
target: root,
|
|
62
|
+
description: `Start at the root (${root})`,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
action: 'navigate',
|
|
66
|
+
target: deep,
|
|
67
|
+
description: `Navigate forward to ${deep}`,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
action: 'assert-visible',
|
|
71
|
+
target: 'h1',
|
|
72
|
+
description: 'Deep-route page loaded successfully',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
action: 'wait',
|
|
76
|
+
value: '300',
|
|
77
|
+
description: 'Let the navigation history settle',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
tags: ['nav', 'history', 'recipe-nav'],
|
|
81
|
+
recommendations: [
|
|
82
|
+
{
|
|
83
|
+
adapter: 'playwright',
|
|
84
|
+
reason: 'page.goBack() proves history is intact — proven NQ-2 pattern',
|
|
85
|
+
confidence: 'medium',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
adapter: 'cypress-e2e',
|
|
89
|
+
reason: 'cy.go("back") — proven CaseLoom history pattern',
|
|
90
|
+
confidence: 'medium',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
sourceGapIds: ['recipe-nav'],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 'recipe-nav-404-handling',
|
|
97
|
+
title: 'Unknown routes show a user-friendly 404 page',
|
|
98
|
+
description: 'Navigating to a non-existent route renders a helpful not-found page rather than a blank screen or an unhandled JS error',
|
|
99
|
+
targetPath: '/this-route-definitely-does-not-exist-qulib-404-probe',
|
|
100
|
+
steps: [
|
|
101
|
+
{
|
|
102
|
+
action: 'navigate',
|
|
103
|
+
target: '/this-route-definitely-does-not-exist-qulib-404-probe',
|
|
104
|
+
description: 'Navigate to a route guaranteed to be absent',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
action: 'assert-visible',
|
|
108
|
+
target: 'h1',
|
|
109
|
+
description: 'A heading is visible — the app renders a page (not-found or otherwise) rather than a blank error',
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
tags: ['nav', 'error-handling', 'recipe-nav'],
|
|
113
|
+
recommendations: [
|
|
114
|
+
{
|
|
115
|
+
adapter: 'playwright',
|
|
116
|
+
reason: 'page.getByText("404") / not-found selector — proven NQ-2 error-handling pattern',
|
|
117
|
+
confidence: 'medium',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
adapter: 'cypress-e2e',
|
|
121
|
+
reason: 'cy.get fallback chain on error/not-found markers',
|
|
122
|
+
confidence: 'medium',
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
sourceGapIds: ['recipe-nav'],
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* seed recipe — data-seeding and state-reset helpers.
|
|
3
|
+
*
|
|
4
|
+
* Lifted from the PROVEN NQ-2 Playwright + CaseLoom Cypress test-data patterns.
|
|
5
|
+
* Re-derived from first principles — not copy-pasted.
|
|
6
|
+
*
|
|
7
|
+
* NQ-2 Playwright seed reference patterns:
|
|
8
|
+
* - await request.post('/api/test/reset', { data: {} })
|
|
9
|
+
* - expect(response.status()).toBe(200)
|
|
10
|
+
* - await request.post('/api/test/seed', { data: { scenario: 'default' } })
|
|
11
|
+
*
|
|
12
|
+
* CaseLoom Cypress seed reference patterns:
|
|
13
|
+
* - cy.request('POST', '/api/test/reset')
|
|
14
|
+
* - cy.request('POST', '/api/test/seed', { scenario: 'default' })
|
|
15
|
+
* - cy.request({ method: 'DELETE', url: '/api/test/all' }).its('status').should('be.oneOf', [200, 204])
|
|
16
|
+
*
|
|
17
|
+
* The seed recipe is primarily a Playwright/API recipe because Cypress request()
|
|
18
|
+
* handles it cleanly, but the NeutralScenario shape covers both adapters via
|
|
19
|
+
* the api-call action.
|
|
20
|
+
*/
|
|
21
|
+
import type { NeutralScenario } from '../schemas/gap-analysis.schema.js';
|
|
22
|
+
import type { RecipeConfig } from '../schemas/recipe.schema.js';
|
|
23
|
+
/**
|
|
24
|
+
* Generate NeutralScenarios for the seed recipe.
|
|
25
|
+
*
|
|
26
|
+
* Returns 2 scenarios:
|
|
27
|
+
* 1. State reset — POST to the reset endpoint returns 200/204 (clean slate)
|
|
28
|
+
* 2. Seed + verify — POST seed then verify the seeded UI state is visible
|
|
29
|
+
*
|
|
30
|
+
* These are rendered as api-call steps, which both adapters handle (Cypress via
|
|
31
|
+
* cy.request, Playwright via page.request.post).
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildSeedScenarios(config?: RecipeConfig): NeutralScenario[];
|
|
34
|
+
//# sourceMappingURL=seed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../src/recipes/seed.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,YAAiB,GAAG,eAAe,EAAE,CA6E/E"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const DEFAULT_SEED_ENDPOINT = '/api/test/seed';
|
|
2
|
+
const DEFAULT_RESET_ENDPOINT = '/api/test/reset';
|
|
3
|
+
/**
|
|
4
|
+
* Generate NeutralScenarios for the seed recipe.
|
|
5
|
+
*
|
|
6
|
+
* Returns 2 scenarios:
|
|
7
|
+
* 1. State reset — POST to the reset endpoint returns 200/204 (clean slate)
|
|
8
|
+
* 2. Seed + verify — POST seed then verify the seeded UI state is visible
|
|
9
|
+
*
|
|
10
|
+
* These are rendered as api-call steps, which both adapters handle (Cypress via
|
|
11
|
+
* cy.request, Playwright via page.request.post).
|
|
12
|
+
*/
|
|
13
|
+
export function buildSeedScenarios(config = {}) {
|
|
14
|
+
const seedEndpoint = config.seedEndpoint ?? DEFAULT_SEED_ENDPOINT;
|
|
15
|
+
const resetEndpoint = DEFAULT_RESET_ENDPOINT;
|
|
16
|
+
return [
|
|
17
|
+
{
|
|
18
|
+
id: 'recipe-seed-reset',
|
|
19
|
+
title: 'Test state reset endpoint returns a success status',
|
|
20
|
+
description: 'POSTing to the reset endpoint clears test data and returns 200 — the test teardown contract is honoured',
|
|
21
|
+
targetPath: resetEndpoint,
|
|
22
|
+
steps: [
|
|
23
|
+
{
|
|
24
|
+
action: 'api-call',
|
|
25
|
+
target: resetEndpoint,
|
|
26
|
+
description: 'POST to the reset endpoint — expect 200/204',
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
tags: ['seed', 'setup', 'recipe-seed'],
|
|
30
|
+
recommendations: [
|
|
31
|
+
{
|
|
32
|
+
adapter: 'playwright',
|
|
33
|
+
reason: 'page.request.post / apiRequest — proven NQ-2 data-setup pattern',
|
|
34
|
+
confidence: 'high',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
adapter: 'cypress-e2e',
|
|
38
|
+
reason: 'cy.request("POST", url) — proven CaseLoom seed pattern',
|
|
39
|
+
confidence: 'high',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
adapter: 'api',
|
|
43
|
+
reason: 'Direct API seed — no browser required',
|
|
44
|
+
confidence: 'high',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
sourceGapIds: ['recipe-seed'],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'recipe-seed-and-verify',
|
|
51
|
+
title: 'Seed endpoint populates data that is visible in the UI',
|
|
52
|
+
description: 'After seeding the default dataset, the UI reflects the seeded state — the test pipeline can establish known state before running assertions',
|
|
53
|
+
targetPath: '/',
|
|
54
|
+
steps: [
|
|
55
|
+
{
|
|
56
|
+
action: 'api-call',
|
|
57
|
+
target: seedEndpoint,
|
|
58
|
+
description: `POST to seed endpoint (${seedEndpoint}) to populate default test data`,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
action: 'navigate',
|
|
62
|
+
target: '/',
|
|
63
|
+
description: 'Navigate to the app root to verify the seeded state is visible',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
action: 'assert-visible',
|
|
67
|
+
target: 'main',
|
|
68
|
+
description: 'Application loaded with seeded data',
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
tags: ['seed', 'data-setup', 'recipe-seed'],
|
|
72
|
+
recommendations: [
|
|
73
|
+
{
|
|
74
|
+
adapter: 'playwright',
|
|
75
|
+
reason: 'Proven NQ-2 seed + navigate pattern — set state before assertions',
|
|
76
|
+
confidence: 'medium',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
adapter: 'cypress-e2e',
|
|
80
|
+
reason: 'cy.request seed then cy.visit — proven CaseLoom setup pattern',
|
|
81
|
+
confidence: 'medium',
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
sourceGapIds: ['recipe-seed'],
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
}
|
package/dist/scaffold-tests.d.ts
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
|
+
import { type SpecValidationReport } from './adapters/validate-specs.js';
|
|
1
2
|
import type { NeutralScenario, GeneratedTest } from './schemas/gap-analysis.schema.js';
|
|
2
3
|
import type { AdapterType } from './schemas/config.schema.js';
|
|
3
4
|
import type { AnalyzeProgressSink } from './harness/progress-log.js';
|
|
4
5
|
import type { TelemetrySink } from './telemetry/telemetry.interface.js';
|
|
6
|
+
import type { RecipeId, RecipeConfig } from './schemas/recipe.schema.js';
|
|
5
7
|
export interface ScaffoldOptions {
|
|
6
8
|
framework?: Extract<AdapterType, 'cypress-e2e' | 'playwright'>;
|
|
7
9
|
maxPagesToScan?: number;
|
|
8
10
|
scenarios?: NeutralScenario[];
|
|
9
11
|
progressLog?: AnalyzeProgressSink;
|
|
10
12
|
telemetry?: TelemetrySink;
|
|
13
|
+
/**
|
|
14
|
+
* Optional list of recipe ids to expand into additional scenarios.
|
|
15
|
+
* Recipe scenarios are APPENDED to any scenarios derived from analysis or
|
|
16
|
+
* supplied via `scenarios` — they never replace existing content.
|
|
17
|
+
* Example: ['auth', 'a11y'] appends login-flow + a11y scenarios.
|
|
18
|
+
*/
|
|
19
|
+
recipes?: RecipeId[];
|
|
20
|
+
/**
|
|
21
|
+
* Per-recipe configuration overrides (selectors, routes, impact thresholds).
|
|
22
|
+
* Only consulted when `recipes` is non-empty.
|
|
23
|
+
*/
|
|
24
|
+
recipeConfig?: RecipeConfig;
|
|
11
25
|
}
|
|
12
26
|
export interface ProjectConfig {
|
|
13
27
|
configFile: {
|
|
@@ -29,6 +43,13 @@ export interface ScaffoldResult {
|
|
|
29
43
|
generatedTests: GeneratedTest[];
|
|
30
44
|
scenarios: NeutralScenario[];
|
|
31
45
|
projectConfig: ProjectConfig;
|
|
46
|
+
/**
|
|
47
|
+
* Dry-run validation of every generated spec: each spec is transpiled through
|
|
48
|
+
* the TypeScript compiler and any parse/compile error is surfaced here. This
|
|
49
|
+
* is the witness that the scaffold did not emit broken code — `ok: false`
|
|
50
|
+
* means at least one generated spec will not parse. Always populated.
|
|
51
|
+
*/
|
|
52
|
+
specValidation: SpecValidationReport;
|
|
32
53
|
}
|
|
33
54
|
export declare function scaffoldTests(url: string, options?: ScaffoldOptions): Promise<ScaffoldResult>;
|
|
34
55
|
//# sourceMappingURL=scaffold-tests.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold-tests.d.ts","sourceRoot":"","sources":["../src/scaffold-tests.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"scaffold-tests.d.ts","sourceRoot":"","sources":["../src/scaffold-tests.ts"],"names":[],"mappings":"AAEA,OAAO,EAA0B,KAAK,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEjG,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAEzE,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC,WAAW,EAAE,aAAa,GAAG,YAAY,CAAC,CAAC;IAC/D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,WAAW,EAAE;QAAE,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IAC1F,YAAY,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,OAAO,CAAC,WAAW,EAAE,aAAa,GAAG,YAAY,CAAC,CAAC;IAC9D,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,aAAa,EAAE,aAAa,CAAC;IAC7B;;;;;OAKG;IACH,cAAc,EAAE,oBAAoB,CAAC;CACtC;AA8ED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAmDzB"}
|
package/dist/scaffold-tests.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { analyzeApp } from './analyze.js';
|
|
2
2
|
import { createAdapter } from './adapters/adapter-factory.js';
|
|
3
|
+
import { validateGeneratedTests } from './adapters/validate-specs.js';
|
|
4
|
+
import { expandRecipes } from './recipes/index.js';
|
|
3
5
|
function buildCypressProjectConfig(url) {
|
|
4
6
|
return {
|
|
5
7
|
configFile: {
|
|
@@ -104,10 +106,18 @@ export async function scaffoldTests(url, options = {}) {
|
|
|
104
106
|
});
|
|
105
107
|
scenarios = result.gapAnalysis.scenarios;
|
|
106
108
|
}
|
|
109
|
+
// Expand any requested recipes and append their scenarios (additive — never replace).
|
|
110
|
+
const recipeScenarios = expandRecipes(options.recipes, options.recipeConfig ?? {});
|
|
111
|
+
const allScenarios = recipeScenarios.length > 0
|
|
112
|
+
? [...scenarios, ...recipeScenarios]
|
|
113
|
+
: scenarios;
|
|
107
114
|
const adapter = createAdapter(framework);
|
|
108
|
-
const generatedTests = adapter.renderAll(
|
|
115
|
+
const generatedTests = adapter.renderAll(allScenarios);
|
|
109
116
|
const projectConfig = framework === 'cypress-e2e'
|
|
110
117
|
? buildCypressProjectConfig(url)
|
|
111
118
|
: buildPlaywrightProjectConfig(url);
|
|
112
|
-
|
|
119
|
+
// Dry-run every generated spec through the TS compiler so a parse/compile
|
|
120
|
+
// failure is caught here, not when a developer first runs the suite.
|
|
121
|
+
const specValidation = validateGeneratedTests(generatedTests);
|
|
122
|
+
return { url, framework, generatedTests, scenarios: allScenarios, projectConfig, specValidation };
|
|
113
123
|
}
|
|
@@ -20,7 +20,7 @@ export declare const AutomationMaturityApplicabilitySchema: z.ZodEnum<["applicab
|
|
|
20
20
|
* Existing consumers that don't read them keep working; honest reports populate them.
|
|
21
21
|
*/
|
|
22
22
|
export declare const AutomationMaturityDimensionSchema: z.ZodObject<{
|
|
23
|
-
dimension: z.ZodEnum<["test-coverage-breadth", "framework-adoption", "test-id-hygiene", "ci-integration", "auth-test-coverage", "component-test-ratio"]>;
|
|
23
|
+
dimension: z.ZodEnum<["test-coverage-breadth", "framework-adoption", "test-id-hygiene", "ci-integration", "auth-test-coverage", "component-test-ratio", "api-test-coverage"]>;
|
|
24
24
|
score: z.ZodNumber;
|
|
25
25
|
weight: z.ZodNumber;
|
|
26
26
|
evidence: z.ZodArray<z.ZodString, "many">;
|
|
@@ -30,7 +30,7 @@ export declare const AutomationMaturityDimensionSchema: z.ZodObject<{
|
|
|
30
30
|
guidance: z.ZodOptional<z.ZodString>;
|
|
31
31
|
}, "strip", z.ZodTypeAny, {
|
|
32
32
|
recommendations: string[];
|
|
33
|
-
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio";
|
|
33
|
+
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio" | "api-test-coverage";
|
|
34
34
|
score: number;
|
|
35
35
|
weight: number;
|
|
36
36
|
evidence: string[];
|
|
@@ -39,7 +39,7 @@ export declare const AutomationMaturityDimensionSchema: z.ZodObject<{
|
|
|
39
39
|
guidance?: string | undefined;
|
|
40
40
|
}, {
|
|
41
41
|
recommendations: string[];
|
|
42
|
-
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio";
|
|
42
|
+
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio" | "api-test-coverage";
|
|
43
43
|
score: number;
|
|
44
44
|
weight: number;
|
|
45
45
|
evidence: string[];
|
|
@@ -54,7 +54,7 @@ export declare const AutomationMaturitySchema: z.ZodObject<{
|
|
|
54
54
|
level: z.ZodNumber;
|
|
55
55
|
label: z.ZodString;
|
|
56
56
|
dimensions: z.ZodArray<z.ZodObject<{
|
|
57
|
-
dimension: z.ZodEnum<["test-coverage-breadth", "framework-adoption", "test-id-hygiene", "ci-integration", "auth-test-coverage", "component-test-ratio"]>;
|
|
57
|
+
dimension: z.ZodEnum<["test-coverage-breadth", "framework-adoption", "test-id-hygiene", "ci-integration", "auth-test-coverage", "component-test-ratio", "api-test-coverage"]>;
|
|
58
58
|
score: z.ZodNumber;
|
|
59
59
|
weight: z.ZodNumber;
|
|
60
60
|
evidence: z.ZodArray<z.ZodString, "many">;
|
|
@@ -64,7 +64,7 @@ export declare const AutomationMaturitySchema: z.ZodObject<{
|
|
|
64
64
|
guidance: z.ZodOptional<z.ZodString>;
|
|
65
65
|
}, "strip", z.ZodTypeAny, {
|
|
66
66
|
recommendations: string[];
|
|
67
|
-
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio";
|
|
67
|
+
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio" | "api-test-coverage";
|
|
68
68
|
score: number;
|
|
69
69
|
weight: number;
|
|
70
70
|
evidence: string[];
|
|
@@ -73,7 +73,7 @@ export declare const AutomationMaturitySchema: z.ZodObject<{
|
|
|
73
73
|
guidance?: string | undefined;
|
|
74
74
|
}, {
|
|
75
75
|
recommendations: string[];
|
|
76
|
-
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio";
|
|
76
|
+
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio" | "api-test-coverage";
|
|
77
77
|
score: number;
|
|
78
78
|
weight: number;
|
|
79
79
|
evidence: string[];
|
|
@@ -91,7 +91,7 @@ export declare const AutomationMaturitySchema: z.ZodObject<{
|
|
|
91
91
|
overallScore: number;
|
|
92
92
|
dimensions: {
|
|
93
93
|
recommendations: string[];
|
|
94
|
-
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio";
|
|
94
|
+
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio" | "api-test-coverage";
|
|
95
95
|
score: number;
|
|
96
96
|
weight: number;
|
|
97
97
|
evidence: string[];
|
|
@@ -109,7 +109,7 @@ export declare const AutomationMaturitySchema: z.ZodObject<{
|
|
|
109
109
|
overallScore: number;
|
|
110
110
|
dimensions: {
|
|
111
111
|
recommendations: string[];
|
|
112
|
-
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio";
|
|
112
|
+
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio" | "api-test-coverage";
|
|
113
113
|
score: number;
|
|
114
114
|
weight: number;
|
|
115
115
|
evidence: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"automation-maturity.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/automation-maturity.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qCAAqC,wDAIhD,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"automation-maturity.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/automation-maturity.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qCAAqC,wDAIhD,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiB5C,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASnC,CAAC;AAEH,MAAM,MAAM,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qCAAqC,CAAC,CAAC;AACpG,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAC5F,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
|