@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
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Preset } from "@jterrazz/typescript/config";
|
|
2
|
+
//#region lint/consumer/rulebook/preset.d.ts
|
|
3
|
+
declare function testPreset(): Preset;
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region lint/kit/project/settings.d.ts
|
|
6
|
+
/** The `test` section of `jterrazz.config.ts`. */
|
|
7
|
+
type TestSettings = {
|
|
8
|
+
/** The path every api route is mounted under (`'/api'`), left out of the folder each route's subject derives. */
|
|
9
|
+
basePath?: `/${string}`;
|
|
10
|
+
/** Api collections no English plural names (`data`, `people`), by route segment. */
|
|
11
|
+
collections?: readonly string[];
|
|
12
|
+
/** Routes the api takes on any method (`app.all('/mcp', ...)`), each path mapped to why it takes any. */
|
|
13
|
+
methodless?: Readonly<Record<string, string>>;
|
|
14
|
+
production?: {
|
|
15
|
+
allow: Readonly<Record<string, string>>;
|
|
16
|
+
};
|
|
17
|
+
/** How a project departs from the one its tree derives, keyed by its specification, with the reason. */
|
|
18
|
+
projects?: Readonly<Partial<Record<TestSpecification, TestProject>>>;
|
|
19
|
+
/** Path to an OpenAPI document (JSON or YAML) declaring the routes, when the app carries no route table. */
|
|
20
|
+
routes?: string;
|
|
21
|
+
/** The folders of `specs/` that hold specifications, each filing its specs under the subject they prove: `specs/<specification>/<subject>/`. */
|
|
22
|
+
specifications?: readonly string[];
|
|
23
|
+
};
|
|
24
|
+
/** The helpers a project is built by, named by their specification. */
|
|
25
|
+
type TestSpecification = 'api' | 'cli' | 'component' | 'integration' | 'job' | 'lint' | 'mobile' | 'unit' | 'website';
|
|
26
|
+
/** What a declared project states beyond its derived one: the global setups it runs, the options its helper takes, and why. */
|
|
27
|
+
type TestProject = {
|
|
28
|
+
readonly reason: string;
|
|
29
|
+
readonly setup?: readonly string[];
|
|
30
|
+
readonly [option: string]: unknown;
|
|
31
|
+
};
|
|
32
|
+
declare module '@jterrazz/typescript/config' {
|
|
33
|
+
interface JterrazzConfig {
|
|
34
|
+
/** What `@jterrazz/test` reads. */
|
|
35
|
+
test?: TestSettings;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { type TestProject, type TestSettings, type TestSpecification, testPreset as test };
|
|
40
|
+
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { t as isRecord } from "./shared-json-shape.js";
|
|
2
|
+
import { t as CATALOGUE_CHAPTER } from "./shared-chapter.js";
|
|
3
|
+
import { n as specificationModules, t as derivedProjects } from "./shared-derived-projects.js";
|
|
4
|
+
import { t as TEST_SECTION } from "./shared-test-section.js";
|
|
5
|
+
import { n as recommendedRules, t as consumerRows } from "./shared-manifest.js";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { RENAMED_FOLDERS, SETUP_FOLDER, SPECIAL_FOLDERS, declaredSubpaths, readAt, rowNamed, whyOf } from "@jterrazz/typescript/rules";
|
|
8
|
+
import { posix } from "node:path";
|
|
9
|
+
import { defineStandard } from "@jterrazz/typescript/config";
|
|
10
|
+
//#region src/standard/standard.ts
|
|
11
|
+
var standard_default = defineStandard({ test: {
|
|
12
|
+
specifications: [
|
|
13
|
+
"api",
|
|
14
|
+
"cli",
|
|
15
|
+
"component",
|
|
16
|
+
"integration",
|
|
17
|
+
"job",
|
|
18
|
+
"lint",
|
|
19
|
+
"mobile",
|
|
20
|
+
"website"
|
|
21
|
+
],
|
|
22
|
+
projects: { unit: {
|
|
23
|
+
isolate: false,
|
|
24
|
+
reason: "a module test leaves no state behind in a module, so a worker runs its files in one module graph"
|
|
25
|
+
} }
|
|
26
|
+
} });
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region lint/kit/project/loaded-packages.ts
|
|
29
|
+
const LOADED_BY = {
|
|
30
|
+
component: [
|
|
31
|
+
"@vitest/browser-playwright",
|
|
32
|
+
"playwright",
|
|
33
|
+
"vitest-browser-react"
|
|
34
|
+
],
|
|
35
|
+
mobile: ["appium", "webdriverio"],
|
|
36
|
+
website: ["@vitest/browser-playwright", "playwright"]
|
|
37
|
+
};
|
|
38
|
+
/** The peers the projects a tree names drive through this package, which the project declares and imports nowhere. */
|
|
39
|
+
function packagesLoadedFor(root) {
|
|
40
|
+
const projects = derivedProjects(root);
|
|
41
|
+
return Object.entries(LOADED_BY).flatMap(([project, names]) => projects.has(project) ? names : []);
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region lint/consumer/rulebook/import.ts
|
|
45
|
+
const importRulesForSpecifications = {
|
|
46
|
+
files: ["**/*.specification.ts"],
|
|
47
|
+
rules: { "import/exports-last": "off" }
|
|
48
|
+
};
|
|
49
|
+
/** Set in an override because a base profile turns the vitest plugin on in an override over the test globs, and an override's entry replaces a top-level one. */
|
|
50
|
+
const vitestOnTests = {
|
|
51
|
+
files: ["**/*.{test,spec,test-d,spec-d}.{ts,tsx,js,jsx}", "**/specs/**/*.{ts,tsx}"],
|
|
52
|
+
rules: {
|
|
53
|
+
"vitest/consistent-test-filename": ["error", { pattern: String.raw`.*\.(?:test\.[tj]sx?|spec\.[tj]s)$` }],
|
|
54
|
+
"vitest/max-nested-describe": ["error", { max: 1 }],
|
|
55
|
+
"vitest/no-restricted-matchers": ["error", {
|
|
56
|
+
toMatchAriaSnapshot: "The ARIA tree is a golden: `expect(result.tree).toMatch(file('./__expected__/<case>.aria.yaml'))`.",
|
|
57
|
+
toMatchFileSnapshot: "Name the file yourself: `expect(subject).toMatch(file('./__expected__/<case>.<ext>'))`.",
|
|
58
|
+
toMatchInlineSnapshot: "An inline snapshot is the run judging itself: `expect(subject).toMatch(file('./__expected__/<case>.<ext>'))`, or compare to a literal with `toStrictEqual`.",
|
|
59
|
+
toMatchScreenshot: "A screenshot is not a golden this dialect can read: assert the ARIA tree, the content, or the markup.",
|
|
60
|
+
toMatchSnapshot: "The golden is `expect(subject).toMatch(file('./__expected__/<name>.<ext>'))`, a path from the spec file; under `src/` compare to a literal with `toStrictEqual`.",
|
|
61
|
+
toThrowErrorMatchingInlineSnapshot: "State the message: `expect(fn).toThrow('<what the subject says>')`.",
|
|
62
|
+
toThrowErrorMatchingSnapshot: "State the message: `expect(fn).toThrow('<what the subject says>')`."
|
|
63
|
+
}],
|
|
64
|
+
"vitest/no-restricted-vi-methods": ["error", {
|
|
65
|
+
setSystemTime: "`vi.setSystemTime` gives way to `clock.at(iso)`, which gives the calendar back.",
|
|
66
|
+
stubGlobal: "`vi.stubGlobal('fetch')` gives way to `await using _ = await intercept(defineStubs(...))`; a subject that fetches a PATH states where it resolves: `intercept(stubs, { origin: 'http://<host>.test' })`.",
|
|
67
|
+
useFakeTimers: "`vi.useFakeTimers` gives way to `clock.at(iso)` and `clock.advance(ms)`.",
|
|
68
|
+
useRealTimers: "`vi.useRealTimers` gives way to nothing: `using` gives the clock back at the scope end."
|
|
69
|
+
}],
|
|
70
|
+
"vitest/prefer-lowercase-title": ["error", { ignoreTopLevelDescribe: true }]
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region lint/consumer/rulebook/preset.ts
|
|
75
|
+
function taughtBy(name) {
|
|
76
|
+
const row = rowNamed(consumerRows, name);
|
|
77
|
+
return {
|
|
78
|
+
read: readAt(row, CATALOGUE_CHAPTER),
|
|
79
|
+
why: whyOf(row)
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const escaped = (text) => text.replaceAll(/[.*+?^${}()|[\]\\]/gu, String.raw`\$&`);
|
|
83
|
+
const either = (patterns) => `(?:${patterns.map((pattern) => `(${pattern})`).join("|")})`;
|
|
84
|
+
const SOURCE = String.raw`\.[cm]?[jt]sx?$`;
|
|
85
|
+
const TEST_FILE = String.raw`\.(test\.[cm]?[jt]sx?|spec\.[cm]?[jt]s)$`;
|
|
86
|
+
const RUNS_A_TEST = String.raw`\.(test\.tsx?|spec\.ts|specification\.tsx?)$`;
|
|
87
|
+
function packages(names) {
|
|
88
|
+
return either(names.map((name) => {
|
|
89
|
+
const written = name.endsWith("*") ? `${escaped(name.slice(0, -1))}[^/]*` : escaped(name);
|
|
90
|
+
return String.raw`(^|/)node_modules/${written}([./]|$)|^${written}([./]|$)`;
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
const SEAMS = [
|
|
94
|
+
{
|
|
95
|
+
fix: "`component.render()` and the element vocabulary render in a real browser: the queries are the same nouns, and they run against what ships",
|
|
96
|
+
packages: ["@testing-library/*"],
|
|
97
|
+
seam: "renderer"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
fix: "a drawing of a browser proves what a browser does not: a rendered thing is a `.test.tsx` in the `__tests__/` of its component's folder, collected by `component()`",
|
|
101
|
+
packages: ["happy-dom", "jsdom"],
|
|
102
|
+
seam: "simulated-dom"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
fix: "Browser Mode is the seam, not the surface: `component.render()` owns the locators, the visitor and the ARIA tree",
|
|
106
|
+
packages: [
|
|
107
|
+
"vitest/browser",
|
|
108
|
+
"vitest-browser-*",
|
|
109
|
+
"@vitest/browser*"
|
|
110
|
+
],
|
|
111
|
+
seam: "browser-mode"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
fix: "the network answers through stubs: `await using _ = await intercept(defineStubs(...))` in module scope, `.intercept()` on a chain",
|
|
115
|
+
packages: ["msw", "nock"],
|
|
116
|
+
seam: "network"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
fix: "the doubles ladder is closed: `mockOf<Port>()` for an injected interface, `vi.fn()` for a function, `vi.spyOn` for an object the test passes in",
|
|
120
|
+
packages: ["sinon", "vitest-mock-extended"],
|
|
121
|
+
seam: "doubles"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
fix: "vitest is the runner this vocabulary speaks: `test`, `expect` and `vi` come from it",
|
|
125
|
+
packages: ["jest", "@jest/*"],
|
|
126
|
+
seam: "runner"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
fix: "time is one primitive: `using _ = clock.at(iso)` pins the calendar and gives it back at the end of the scope",
|
|
130
|
+
packages: ["mockdate"],
|
|
131
|
+
seam: "clock"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
fix: "the website specification drives the browser: `specification.website()` owns the page, and the peer is its",
|
|
135
|
+
packages: [
|
|
136
|
+
"playwright",
|
|
137
|
+
"playwright-core",
|
|
138
|
+
"@playwright/test"
|
|
139
|
+
],
|
|
140
|
+
seam: "browser"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
fix: "the mobile specification drives the simulator: `specification.mobile()` owns the session, and the peers are its",
|
|
144
|
+
packages: ["webdriverio", "appium"],
|
|
145
|
+
seam: "simulator"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
fix: "a component rendered to a string is still a component: the test is a `.test.tsx` in the `__tests__/` of its folder, and `result.html` carries the markup",
|
|
149
|
+
from: String.raw`\.test\.ts$`,
|
|
150
|
+
packages: ["react-dom/server"],
|
|
151
|
+
seam: "string-renderer"
|
|
152
|
+
}
|
|
153
|
+
];
|
|
154
|
+
const secondRuntime = taughtBy("no-second-test-runtime");
|
|
155
|
+
function secondRuntimeLaw(seam, pathNot) {
|
|
156
|
+
return {
|
|
157
|
+
fix: seam.fix,
|
|
158
|
+
from: {
|
|
159
|
+
path: seam.from ?? RUNS_A_TEST,
|
|
160
|
+
...pathNot === void 0 ? {} : { pathNot }
|
|
161
|
+
},
|
|
162
|
+
name: `no-second-test-runtime-${seam.seam}`,
|
|
163
|
+
read: secondRuntime.read,
|
|
164
|
+
to: { path: packages(seam.packages) },
|
|
165
|
+
why: secondRuntime.why
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function publishedFix() {
|
|
169
|
+
const published = declaredSubpaths("@jterrazz/test", import.meta.dirname);
|
|
170
|
+
return `import from "@jterrazz/test"; the published subpaths are ${published.length === 0 ? "none" : published.join(", ")}`;
|
|
171
|
+
}
|
|
172
|
+
const LAYERS = [
|
|
173
|
+
{
|
|
174
|
+
...taughtBy("no-test-to-test-import"),
|
|
175
|
+
fix: "under `specs/`, move what both read into the `__setup__/` of the lowest folder they share; under `src/`, into a `__tests__/<file>.fixtures.ts` for typed input data",
|
|
176
|
+
from: { path: TEST_FILE },
|
|
177
|
+
name: "no-test-to-test-import",
|
|
178
|
+
to: { path: String.raw`\.test\.[cm]?[jt]sx?$` }
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
...taughtBy("fixtures-imported-by-tests-only"),
|
|
182
|
+
fix: "import it from a `*.test.ts` only, or move what the file needs into a module of its own",
|
|
183
|
+
from: { pathNot: TEST_FILE },
|
|
184
|
+
name: "fixtures-imported-by-tests-only",
|
|
185
|
+
to: { path: String.raw`\.fixtures${SOURCE}` }
|
|
186
|
+
},
|
|
187
|
+
...SEAMS.map((seam) => secondRuntimeLaw(seam)),
|
|
188
|
+
{
|
|
189
|
+
...taughtBy("no-unpublished-subpath"),
|
|
190
|
+
fix: publishedFix(),
|
|
191
|
+
from: {},
|
|
192
|
+
name: "no-unpublished-subpath",
|
|
193
|
+
to: {
|
|
194
|
+
couldNotResolve: true,
|
|
195
|
+
path: "^@jterrazz/test/"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
];
|
|
199
|
+
const EXTENSIONS = [
|
|
200
|
+
"c",
|
|
201
|
+
"m",
|
|
202
|
+
""
|
|
203
|
+
].flatMap((module) => ["j", "t"].flatMap((language) => ["x", ""].map((jsx) => `${module}${language}s${jsx}`)));
|
|
204
|
+
const AT_THE_SPECS_ROOT = [...[
|
|
205
|
+
"test",
|
|
206
|
+
"test-d",
|
|
207
|
+
"spec",
|
|
208
|
+
"specification"
|
|
209
|
+
].flatMap((kind) => EXTENSIONS.map((extension) => `.${kind}.${extension}`)), ".spec.yaml"];
|
|
210
|
+
const ANY_OTHER_FILE = [
|
|
211
|
+
".*",
|
|
212
|
+
".*.*",
|
|
213
|
+
".*.*.*",
|
|
214
|
+
".*.*.*.*"
|
|
215
|
+
];
|
|
216
|
+
const OF_A_UNIT = [[".json", "regex:(package|tsconfig)"], [".config.ts", "regex:(jterrazz|vitest)"]];
|
|
217
|
+
function specsRootFiles() {
|
|
218
|
+
const refused = ANY_OTHER_FILE.map((key) => [key, "exists:0"]);
|
|
219
|
+
const held = AT_THE_SPECS_ROOT.flatMap((key) => [[key, "regex:.+"], [`.*${key}`, "regex:.+"]]);
|
|
220
|
+
return Object.fromEntries([
|
|
221
|
+
...refused,
|
|
222
|
+
...held,
|
|
223
|
+
...OF_A_UNIT
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
226
|
+
const CLOSED_LIST = `regex:${either(["[^_].*", ...SPECIAL_FOLDERS.map((name) => escaped(name))])}`;
|
|
227
|
+
const LISTED = SPECIAL_FOLDERS.map((name) => `\`${name}/\``).join(", ");
|
|
228
|
+
const EARLIER_SPELLINGS = Object.entries(RENAMED_FOLDERS).filter(([earlier]) => earlier.startsWith("_")).map(([earlier, now]) => `\`${earlier}/\` is \`${now}/\``).join(", ");
|
|
229
|
+
const NAMES = [
|
|
230
|
+
{
|
|
231
|
+
...taughtBy("specs-root-holds-specifications-and-shared"),
|
|
232
|
+
fix: `move a file where it belongs: code into \`specs/${SETUP_FOLDER}/\` or the \`${SETUP_FOLDER}/\` of the one specification that reads it, data into the ground folder of its role`,
|
|
233
|
+
ls: {
|
|
234
|
+
"**/specs": specsRootFiles(),
|
|
235
|
+
"**/specs/*": {}
|
|
236
|
+
},
|
|
237
|
+
name: "specs-root-holds-specifications-and-shared"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
...taughtBy("special-folder-in-closed-list"),
|
|
241
|
+
fix: `rename it to the special folder that says what it holds (${LISTED}), or drop the \`_\` if it is a subject; an earlier spelling names its own (${EARLIER_SPELLINGS}), and what \`_shared/\` held sits in the special folders at the specs root`,
|
|
242
|
+
ignore: SPECIAL_FOLDERS.map((name) => `**/${name}`),
|
|
243
|
+
ls: { "**/specs/**": { ".dir": CLOSED_LIST } },
|
|
244
|
+
name: "special-folder-in-closed-list"
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
...taughtBy("spec-file-in-a-specs-tree"),
|
|
248
|
+
fix: "move it under `specs/<specification>/`, or rename it `.test.ts` in the `__tests__/` of the folder of the module it covers",
|
|
249
|
+
ignore: ["specs", "**/specs"],
|
|
250
|
+
ls: { "**": {
|
|
251
|
+
".*.spec.ts": "exists:0",
|
|
252
|
+
".spec.ts": "exists:0"
|
|
253
|
+
} },
|
|
254
|
+
name: "spec-file-in-a-specs-tree"
|
|
255
|
+
}
|
|
256
|
+
];
|
|
257
|
+
const TEST_COMMENT_OPENINGS = Object.freeze([
|
|
258
|
+
"Given - ",
|
|
259
|
+
"When - ",
|
|
260
|
+
"Then - ",
|
|
261
|
+
"And - ",
|
|
262
|
+
"checker-disable",
|
|
263
|
+
"testId:"
|
|
264
|
+
]);
|
|
265
|
+
const TEST_STANDARD = standard_default.test ?? {};
|
|
266
|
+
const recordOf = (value) => isRecord(value) ? value : {};
|
|
267
|
+
function loadedByName(section) {
|
|
268
|
+
return Object.values(recordOf(section.projects)).flatMap((project) => {
|
|
269
|
+
const { root, wrap } = recordOf(project);
|
|
270
|
+
return typeof wrap === "string" ? [posix.normalize(typeof root === "string" ? posix.join(root, wrap) : wrap)] : [];
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
function testPreset() {
|
|
274
|
+
return {
|
|
275
|
+
baseline: [TEST_SECTION],
|
|
276
|
+
layers: LAYERS,
|
|
277
|
+
name: TEST_SECTION,
|
|
278
|
+
names: NAMES,
|
|
279
|
+
oxlint: {
|
|
280
|
+
jsPlugins: ["@jterrazz/test/oxlint"],
|
|
281
|
+
overrides: [importRulesForSpecifications, vitestOnTests],
|
|
282
|
+
rules: {
|
|
283
|
+
...recommendedRules,
|
|
284
|
+
"jterrazz-typescript/comment-states-its-kind": ["error", { openings: [...TEST_COMMENT_OPENINGS] }]
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
checker: {
|
|
288
|
+
label: "Test Conventions (@jterrazz/test)",
|
|
289
|
+
module: createRequire(import.meta.url).resolve("#checker")
|
|
290
|
+
},
|
|
291
|
+
derive: (root) => ({ projects: Object.fromEntries(derivedProjects(root)) }),
|
|
292
|
+
entries: (section, root) => [...loadedByName(section), ...specificationModules(root)],
|
|
293
|
+
loadedPackages: packagesLoadedFor,
|
|
294
|
+
files: { "vitest.config.ts": {
|
|
295
|
+
scope: "unit",
|
|
296
|
+
text: "import { vitestConfig } from '@jterrazz/test/vitest';\n\nexport default await vitestConfig(import.meta.url);\n"
|
|
297
|
+
} },
|
|
298
|
+
origins: [{
|
|
299
|
+
file: "src/standard/standard.ts",
|
|
300
|
+
settings: TEST_STANDARD
|
|
301
|
+
}],
|
|
302
|
+
package: "@jterrazz/test",
|
|
303
|
+
settings: TEST_STANDARD
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
//#endregion
|
|
307
|
+
export { testPreset as test };
|
|
308
|
+
|
|
309
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/expectations/in-place/in-place.global-setup.d.ts
|
|
2
|
+
export declare function inPlaceSetup(): string;
|
|
3
|
+
type RunProject = {
|
|
4
|
+
config: {
|
|
5
|
+
root: string;
|
|
6
|
+
};
|
|
7
|
+
provide: (key: 'inPlaceRewrites', value: string) => void;
|
|
8
|
+
};
|
|
9
|
+
export default function setup(project: RunProject): () => void;
|
|
10
|
+
//#endregion
|
|
11
|
+
//# sourceMappingURL=in-place.global-setup.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { i as writePendingRewrites } from "./shared-in-place.js";
|
|
2
|
+
import { l as VITEST_ARTIFACTS_DIR } from "./shared-artifacts.js";
|
|
3
|
+
import { t as setupEntry } from "./shared-setup-entry.js";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
//#region src/expectations/in-place/in-place.global-setup.ts
|
|
7
|
+
function inPlaceSetup() {
|
|
8
|
+
return setupEntry(import.meta.dirname, "in-place");
|
|
9
|
+
}
|
|
10
|
+
const IN_PLACE_DIR = `${VITEST_ARTIFACTS_DIR}/in-place`;
|
|
11
|
+
function setup(project) {
|
|
12
|
+
const folder = join(project.config.root, IN_PLACE_DIR, randomUUID());
|
|
13
|
+
project.provide("inPlaceRewrites", folder);
|
|
14
|
+
return () => {
|
|
15
|
+
writePendingRewrites(folder);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { setup as default, inPlaceSetup };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=in-place.global-setup.js.map
|