@jterrazz/test 16.1.1 → 17.0.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 +45 -171
- package/dist/browser/index.js +2 -2980
- package/dist/browser/services.js +2 -0
- package/dist/browser/stubs.js +2 -0
- package/dist/checker.d.ts +6 -1
- package/dist/checker.js +4534 -2628
- package/dist/config.d.ts +40 -0
- package/dist/config.js +309 -0
- package/dist/in-place.global-setup.d.ts +11 -0
- package/dist/in-place.global-setup.js +21 -0
- package/dist/index.d.ts +1653 -3004
- package/dist/index.js +5226 -3845
- package/dist/mobile-session.global-setup.d.ts +14 -0
- package/dist/mobile-session.global-setup.js +31 -0
- package/dist/oxlint.cjs +6069 -5634
- package/dist/oxlint.d.cts +43 -7212
- package/dist/oxlint.d.ts +43 -7212
- package/dist/oxlint.js +6127 -5693
- package/dist/route-coverage.global-setup.d.ts +42 -0
- package/dist/route-coverage.global-setup.js +2 -0
- package/dist/services.d.ts +3 -0
- package/dist/services.global-setup.d.ts +43 -0
- package/dist/services.global-setup.js +2 -0
- package/dist/services.js +597 -0
- package/dist/shared-appium.adapter.js +428 -0
- package/dist/shared-artifacts.js +32 -0
- package/dist/shared-chapter.js +7 -0
- package/dist/shared-container.port.d.ts +31 -0
- package/dist/shared-derived-projects.js +58 -0
- package/dist/shared-device.port.d.ts +189 -0
- package/dist/shared-exchange.js +447 -0
- package/dist/shared-in-place.js +172 -0
- package/dist/shared-index.browser.js +3191 -0
- package/dist/shared-index.services.d.ts +346 -0
- package/dist/shared-index.stubs.d.ts +287 -0
- package/dist/shared-json-shape.js +17 -0
- package/dist/shared-landmarks.js +71 -0
- package/dist/shared-ledger.js +68 -0
- package/dist/shared-literate-plugin.js +183 -0
- package/dist/shared-manifest.js +1321 -0
- package/dist/shared-pause.js +11 -0
- package/dist/shared-peer.js +88 -0
- package/dist/shared-playwright.adapter.js +330 -0
- package/dist/shared-process.adapter.js +74 -0
- package/dist/shared-refusal.js +35 -0
- package/dist/shared-resolve.js +24 -0
- package/dist/shared-route-coverage.global-setup.js +187 -0
- package/dist/shared-scenario-failure.js +198 -0
- package/dist/shared-serve.js +365 -0
- package/dist/shared-service-images.js +10 -0
- package/dist/shared-services.global-setup.js +179 -0
- package/dist/shared-session-ledger.js +301 -0
- package/dist/shared-setup-entry.js +12 -0
- package/dist/shared-source-scan.js +133 -0
- package/dist/shared-spec-document.js +365 -0
- package/dist/shared-specifications.js +26 -0
- package/dist/shared-stream-body.js +130 -0
- package/dist/shared-stub-server.js +190 -0
- package/dist/shared-temp-root.global-setup.js +80 -0
- package/dist/shared-test-baseline.js +26 -0
- package/dist/shared-test-section.js +58 -0
- package/dist/shared-testcontainers.adapter.js +203 -0
- package/dist/shared-tokens.js +55 -0
- package/dist/shared-yaml-document.js +119 -0
- package/dist/stubs.d.ts +2 -0
- package/dist/stubs.js +657 -0
- package/dist/temp-root.global-setup.d.ts +7 -0
- package/dist/temp-root.global-setup.js +2 -0
- package/dist/vitest.d.ts +97 -163
- package/dist/vitest.js +373 -525
- package/docs/README.md +82 -36
- package/docs/concepts/architecture.md +118 -0
- package/docs/concepts/conventions.md +333 -0
- package/docs/guides/api-specs.md +374 -0
- package/docs/guides/cli-specs.md +564 -0
- package/docs/guides/component-specs.md +252 -0
- package/docs/guides/develop.md +94 -0
- package/docs/guides/integration-specs.md +181 -0
- package/docs/guides/job-specs.md +180 -0
- package/docs/guides/lint-specs.md +174 -0
- package/docs/guides/mobile-specs.md +319 -0
- package/docs/guides/module-tests.md +149 -0
- package/docs/guides/release.md +43 -0
- package/docs/guides/spec-documents.md +189 -0
- package/docs/guides/website-specs.md +413 -0
- package/docs/reference/assertions.md +345 -0
- package/docs/reference/glossary.md +20 -0
- package/docs/reference/linting.md +483 -0
- package/docs/reference/services.md +236 -0
- package/docs/reference/stubs.md +498 -0
- package/docs/reference/time-and-doubles.md +137 -0
- package/docs/reference/tokens.md +258 -0
- package/docs/reference/visitor.md +221 -0
- package/docs/start/getting-started.md +187 -0
- package/docs/start/set-up-a-project.md +214 -0
- package/package.json +50 -30
- package/schema/spec.schema.json +43 -17
- package/dist/appium.adapter.js +0 -489
- package/dist/artifacts.js +0 -32
- package/dist/fixtures.js +0 -110
- package/dist/literate.js +0 -1747
- package/dist/match.js +0 -804
- package/dist/playwright.adapter.js +0 -438
- package/dist/server.js +0 -160
- package/dist/stream.js +0 -321
- package/dist/substring-warning.js +0 -282
- package/docs/01-architecture.md +0 -95
- package/docs/02-developing.md +0 -351
- package/docs/03-testing.md +0 -495
- package/docs/04-operating.md +0 -101
- package/docs/05-module-tests.md +0 -152
- package/docs/06-integration.md +0 -180
- package/docs/07-component.md +0 -246
- package/docs/08-website.md +0 -404
- package/docs/09-mobile.md +0 -270
- package/docs/10-api.md +0 -264
- package/docs/11-jobs.md +0 -157
- package/docs/12-cli.md +0 -677
- package/docs/13-elements.md +0 -248
- package/docs/14-assertions.md +0 -314
- package/docs/15-tokens.md +0 -253
- package/docs/16-contracts.md +0 -438
- package/docs/17-services.md +0 -188
- package/docs/18-conventions.md +0 -332
- package/docs/19-linting.md +0 -512
- package/docs/decisions/001-v9-conventions-on-three-channels.md +0 -50
- package/docs/decisions/002-the-statique-channel-holds-only-what-upstream-does-not.md +0 -49
- package/docs/decisions/003-a-rendered-component-is-a-facet-on-vitest-browser-mode.md +0 -84
- package/docs/decisions/004-a-module-against-real-services-or-a-golden-is-the-integration-facet.md +0 -81
- package/docs/decisions/005-the-doubles-ladder-is-closed.md +0 -86
- package/docs/decisions/006-the-catalogue-reaches-a-file-by-its-role.md +0 -245
- package/docs/decisions/007-compose-mode-leaves-the-package.md +0 -53
- package/docs/decisions/008-vitest-5-node-24-and-the-native-seams-as-optional-peers.md +0 -75
- package/docs/decisions/_template.md +0 -22
- package/docs/reference/classes/Matcher.md +0 -120
- package/docs/reference/classes/ProcessHandle.md +0 -368
- package/docs/reference/functions/defineContract.md +0 -39
- package/docs/reference/functions/defineContracts.md +0 -36
- package/docs/reference/functions/disabled.md +0 -28
- package/docs/reference/functions/enabled.md +0 -20
- package/docs/reference/functions/focused.md +0 -26
- package/docs/reference/functions/mockOf.md +0 -79
- package/docs/reference/functions/postgres.md +0 -31
- package/docs/reference/functions/process.md +0 -33
- package/docs/reference/functions/redis.md +0 -28
- package/docs/reference/functions/required.md +0 -41
- package/docs/reference/functions/selected.md +0 -26
- package/docs/reference/functions/sqlite.md +0 -33
- package/docs/reference/functions/testId.md +0 -20
- package/docs/reference/functions/text.md +0 -40
- package/docs/reference/functions/valued.md +0 -28
- package/docs/reference/functions/waitUntil.md +0 -46
- package/docs/reference/functions/within.md +0 -29
- package/docs/reference/index.md +0 -196
- package/docs/reference/interfaces/BaseResult.md +0 -87
- package/docs/reference/interfaces/CallResult.md +0 -160
- package/docs/reference/interfaces/CaptureScope.md +0 -82
- package/docs/reference/interfaces/CliResult.md +0 -253
- package/docs/reference/interfaces/ContainerAccessor.md +0 -166
- package/docs/reference/interfaces/DirectoryAccessor.md +0 -33
- package/docs/reference/interfaces/FetchResult.md +0 -180
- package/docs/reference/interfaces/FilesystemAccessor.md +0 -46
- package/docs/reference/interfaces/HttpResult.md +0 -126
- package/docs/reference/interfaces/JsonAccessor.md +0 -46
- package/docs/reference/interfaces/PageResult.md +0 -356
- package/docs/reference/interfaces/RenderResult.md +0 -72
- package/docs/reference/interfaces/RenderedText.md +0 -110
- package/docs/reference/interfaces/ResponseAccessor.md +0 -47
- package/docs/reference/interfaces/ScreenResult.md +0 -128
- package/docs/reference/interfaces/TableAccessor.md +0 -26
- package/docs/reference/interfaces/TextAccessor.md +0 -96
- package/docs/reference/type-aliases/ApiHandle.md +0 -68
- package/docs/reference/type-aliases/ApiSpecification.md +0 -213
- package/docs/reference/type-aliases/ApiSpecificationOptions.md +0 -68
- package/docs/reference/type-aliases/BrowserConsoleMessage.md +0 -30
- package/docs/reference/type-aliases/BrowserLinkElement.md +0 -50
- package/docs/reference/type-aliases/BrowserMetaElement.md +0 -40
- package/docs/reference/type-aliases/BrowserOpenOptions.md +0 -87
- package/docs/reference/type-aliases/BrowserPage.md +0 -132
- package/docs/reference/type-aliases/BrowserPort.md +0 -51
- package/docs/reference/type-aliases/CliEnv.md +0 -11
- package/docs/reference/type-aliases/CliHandle.md +0 -80
- package/docs/reference/type-aliases/CliInput.md +0 -36
- package/docs/reference/type-aliases/CliOutput.md +0 -46
- package/docs/reference/type-aliases/CliPort.md +0 -58
- package/docs/reference/type-aliases/CliSpecification.md +0 -144
- package/docs/reference/type-aliases/CliSpecificationOptions.md +0 -134
- package/docs/reference/type-aliases/ComponentChain.md +0 -156
- package/docs/reference/type-aliases/ComponentScenario.md +0 -20
- package/docs/reference/type-aliases/ComponentUi.md +0 -47
- package/docs/reference/type-aliases/ComponentVisitor.md +0 -10
- package/docs/reference/type-aliases/ContainerPort.md +0 -113
- package/docs/reference/type-aliases/Contract.md +0 -68
- package/docs/reference/type-aliases/ContractInput.md +0 -13
- package/docs/reference/type-aliases/ContractRequest.md +0 -95
- package/docs/reference/type-aliases/ContractResponder.md +0 -23
- package/docs/reference/type-aliases/ContractResponse.md +0 -78
- package/docs/reference/type-aliases/ContractResponseValue.md +0 -13
- package/docs/reference/type-aliases/Contracts.md +0 -48
- package/docs/reference/type-aliases/DatabaseKeys.md +0 -16
- package/docs/reference/type-aliases/DatabasePort.md +0 -72
- package/docs/reference/type-aliases/DeviceOpenOptions.md +0 -46
- package/docs/reference/type-aliases/DevicePort.md +0 -51
- package/docs/reference/type-aliases/DeviceScreen.md +0 -32
- package/docs/reference/type-aliases/DeviceTimeouts.md +0 -39
- package/docs/reference/type-aliases/DockerSpecConfig.md +0 -43
- package/docs/reference/type-aliases/DomMount.md +0 -21
- package/docs/reference/type-aliases/ElementKind.md +0 -27
- package/docs/reference/type-aliases/ElementMatch.md +0 -74
- package/docs/reference/type-aliases/ElementOptions.md +0 -29
- package/docs/reference/type-aliases/ElementRef.md +0 -128
- package/docs/reference/type-aliases/ExecOptions.md +0 -37
- package/docs/reference/type-aliases/FileAccessor.md +0 -54
- package/docs/reference/type-aliases/HonoApp.md +0 -31
- package/docs/reference/type-aliases/HttpContractFilter.md +0 -49
- package/docs/reference/type-aliases/HttpResponseInit.md +0 -46
- package/docs/reference/type-aliases/HttpStreamInit.md +0 -58
- package/docs/reference/type-aliases/IntegrationHandle.md +0 -46
- package/docs/reference/type-aliases/IntegrationSpecification.md +0 -111
- package/docs/reference/type-aliases/IntegrationSpecificationOptions.md +0 -42
- package/docs/reference/type-aliases/Intercept.md +0 -19
- package/docs/reference/type-aliases/InterceptOptions.md +0 -28
- package/docs/reference/type-aliases/InterceptScope.md +0 -11
- package/docs/reference/type-aliases/IsolationStrategy.md +0 -75
- package/docs/reference/type-aliases/JobHandle.md +0 -34
- package/docs/reference/type-aliases/JobsHandle.md +0 -57
- package/docs/reference/type-aliases/JobsResult.md +0 -16
- package/docs/reference/type-aliases/JobsSpecification.md +0 -94
- package/docs/reference/type-aliases/JobsSpecificationOptions.md +0 -56
- package/docs/reference/type-aliases/LandmarkKind.md +0 -20
- package/docs/reference/type-aliases/LiterateRunFlags.md +0 -27
- package/docs/reference/type-aliases/LiterateServeRegistration.md +0 -70
- package/docs/reference/type-aliases/MatchFixtureOptions.md +0 -27
- package/docs/reference/type-aliases/MatchableRequest.md +0 -61
- package/docs/reference/type-aliases/MatcherKind.md +0 -34
- package/docs/reference/type-aliases/MobileBackendOptions.md +0 -28
- package/docs/reference/type-aliases/MobileElementKind.md +0 -14
- package/docs/reference/type-aliases/MobileElementMatch.md +0 -60
- package/docs/reference/type-aliases/MobileElementRef.md +0 -20
- package/docs/reference/type-aliases/MobileHandle.md +0 -65
- package/docs/reference/type-aliases/MobileScenario.md +0 -20
- package/docs/reference/type-aliases/MobileSpecification.md +0 -51
- package/docs/reference/type-aliases/MobileSpecificationOptions.md +0 -126
- package/docs/reference/type-aliases/MobileVisitor.md +0 -81
- package/docs/reference/type-aliases/MockOfOptions.md +0 -26
- package/docs/reference/type-aliases/MockPort.md +0 -10
- package/docs/reference/type-aliases/PinnedClock.md +0 -10
- package/docs/reference/type-aliases/PostgresOptions.md +0 -32
- package/docs/reference/type-aliases/ProcessOptions.md +0 -112
- package/docs/reference/type-aliases/RedisOptions.md +0 -20
- package/docs/reference/type-aliases/RenderSubject.md +0 -12
- package/docs/reference/type-aliases/ScreenNode.md +0 -67
- package/docs/reference/type-aliases/ServerPort.md +0 -36
- package/docs/reference/type-aliases/ServerResponse.md +0 -46
- package/docs/reference/type-aliases/ServerSpec.md +0 -21
- package/docs/reference/type-aliases/ServiceHandle.md +0 -216
- package/docs/reference/type-aliases/ServiceRecord.md +0 -12
- package/docs/reference/type-aliases/SpecDocument.md +0 -84
- package/docs/reference/type-aliases/SpecEnvToken.md +0 -21
- package/docs/reference/type-aliases/SpecFileAssertion.md +0 -27
- package/docs/reference/type-aliases/SpecFixture.md +0 -30
- package/docs/reference/type-aliases/SpecKind.md +0 -8
- package/docs/reference/type-aliases/SpecRun.md +0 -108
- package/docs/reference/type-aliases/SpecServeEntry.md +0 -40
- package/docs/reference/type-aliases/SpecStream.md +0 -32
- package/docs/reference/type-aliases/SpecificationConfig.md +0 -290
- package/docs/reference/type-aliases/SqliteOptions.md +0 -36
- package/docs/reference/type-aliases/SseEvent.md +0 -58
- package/docs/reference/type-aliases/StreamBody.md +0 -61
- package/docs/reference/type-aliases/TextFilter.md +0 -22
- package/docs/reference/type-aliases/VisitScenario.md +0 -20
- package/docs/reference/type-aliases/Visitor.md +0 -215
- package/docs/reference/type-aliases/WaitUntilOptions.md +0 -46
- package/docs/reference/type-aliases/WebsiteBackendOptions.md +0 -37
- package/docs/reference/type-aliases/WebsiteHandle.md +0 -51
- package/docs/reference/type-aliases/WebsiteSpecification.md +0 -118
- package/docs/reference/type-aliases/WebsiteSpecificationOptions.md +0 -40
- package/docs/reference/variables/anthropic.md +0 -19
- package/docs/reference/variables/banner.md +0 -10
- package/docs/reference/variables/button.md +0 -10
- package/docs/reference/variables/clock.md +0 -16
- package/docs/reference/variables/complementary.md +0 -10
- package/docs/reference/variables/component.md +0 -10
- package/docs/reference/variables/content.md +0 -10
- package/docs/reference/variables/contentinfo.md +0 -10
- package/docs/reference/variables/dialog.md +0 -10
- package/docs/reference/variables/field.md +0 -10
- package/docs/reference/variables/form.md +0 -10
- package/docs/reference/variables/heading.md +0 -10
- package/docs/reference/variables/http.md +0 -40
- package/docs/reference/variables/intercept.md +0 -11
- package/docs/reference/variables/link.md +0 -10
- package/docs/reference/variables/listitem.md +0 -10
- package/docs/reference/variables/main.md +0 -10
- package/docs/reference/variables/match.md +0 -8
- package/docs/reference/variables/navigation.md +0 -10
- package/docs/reference/variables/openai.md +0 -21
- package/docs/reference/variables/option.md +0 -17
- package/docs/reference/variables/region.md +0 -10
- package/docs/reference/variables/row.md +0 -10
- package/docs/reference/variables/search.md +0 -10
- package/docs/reference/variables/specification.md +0 -8
- package/docs/reference/variables/status.md +0 -10
- package/docs/reference/variables/table.md +0 -10
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//#region src/visitor/targets/roles.ts
|
|
2
|
+
const stated = (options) => options?.exact === void 0 ? {} : { exact: options.exact };
|
|
3
|
+
const named = (kind) => (name, options) => ({
|
|
4
|
+
kind,
|
|
5
|
+
name,
|
|
6
|
+
...stated(options)
|
|
7
|
+
});
|
|
8
|
+
const optionallyNamed = (kind) => (name, options) => ({
|
|
9
|
+
kind,
|
|
10
|
+
...name === void 0 ? {} : { name },
|
|
11
|
+
...stated(options)
|
|
12
|
+
});
|
|
13
|
+
/** A button (or element with the button role), by accessible name. */
|
|
14
|
+
const button = named("button");
|
|
15
|
+
/** A form field, by label. */
|
|
16
|
+
const field = named("field");
|
|
17
|
+
/** A heading, by accessible name. */
|
|
18
|
+
const heading = named("heading");
|
|
19
|
+
/** A link, by accessible name. */
|
|
20
|
+
const link = named("link");
|
|
21
|
+
/** An element containing the given text. */
|
|
22
|
+
const content = named("text");
|
|
23
|
+
/** An option of a select or listbox, by label; asserted by presence, since a collapsed select's options have no box. */
|
|
24
|
+
const option = named("option");
|
|
25
|
+
/** A modal or non-modal `<dialog>`, by accessible name. A closed one is absent. */
|
|
26
|
+
const dialog = optionallyNamed("dialog");
|
|
27
|
+
/** A live region announcing a result: `role="status"`, an `<output>`. */
|
|
28
|
+
const status = optionallyNamed("status");
|
|
29
|
+
/** A table, by its caption or accessible name. */
|
|
30
|
+
const table = optionallyNamed("table");
|
|
31
|
+
/** A row of a table or grid, by the text of its cells. */
|
|
32
|
+
const row = optionallyNamed("row");
|
|
33
|
+
/** An item of a list, by its text. */
|
|
34
|
+
const listitem = optionallyNamed("listitem");
|
|
35
|
+
/** The escape hatch: an element by `data-testid`. Prefer user-facing targets. */
|
|
36
|
+
const testId = (id) => ({
|
|
37
|
+
kind: "testId",
|
|
38
|
+
name: id
|
|
39
|
+
});
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/visitor/targets/landmarks.ts
|
|
42
|
+
/** The `banner` landmark: the page header. */
|
|
43
|
+
const banner = optionallyNamed("banner");
|
|
44
|
+
/** The `complementary` landmark: an `<aside>`, a sidebar. */
|
|
45
|
+
const complementary = optionallyNamed("complementary");
|
|
46
|
+
/** The `contentinfo` landmark: the page footer. */
|
|
47
|
+
const contentinfo = optionallyNamed("contentinfo");
|
|
48
|
+
/** The `form` landmark: a form carrying an accessible name. */
|
|
49
|
+
const form = optionallyNamed("form");
|
|
50
|
+
/** The `main` landmark: the primary content of the document. */
|
|
51
|
+
const main = optionallyNamed("main");
|
|
52
|
+
/** The `navigation` landmark: a `<nav>`. Name it when a page has several. */
|
|
53
|
+
const navigation = optionallyNamed("navigation");
|
|
54
|
+
/** The `region` landmark: a `<section>` carrying an accessible name. */
|
|
55
|
+
const region = optionallyNamed("region");
|
|
56
|
+
/** The `search` landmark. */
|
|
57
|
+
const search = optionallyNamed("search");
|
|
58
|
+
/** Restrict a target to the inside of another: `click(within(navigation(), link('Articles')))`. */
|
|
59
|
+
const within = (scope, target) => ({
|
|
60
|
+
...target,
|
|
61
|
+
scope: target.scope ? within(scope, target.scope) : scope
|
|
62
|
+
});
|
|
63
|
+
function scopeChain(target) {
|
|
64
|
+
const chain = [];
|
|
65
|
+
for (let current = target; current; current = current.scope) chain.unshift(current);
|
|
66
|
+
return chain;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { testId as S, listitem as _, main as a, status as b, scopeChain as c, button as d, content as f, link as g, heading as h, form as i, search as l, field as m, complementary as n, navigation as o, dialog as p, contentinfo as r, region as s, banner as t, within as u, option as v, table as x, row as y };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=shared-landmarks.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { t as isRecord } from "./shared-json-shape.js";
|
|
2
|
+
import { l as VITEST_ARTIFACTS_DIR } from "./shared-artifacts.js";
|
|
3
|
+
import { mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
//#region src/expectations/in-place/update.ts
|
|
7
|
+
/** `TEST_UPDATE=1` or vitest's `-u` / `--update`. */
|
|
8
|
+
function shouldUpdateSnapshots() {
|
|
9
|
+
if (process.env.TEST_UPDATE === "1") return true;
|
|
10
|
+
return process.argv.includes("-u") || process.argv.includes("--update");
|
|
11
|
+
}
|
|
12
|
+
const UPDATE_HINT = "Run with TEST_UPDATE=1 (or vitest -u) to create it.";
|
|
13
|
+
const FROZEN_HINT = "This golden is `{ frozen }`: update mode never writes it. Write the file by hand, or drop `{ frozen }` for one TEST_UPDATE=1 run and put it back.";
|
|
14
|
+
function missingHint(frozen) {
|
|
15
|
+
return frozen ? FROZEN_HINT : UPDATE_HINT;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/specifications/api/routes/ledger.ts
|
|
19
|
+
const isLedger = (value) => isRecord(value) && Array.isArray(value.reached) && (value.declared === void 0 || Array.isArray(value.declared));
|
|
20
|
+
function entriesOf(directory) {
|
|
21
|
+
try {
|
|
22
|
+
return readdirSync(directory, { withFileTypes: true });
|
|
23
|
+
} catch {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const ROUTES_DIR = `${VITEST_ARTIFACTS_DIR}/routes`;
|
|
28
|
+
function shardLedgersDir(shard) {
|
|
29
|
+
return `${ROUTES_DIR}/shard-${shard.index}-${shard.count}`;
|
|
30
|
+
}
|
|
31
|
+
function clearLedgers(directory) {
|
|
32
|
+
rmSync(directory, {
|
|
33
|
+
force: true,
|
|
34
|
+
recursive: true
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function writeLedger(directory, ledger) {
|
|
38
|
+
mkdirSync(directory, { recursive: true });
|
|
39
|
+
writeFileSync(join(directory, `${randomUUID()}.json`), `${JSON.stringify(ledger)}\n`);
|
|
40
|
+
}
|
|
41
|
+
const parsed = (path) => JSON.parse(readFileSync(path, "utf8"));
|
|
42
|
+
function readLedgers(directory) {
|
|
43
|
+
return entriesOf(directory).filter((entry) => entry.name.endsWith(".json")).map((entry) => parsed(join(directory, entry.name))).filter((ledger) => isLedger(ledger));
|
|
44
|
+
}
|
|
45
|
+
const PARTIAL_MARK = "partial";
|
|
46
|
+
function markPartial(directory) {
|
|
47
|
+
mkdirSync(directory, { recursive: true });
|
|
48
|
+
writeFileSync(join(directory, PARTIAL_MARK), "");
|
|
49
|
+
}
|
|
50
|
+
function measure(ledgers) {
|
|
51
|
+
const tables = ledgers.map((ledger) => ledger.declared);
|
|
52
|
+
return {
|
|
53
|
+
declared: tables.every((table) => table !== void 0) ? tables.flat() : void 0,
|
|
54
|
+
reached: ledgers.flatMap((ledger) => ledger.reached)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function routesLedger() {
|
|
58
|
+
try {
|
|
59
|
+
const { inject } = await import("vitest");
|
|
60
|
+
return inject("routesLedger");
|
|
61
|
+
} catch {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { readLedgers as a, writeLedger as c, measure as i, missingHint as l, clearLedgers as n, routesLedger as o, markPartial as r, shardLedgersDir as s, ROUTES_DIR as t, shouldUpdateSnapshots as u };
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=shared-ledger.js.map
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { n as refusal } from "./shared-refusal.js";
|
|
2
|
+
import { d as isRelativePath, i as readSpecFile, l as SpecSyntaxError, u as dedent } from "./shared-spec-document.js";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { basename, isAbsolute, resolve } from "node:path";
|
|
5
|
+
//#region src/disk/spec-path.ts
|
|
6
|
+
const DISK_KEY = "@jterrazz/test:disk";
|
|
7
|
+
const DISK = Symbol.for(DISK_KEY);
|
|
8
|
+
/** Name one file, by its path from the spec file. */
|
|
9
|
+
function file(path) {
|
|
10
|
+
requireRelativePath("file", path);
|
|
11
|
+
if (path.endsWith("/")) {
|
|
12
|
+
const bare = path.replace(/\/+$/u, "");
|
|
13
|
+
throw new TypeError(refusal("disk-named-by-relative-path-at-runtime", {
|
|
14
|
+
fix: `name the directory with directory(${JSON.stringify(path)}), or the file without its /: file(${JSON.stringify(bare)})`,
|
|
15
|
+
found: `file(${JSON.stringify(path)}), a path ending in /, which is a directory's`
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
return diskValue("file", path);
|
|
19
|
+
}
|
|
20
|
+
function diskValue(brand, path) {
|
|
21
|
+
const value = {
|
|
22
|
+
[DISK]: brand,
|
|
23
|
+
path
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(value, Symbol.match, { value: () => {
|
|
26
|
+
throw new TypeError(refusal("one-verb-per-meaning", {
|
|
27
|
+
fix: `wrap the string to golden it, \`expect(text(value)).toMatch(${brand}(...))\`, or compare it to a value, \`toMatch('...')\``,
|
|
28
|
+
found: `toMatch(${brand}(${JSON.stringify(path)})) on a string, a value with no golden`
|
|
29
|
+
}));
|
|
30
|
+
} });
|
|
31
|
+
return Object.freeze(value);
|
|
32
|
+
}
|
|
33
|
+
/** Name one directory, by its path from the spec file, ending in `/`. */
|
|
34
|
+
function directory(path) {
|
|
35
|
+
requireRelativePath("directory", path);
|
|
36
|
+
if (!path.endsWith("/")) throw new TypeError(refusal("disk-named-by-relative-path-at-runtime", {
|
|
37
|
+
fix: `end it in /: directory(${JSON.stringify(`${path}/`)}), or name a file with file(${JSON.stringify(path)})`,
|
|
38
|
+
found: `directory(${JSON.stringify(path)}), a path that does not end in /`
|
|
39
|
+
}));
|
|
40
|
+
return diskValue("directory", path);
|
|
41
|
+
}
|
|
42
|
+
function isDiskFile(value) {
|
|
43
|
+
return brandOf(value) === "file";
|
|
44
|
+
}
|
|
45
|
+
function isDiskDirectory(value) {
|
|
46
|
+
return brandOf(value) === "directory";
|
|
47
|
+
}
|
|
48
|
+
function isDiskTarget(value) {
|
|
49
|
+
return brandOf(value) !== void 0;
|
|
50
|
+
}
|
|
51
|
+
function brandOf(value) {
|
|
52
|
+
if (value === null || typeof value !== "object") return;
|
|
53
|
+
const brand = Reflect.get(value, DISK);
|
|
54
|
+
return brand === "file" || brand === "directory" ? brand : void 0;
|
|
55
|
+
}
|
|
56
|
+
function spelled(value) {
|
|
57
|
+
if (isDiskTarget(value)) return `${brandOf(value)}(${JSON.stringify(value.path)})`;
|
|
58
|
+
return typeof value === "string" ? JSON.stringify(value) : String(value);
|
|
59
|
+
}
|
|
60
|
+
function requireDiskFile(verb, value, extension = "") {
|
|
61
|
+
if (!isDiskFile(value)) throw new TypeError(refusal("disk-named-by-relative-path-at-runtime", {
|
|
62
|
+
fix: `name one file: ${verb}(file('./${exampleOf(verb, extension)}'))`,
|
|
63
|
+
found: isDiskDirectory(value) ? `${verb}(${spelled(value)}), a directory where one file is read` : `${verb}(${spelled(value)}), a value where a file is read`
|
|
64
|
+
}));
|
|
65
|
+
if (!value.path.endsWith(extension)) throw new TypeError(refusal("disk-named-by-relative-path-at-runtime", {
|
|
66
|
+
fix: `name the ${extension} file ${verb}() reads: ${verb}(file('./${exampleOf(verb, extension)}'))`,
|
|
67
|
+
found: `${verb}(${spelled(value)}), a file not ending in ${extension}`
|
|
68
|
+
}));
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
function requireDiskTarget(verb, value) {
|
|
72
|
+
if (!isDiskTarget(value)) throw new TypeError(refusal("disk-named-by-relative-path-at-runtime", {
|
|
73
|
+
fix: `name the disk: ${verb}(file('./<path>')) for a file, ${verb}(directory('./<path>/')) for a directory`,
|
|
74
|
+
found: `${verb}(${spelled(value)}), a value where the disk is read`
|
|
75
|
+
}));
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
function exampleOf(verb, extension) {
|
|
79
|
+
return {
|
|
80
|
+
fixture: "__fixtures__/config.json",
|
|
81
|
+
request: "__requests__/create.http",
|
|
82
|
+
run: "case.spec.yaml",
|
|
83
|
+
seed: "__seeds__/rows.sql"
|
|
84
|
+
}[verb] ?? `__expected__/output${extension || ".txt"}`;
|
|
85
|
+
}
|
|
86
|
+
function asRelative(path) {
|
|
87
|
+
const bare = typeof path === "string" ? path.replace(/^\/+/u, "") : "";
|
|
88
|
+
return `./${bare === "" ? "__expected__/output.txt" : bare}`;
|
|
89
|
+
}
|
|
90
|
+
function requireRelativePath(call, path) {
|
|
91
|
+
if (typeof path !== "string" || !isRelativePath(path)) throw new TypeError(refusal("disk-named-by-relative-path-at-runtime", {
|
|
92
|
+
fix: `start it with ./ or ../, from the spec file: ${call}('${asRelative(path)}')`,
|
|
93
|
+
found: `${call}(${JSON.stringify(path)}), a path that is not relative to the spec file`
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/disk/resolved-spec-path.ts
|
|
98
|
+
function resolveSpecPath(verb, path, specDir) {
|
|
99
|
+
requireRelativePath(verb, path);
|
|
100
|
+
return resolve(specDir, path);
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/expectations/in-place/render.ts
|
|
104
|
+
function escapeTemplate(text) {
|
|
105
|
+
return text.replaceAll("\\", String.raw`\\`).replaceAll("`", "\\`").replaceAll("${", "\\${");
|
|
106
|
+
}
|
|
107
|
+
function renderText(text, indent) {
|
|
108
|
+
if (!text.includes("\n")) return `\`${escapeTemplate(text)}\``;
|
|
109
|
+
const inner = `${indent} `;
|
|
110
|
+
const lines = text.split("\n");
|
|
111
|
+
const last = String(lines.pop());
|
|
112
|
+
const block = `\n${lines.map((line) => line === "" ? "" : `${inner}${line}`).join("\n")}\n${last === "" ? indent : `${inner}${last}`}`;
|
|
113
|
+
return dedent(block) === text ? `\`${escapeTemplate(block)}\`` : JSON.stringify(text);
|
|
114
|
+
}
|
|
115
|
+
const NUMBER_MARK = "@@in-place-number:";
|
|
116
|
+
const GROUPED_FROM = 1e4;
|
|
117
|
+
function grouped(value) {
|
|
118
|
+
return typeof value === "number" && Number.isSafeInteger(value) && Math.abs(value) >= GROUPED_FROM ? `${NUMBER_MARK}${String(value).replaceAll(/\B(?=(?:\d{3})+$)/gu, "_")}` : value;
|
|
119
|
+
}
|
|
120
|
+
const MARKED = new RegExp(`"${NUMBER_MARK}(?<digits>-?[\\d_]+)"`, "gu");
|
|
121
|
+
const literal = (value, space) => JSON.stringify(value, (_key, item) => grouped(item), space)?.replaceAll(MARKED, "$<digits>");
|
|
122
|
+
function renderValue(value, indent) {
|
|
123
|
+
return (literal(value, 4) ?? "undefined").split("\n").join(`\n${indent}`);
|
|
124
|
+
}
|
|
125
|
+
function renderRows(rows, indent) {
|
|
126
|
+
if (rows.length === 0) return "[]";
|
|
127
|
+
return `[\n${rows.map((row) => `${indent} [${row.map((cell) => literal(cell) ?? "null").join(", ")}],`).join("\n")}\n${indent}]`;
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/specifications/cli/documents/literate-plugin.ts
|
|
131
|
+
const SPEC_FILE = /\.spec\.yaml(?:\?.*)?$/u;
|
|
132
|
+
function grammarRefusal(error, displayPath) {
|
|
133
|
+
return new Error(refusal({
|
|
134
|
+
fix: "write the key the grammar names; the reason prints the accepted set",
|
|
135
|
+
found: `${displayPath}:${error.line}: ${error.reason}`,
|
|
136
|
+
read: "docs/reference/linting.md#document-follows-its-grammar",
|
|
137
|
+
why: "A spec document follows one grammar, read by the parser the runner and the linter share: closed keys, `description:` and `runs:` required, `command:` and `exit:` in every run."
|
|
138
|
+
}), { cause: error });
|
|
139
|
+
}
|
|
140
|
+
function readDocument(content, displayPath) {
|
|
141
|
+
try {
|
|
142
|
+
return readSpecFile(content, displayPath);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
throw error instanceof SpecSyntaxError ? grammarRefusal(error, displayPath) : error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function literateModule(content, filePath, runnerPath) {
|
|
148
|
+
const { description } = readDocument(content, filePath).document;
|
|
149
|
+
return [
|
|
150
|
+
"import { test } from 'vitest';",
|
|
151
|
+
`import { cli } from ${JSON.stringify(runnerPath)};`,
|
|
152
|
+
"",
|
|
153
|
+
`test(${JSON.stringify(description)}, async () => {`,
|
|
154
|
+
` await cli.run({ [Symbol.for(${JSON.stringify(DISK_KEY)})]: 'file', path: ${JSON.stringify(`./${basename(filePath)}`)} });`,
|
|
155
|
+
"});",
|
|
156
|
+
""
|
|
157
|
+
].join("\n");
|
|
158
|
+
}
|
|
159
|
+
function cleanId(id) {
|
|
160
|
+
return id.split("?")[0] ?? id;
|
|
161
|
+
}
|
|
162
|
+
function literate(options) {
|
|
163
|
+
const include = options.include ?? ["**/*.spec.yaml"];
|
|
164
|
+
let root = process.cwd();
|
|
165
|
+
return {
|
|
166
|
+
config: () => ({ test: { include } }),
|
|
167
|
+
configResolved: (resolved) => {
|
|
168
|
+
({root} = resolved);
|
|
169
|
+
},
|
|
170
|
+
enforce: "pre",
|
|
171
|
+
load: (id) => {
|
|
172
|
+
if (!SPEC_FILE.test(id)) return null;
|
|
173
|
+
const filePath = cleanId(id);
|
|
174
|
+
const runnerPath = isAbsolute(options.runner) ? options.runner : resolve(root, options.runner);
|
|
175
|
+
return literateModule(readFileSync(filePath, "utf8"), filePath, runnerPath);
|
|
176
|
+
},
|
|
177
|
+
name: "jterrazz-test:literate"
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
//#endregion
|
|
181
|
+
export { renderValue as a, file as c, isDiskTarget as d, requireDiskFile as f, renderText as i, isDiskDirectory as l, literate as n, resolveSpecPath as o, requireDiskTarget as p, renderRows as r, directory as s, grammarRefusal as t, isDiskFile as u };
|
|
182
|
+
|
|
183
|
+
//# sourceMappingURL=shared-literate-plugin.js.map
|