@specific.dev/spectest 0.56.2 → 0.58.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/dist/browser-coverage.d.ts +20 -0
- package/dist/browser-coverage.js +185 -0
- package/dist/browser.js +36 -0
- package/dist/daemon.js +200 -11
- package/dist/harness/browser-coverage.d.ts +95 -0
- package/dist/harness/browser-coverage.js +257 -0
- package/dist/harness/coverage.d.ts +60 -0
- package/dist/harness/coverage.js +122 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +32 -0
- package/package.json +1 -1
- package/src/browser-coverage.ts +209 -0
- package/src/browser.ts +36 -0
- package/src/daemon.ts +230 -11
- package/src/harness/browser-coverage.test.ts +94 -0
- package/src/harness/browser-coverage.ts +310 -0
- package/src/harness/coverage.test.ts +88 -0
- package/src/harness/coverage.ts +173 -0
- package/src/index.ts +81 -0
package/src/index.ts
CHANGED
|
@@ -252,6 +252,27 @@ export interface ServiceConfig {
|
|
|
252
252
|
tls?: readonly ServiceTls[];
|
|
253
253
|
/** Bind-mounted volumes for state that survives snapshot/fork. */
|
|
254
254
|
volumes?: readonly VolumeMount[];
|
|
255
|
+
/**
|
|
256
|
+
* Opt this service in to **code coverage collection** (experimental).
|
|
257
|
+
*
|
|
258
|
+
* The service gets a writable directory bind-mounted at
|
|
259
|
+
* `/spectest/coverage/`. The service's own coverage tool writes **lcov**
|
|
260
|
+
* reports there — cumulative from process start, never reset. After
|
|
261
|
+
* bring-up and after every test, spectest runs `command` (if given) inside
|
|
262
|
+
* the container, then reads every file in the directory and records the
|
|
263
|
+
* set of source files that ran. Only the `SF:` records are read.
|
|
264
|
+
*
|
|
265
|
+
* - `true`: the service writes its reports by itself (a dump on a timer,
|
|
266
|
+
* an exit-time dump for short-lived processes).
|
|
267
|
+
* - `{ command }`: run this (via `sh -c`) in the container to make the
|
|
268
|
+
* service write a report, before the directory is read.
|
|
269
|
+
*
|
|
270
|
+
* The directory must hold at least one lcov report each time it is read;
|
|
271
|
+
* an empty directory or a failed command fails the test with a clear
|
|
272
|
+
* error, so a hole in the coverage data is never silent. See
|
|
273
|
+
* `spectest docs /services/coverage`.
|
|
274
|
+
*/
|
|
275
|
+
coverage?: ServiceCoverage;
|
|
255
276
|
/**
|
|
256
277
|
* Files seeded into the container's filesystem **before it starts**.
|
|
257
278
|
* Each entry's `content` is written to a VM-host staging path and
|
|
@@ -1017,6 +1038,32 @@ export type ServiceImage =
|
|
|
1017
1038
|
exclude?: readonly string[];
|
|
1018
1039
|
};
|
|
1019
1040
|
|
|
1041
|
+
/**
|
|
1042
|
+
* A service's opt-in to coverage collection — see `ServiceConfig.coverage`.
|
|
1043
|
+
* `true` when the service writes its own reports; `{ command }` when
|
|
1044
|
+
* spectest must run a command in the container to produce one.
|
|
1045
|
+
*/
|
|
1046
|
+
export type ServiceCoverage =
|
|
1047
|
+
| true
|
|
1048
|
+
| {
|
|
1049
|
+
/** Run this (via `sh -c`) in the container before the coverage
|
|
1050
|
+
* directory is read, so the service writes a fresh lcov report. */
|
|
1051
|
+
command?: string;
|
|
1052
|
+
/**
|
|
1053
|
+
* Collect **frontend** coverage for the app this service serves.
|
|
1054
|
+
* The code runs in the guest browser — spectest's own process — so
|
|
1055
|
+
* the user cannot write a report for it: spectest turns on V8
|
|
1056
|
+
* coverage for every script `ctx.browser()`/`ctx.mobile()` loads
|
|
1057
|
+
* from this service's origin, maps it back to original sources
|
|
1058
|
+
* through the served source maps, and adds one lcov report to this
|
|
1059
|
+
* service's capture. Scripts a source map can't resolve are
|
|
1060
|
+
* attributed to their served path (which the repo mapping then
|
|
1061
|
+
* treats as unknown — the safe answer). Needs the app to serve
|
|
1062
|
+
* source maps to the test environment.
|
|
1063
|
+
*/
|
|
1064
|
+
browser?: boolean;
|
|
1065
|
+
};
|
|
1066
|
+
|
|
1020
1067
|
export interface VolumeMount {
|
|
1021
1068
|
/**
|
|
1022
1069
|
* Named shared volume. Two services mounting the same `name` share one
|
|
@@ -1236,6 +1283,39 @@ export interface FakeContext {
|
|
|
1236
1283
|
certificate(hostnames: readonly string[]): Promise<CertificateMaterial>;
|
|
1237
1284
|
}
|
|
1238
1285
|
|
|
1286
|
+
/**
|
|
1287
|
+
* Check one service's `coverage` field. Exported so the daemon applies the
|
|
1288
|
+
* same rule to a runtime `startService` spec.
|
|
1289
|
+
*/
|
|
1290
|
+
export function validateCoverage(service: string, cov: unknown): void {
|
|
1291
|
+
if (cov === undefined || cov === true) return;
|
|
1292
|
+
if (typeof cov === "object" && cov !== null) {
|
|
1293
|
+
const o = cov as { command?: unknown; browser?: unknown };
|
|
1294
|
+
const cmdOk =
|
|
1295
|
+
o.command === undefined ||
|
|
1296
|
+
(typeof o.command === "string" && o.command.trim().length > 0);
|
|
1297
|
+
const browserOk = o.browser === undefined || typeof o.browser === "boolean";
|
|
1298
|
+
if (cmdOk && browserOk && (o.command !== undefined || o.browser === true)) return;
|
|
1299
|
+
}
|
|
1300
|
+
throw new Error(
|
|
1301
|
+
`service "${service}" has an invalid \`coverage\` value — use \`true\`, \`{ command: "<shell command>" }\`, or \`{ browser: true }\``,
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
/** Whether a `coverage` value collects reports from the container's own
|
|
1306
|
+
* filesystem (`/spectest/coverage/`). True for `true`, `{ command }`, and
|
|
1307
|
+
* any object that isn't browser-only. */
|
|
1308
|
+
export function coverageUsesContainer(cov: ServiceCoverage | undefined): boolean {
|
|
1309
|
+
if (cov === undefined) return false;
|
|
1310
|
+
if (cov === true) return true;
|
|
1311
|
+
return cov.command !== undefined || cov.browser !== true;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
/** Whether a `coverage` value collects frontend (browser) coverage. */
|
|
1315
|
+
export function coverageUsesBrowser(cov: ServiceCoverage | undefined): boolean {
|
|
1316
|
+
return typeof cov === "object" && cov.browser === true;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1239
1319
|
function validateEnvironmentConfig<S extends ServicesMap>(
|
|
1240
1320
|
config: EnvironmentConfig<S>,
|
|
1241
1321
|
): void {
|
|
@@ -1281,6 +1361,7 @@ function validateEnvironmentConfig<S extends ServicesMap>(
|
|
|
1281
1361
|
);
|
|
1282
1362
|
}
|
|
1283
1363
|
}
|
|
1364
|
+
validateCoverage(name, svc.coverage);
|
|
1284
1365
|
for (const raw of svc.hostnames ?? []) {
|
|
1285
1366
|
const h = raw.toLowerCase();
|
|
1286
1367
|
if (!HOSTNAME_RE.test(hostPatternBody(h))) {
|