@rpcbase/test 0.334.0 → 0.336.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/clearDatabase.js +4 -1
  2. package/dist/clearDatabase.js.map +1 -1
  3. package/dist/cli.js +130 -77
  4. package/dist/cli.js.map +1 -1
  5. package/dist/coverage/collect.js +3 -1
  6. package/dist/coverage/collect.js.map +1 -1
  7. package/dist/coverage/config-loader.js +20 -36
  8. package/dist/coverage/config-loader.js.map +1 -1
  9. package/dist/coverage/config.js +19 -8
  10. package/dist/coverage/config.js.map +1 -1
  11. package/dist/coverage/console-text-report.js +23 -13
  12. package/dist/coverage/console-text-report.js.map +1 -1
  13. package/dist/coverage/files.js +25 -28
  14. package/dist/coverage/files.js.map +1 -1
  15. package/dist/coverage/fixtures.js +3 -1
  16. package/dist/coverage/fixtures.js.map +1 -1
  17. package/dist/coverage/global-setup.js +4 -1
  18. package/dist/coverage/global-setup.js.map +1 -1
  19. package/dist/coverage/index.js +3 -1
  20. package/dist/coverage/index.js.map +1 -1
  21. package/dist/coverage/report.js +55 -62
  22. package/dist/coverage/report.js.map +1 -1
  23. package/dist/coverage/reporter.js +4 -1
  24. package/dist/coverage/reporter.js.map +1 -1
  25. package/dist/coverage/v8-tracker.js +18 -14
  26. package/dist/coverage/v8-tracker.js.map +1 -1
  27. package/dist/index.js +10 -3
  28. package/dist/index.js.map +1 -1
  29. package/dist/serverCoverage.js +6 -2
  30. package/dist/serverCoverage.js.map +1 -1
  31. package/dist/specs-map.d.ts +15 -0
  32. package/dist/specs-map.d.ts.map +1 -0
  33. package/dist/specs-map.js +50 -0
  34. package/dist/specs-map.js.map +1 -0
  35. package/dist/vitest.config.js +14 -14
  36. package/dist/vitest.config.js.map +1 -1
  37. package/package.json +6 -5
@@ -1,6 +1,9 @@
1
1
  import mongoose from "mongoose";
2
2
  async function clearDatabase(dbName) {
3
- const { DB_PORT, APP_NAME } = process.env;
3
+ const {
4
+ DB_PORT,
5
+ APP_NAME
6
+ } = process.env;
4
7
  const connectionString = `mongodb://localhost:${DB_PORT}/${APP_NAME}-${dbName}`;
5
8
  const connection = await mongoose.createConnection(connectionString).asPromise();
6
9
  await connection.dropDatabase();
@@ -1 +1 @@
1
- {"version":3,"file":"clearDatabase.js","sources":["../src/clearDatabase.ts"],"sourcesContent":["import mongoose from \"mongoose\"\n\n\nexport async function clearDatabase(dbName: string): Promise<void> {\n const { DB_PORT, APP_NAME } = process.env\n\n const connectionString = `mongodb://localhost:${DB_PORT}/${APP_NAME}-${dbName}`\n\n // console.log(\"will clear DB:\", connectionString)\n\n const connection = await mongoose\n .createConnection(connectionString)\n .asPromise()\n\n // Drop the database\n await connection.dropDatabase()\n\n await connection.close()\n}\n"],"names":[],"mappings":";AAGA,eAAsB,cAAc,QAA+B;AACjE,QAAM,EAAE,SAAS,SAAA,IAAa,QAAQ;AAEtC,QAAM,mBAAmB,uBAAuB,OAAO,IAAI,QAAQ,IAAI,MAAM;AAI7E,QAAM,aAAa,MAAM,SACtB,iBAAiB,gBAAgB,EACjC,UAAA;AAGH,QAAM,WAAW,aAAA;AAEjB,QAAM,WAAW,MAAA;AACnB;"}
1
+ {"version":3,"file":"clearDatabase.js","sources":["../src/clearDatabase.ts"],"sourcesContent":["import mongoose from \"mongoose\"\n\n\nexport async function clearDatabase(dbName: string): Promise<void> {\n const { DB_PORT, APP_NAME } = process.env\n\n const connectionString = `mongodb://localhost:${DB_PORT}/${APP_NAME}-${dbName}`\n\n // console.log(\"will clear DB:\", connectionString)\n\n const connection = await mongoose\n .createConnection(connectionString)\n .asPromise()\n\n // Drop the database\n await connection.dropDatabase()\n\n await connection.close()\n}\n"],"names":["clearDatabase","dbName","DB_PORT","APP_NAME","process","env","connectionString","connection","mongoose","createConnection","asPromise","dropDatabase","close"],"mappings":";AAGA,eAAsBA,cAAcC,QAA+B;AACjE,QAAM;AAAA,IAAEC;AAAAA,IAASC;AAAAA,EAAAA,IAAaC,QAAQC;AAEtC,QAAMC,mBAAmB,uBAAuBJ,OAAO,IAAIC,QAAQ,IAAIF,MAAM;AAI7E,QAAMM,aAAa,MAAMC,SACtBC,iBAAiBH,gBAAgB,EACjCI,UAAAA;AAGH,QAAMH,WAAWI,aAAAA;AAEjB,QAAMJ,WAAWK,MAAAA;AACnB;"}
package/dist/cli.js CHANGED
@@ -11,6 +11,7 @@ import { createCollectCoverageMatcher, resolveCollectCoverageRoots, isInsideAnyR
11
11
  import { loadCoverageOptions } from "./coverage/config-loader.js";
12
12
  import { removeCoverageFiles } from "./coverage/files.js";
13
13
  import { CoverageThresholdError, collectCoveredFiles, generateCoverageReport } from "./coverage/report.js";
14
+ import { createSpecsByFileRecord, readSpecsMapIndex, warnSpecsMapOutdated } from "./specs-map.js";
14
15
  const require$1 = createRequire(import.meta.url);
15
16
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
16
17
  const shouldForceTty = !process.stdout.isTTY && process.env.FORCE_COLOR === "true";
@@ -51,7 +52,9 @@ async function runTests() {
51
52
  }
52
53
  let testError = null;
53
54
  try {
54
- await runVitest(vitestCoverage, combinedCoverage?.config ?? null, filteredArgs, { disableCoverage: auto });
55
+ await runVitest(vitestCoverage, combinedCoverage?.config ?? null, filteredArgs, {
56
+ disableCoverage: auto
57
+ });
55
58
  console.log("\nRunning Playwright Tests...");
56
59
  const playwrightArgs = auto ? await resolveAutoPlaywrightArgs({
57
60
  userArgs: filteredArgs,
@@ -60,7 +63,9 @@ async function runTests() {
60
63
  showMapping
61
64
  }) : filteredArgs;
62
65
  if (playwrightArgs) {
63
- await runPlaywright(playwrightArgs, { disableCoverage: auto });
66
+ await runPlaywright(playwrightArgs, {
67
+ disableCoverage: auto
68
+ });
64
69
  }
65
70
  } catch (error) {
66
71
  testError = error;
@@ -86,7 +91,9 @@ runTests().then(() => process.exit(0)).catch((error) => {
86
91
  }
87
92
  process.exit(1);
88
93
  });
89
- async function runVitest(coverage, combinedConfig, userArgs, { disableCoverage = false } = {}) {
94
+ async function runVitest(coverage, combinedConfig, userArgs, {
95
+ disableCoverage = false
96
+ } = {}) {
90
97
  const vitestArgs = ["run", "--passWithNoTests"];
91
98
  const vitestConfig = resolveVitestConfig();
92
99
  const hasCustomConfig = userArgs.some((arg) => {
@@ -106,7 +113,9 @@ async function runVitest(coverage, combinedConfig, userArgs, { disableCoverage =
106
113
  }
107
114
  if (coverage?.enabled && !disableCoverage) {
108
115
  const nodeCoverageDir = resolveNodeCoverageDir(combinedConfig ?? coverage.config);
109
- await fs.mkdir(nodeCoverageDir, { recursive: true });
116
+ await fs.mkdir(nodeCoverageDir, {
117
+ recursive: true
118
+ });
110
119
  env.NODE_V8_COVERAGE = nodeCoverageDir;
111
120
  }
112
121
  await spawnWithLogs({
@@ -129,7 +138,7 @@ async function buildSpecsMapFromCoverage({
129
138
  combinedCoverage
130
139
  }) {
131
140
  if (!combinedCoverage?.enabled) {
132
- throw new Error("[specs-map] Coverage must be enabled to build the specs map.");
141
+ throw new Error("[specs-map] Cannot build specs map when coverage is disabled.");
133
142
  }
134
143
  const config = combinedCoverage.config;
135
144
  const workspaceRoot = findWorkspaceRoot(process.cwd());
@@ -138,8 +147,16 @@ async function buildSpecsMapFromCoverage({
138
147
  throw new Error("[specs-map] No spec files found under spec/**/*.spec{,.desktop,.mobile}.ts");
139
148
  }
140
149
  const filesMapDir = path.join(config.testResultsRoot, "files-map");
141
- await fs.rm(filesMapDir, { recursive: true, force: true });
142
- await fs.mkdir(filesMapDir, { recursive: true });
150
+ const specsMapIndexFile = path.join(filesMapDir, "index.json");
151
+ await fs.rm(filesMapDir, {
152
+ recursive: true,
153
+ force: true
154
+ });
155
+ await fs.mkdir(filesMapDir, {
156
+ recursive: true
157
+ });
158
+ const specsMap = [];
159
+ const specsByFile = /* @__PURE__ */ new Map();
143
160
  for (const specSourceFile of specSourceFiles) {
144
161
  const specProjectPath = path.relative(config.rootDir, specSourceFile);
145
162
  const specWorkspacePath = toPosixPath(path.relative(workspaceRoot, specSourceFile));
@@ -159,25 +176,28 @@ async function buildSpecsMapFromCoverage({
159
176
  }
160
177
  const coveredFiles = await collectCoveredFiles(config);
161
178
  const impactedFiles = coveredFiles.map((filePath) => toPosixPath(path.relative(workspaceRoot, filePath))).filter((relativePath) => relativePath && !relativePath.startsWith("../") && relativePath !== "..").sort();
162
- const outputFile = path.join(filesMapDir, `${specProjectPath}.json`);
163
- await fs.mkdir(path.dirname(outputFile), { recursive: true });
164
- await fs.writeFile(
165
- outputFile,
166
- JSON.stringify(
167
- {
168
- spec: specWorkspacePath,
169
- files: impactedFiles,
170
- failed
171
- },
172
- null,
173
- 2
174
- ),
175
- "utf8"
176
- );
179
+ specsMap.push({
180
+ spec: specWorkspacePath,
181
+ files: impactedFiles,
182
+ failed
183
+ });
184
+ for (const file of impactedFiles) {
185
+ const list = specsByFile.get(file) ?? [];
186
+ if (!list.includes(specWorkspacePath)) {
187
+ list.push(specWorkspacePath);
188
+ }
189
+ specsByFile.set(file, list);
190
+ }
177
191
  if (failed) {
178
192
  throw error;
179
193
  }
180
194
  }
195
+ await fs.writeFile(specsMapIndexFile, JSON.stringify({
196
+ version: 1,
197
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
198
+ specs: specsMap,
199
+ byFile: createSpecsByFileRecord(specsByFile)
200
+ }, null, 2), "utf8");
181
201
  }
182
202
  async function resolveAutoPlaywrightArgs({
183
203
  userArgs,
@@ -191,16 +211,15 @@ async function resolveAutoPlaywrightArgs({
191
211
  return userArgs;
192
212
  }
193
213
  const filesMapDir = path.join(config.testResultsRoot, "files-map");
194
- const mapFiles = await findFilesMapJson(filesMapDir);
195
- if (mapFiles.length === 0) {
196
- console.warn("[auto] Specs map not found; running full Playwright suite.");
214
+ const indexPath = path.join(filesMapDir, "index.json");
215
+ const mapIndex = await readSpecsMapIndex(indexPath);
216
+ if (!mapIndex) {
217
+ warnSpecsMapOutdated(indexPath, "Specs map index not found or invalid.");
197
218
  return userArgs;
198
219
  }
199
220
  const workspaceRoot = findWorkspaceRoot(process.cwd());
200
221
  const gitChanges = getGitChanges(workspaceRoot);
201
- const renameMap = new Map(
202
- gitChanges.filter((change) => change.kind === "rename").map((change) => [change.oldPath, change.newPath])
203
- );
222
+ const renameMap = new Map(gitChanges.filter((change) => change.kind === "rename").map((change) => [change.oldPath, change.newPath]));
204
223
  const specRootAbs = path.join(config.rootDir, "spec");
205
224
  const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir);
206
225
  const directSpecChanges = /* @__PURE__ */ new Set();
@@ -231,33 +250,48 @@ async function resolveAutoPlaywrightArgs({
231
250
  console.log("[auto] No relevant git changes.");
232
251
  return null;
233
252
  }
253
+ if (mapIndex.specs.length === 0) {
254
+ warnSpecsMapOutdated(indexPath, "Specs map index is empty.");
255
+ return userArgs;
256
+ }
234
257
  const parsedMaps = [];
235
- for (const file of mapFiles) {
236
- const json = await readJson(file);
237
- if (!json) {
238
- continue;
239
- }
240
- if (json.failed === true) {
241
- console.warn("[auto] Specs map contains failed entries; running full Playwright suite.");
258
+ for (const entry of mapIndex.specs) {
259
+ if (entry?.failed === true) {
260
+ warnSpecsMapOutdated(indexPath, "Specs map was built from a failed spec run.");
242
261
  return userArgs;
243
262
  }
244
- const spec = typeof json?.spec === "string" ? json.spec : null;
263
+ const spec = typeof entry?.spec === "string" ? entry.spec : null;
245
264
  if (!spec) {
246
265
  continue;
247
266
  }
248
- const files = Array.isArray(json?.files) ? json.files.filter((entry) => typeof entry === "string") : [];
249
- parsedMaps.push({ spec, files });
267
+ const files = Array.isArray(entry?.files) ? entry.files.filter((value) => typeof value === "string") : [];
268
+ parsedMaps.push({
269
+ spec,
270
+ files
271
+ });
250
272
  }
251
273
  if (parsedMaps.length === 0) {
252
- console.warn("[auto] Specs map is empty; running full Playwright suite.");
274
+ warnSpecsMapOutdated(indexPath, "Specs map index payload is empty.");
253
275
  return userArgs;
254
276
  }
255
277
  const specsByImpactedFile = /* @__PURE__ */ new Map();
278
+ for (const [file, specs] of Object.entries(mapIndex.byFile ?? {})) {
279
+ const resolvedSpecs = specs.filter((spec) => typeof spec === "string").map((spec) => resolveRenamedPath(spec, renameMap));
280
+ const list = specsByImpactedFile.get(file) ?? [];
281
+ for (const spec of resolvedSpecs) {
282
+ if (!list.includes(spec)) {
283
+ list.push(spec);
284
+ }
285
+ }
286
+ specsByImpactedFile.set(file, list);
287
+ }
256
288
  for (const entry of parsedMaps) {
257
289
  const resolvedSpec = resolveRenamedPath(entry.spec, renameMap);
258
290
  for (const file of entry.files) {
259
291
  const list = specsByImpactedFile.get(file) ?? [];
260
- list.push(resolvedSpec);
292
+ if (!list.includes(resolvedSpec)) {
293
+ list.push(resolvedSpec);
294
+ }
261
295
  specsByImpactedFile.set(file, list);
262
296
  }
263
297
  }
@@ -351,11 +385,6 @@ async function resolveAutoPlaywrightArgs({
351
385
  console.log(`[auto] Running ${playwrightFiles.length}/${totalSpecFiles} spec file(s).`);
352
386
  return [...userArgs, ...playwrightFiles];
353
387
  }
354
- async function findFilesMapJson(filesMapDir) {
355
- const patterns = ["spec/**/*.spec{,.desktop,.mobile}.ts.json", "spec/**/*.spec{,.desktop,.mobile}.tsx.json"];
356
- const matches = await fg(patterns, { cwd: filesMapDir, absolute: true, onlyFiles: true }).catch(() => []);
357
- return matches.sort();
358
- }
359
388
  function getGitChanges(workspaceRoot) {
360
389
  const result = spawnSync("git", ["status", "--porcelain=1", "-z"], {
361
390
  cwd: workspaceRoot,
@@ -421,7 +450,11 @@ function isSpecSourceFile(absolutePath, specRootAbsolute) {
421
450
  }
422
451
  async function findSpecSourceFiles(projectRoot) {
423
452
  const patterns = ["spec/**/*.spec{,.desktop,.mobile}.ts", "spec/**/*.spec{,.desktop,.mobile}.tsx"];
424
- const matches = await fg(patterns, { cwd: projectRoot, absolute: true, onlyFiles: true });
453
+ const matches = await fg(patterns, {
454
+ cwd: projectRoot,
455
+ absolute: true,
456
+ onlyFiles: true
457
+ });
425
458
  return matches.sort();
426
459
  }
427
460
  function resolvePlaywrightSpecFile(specProjectPath) {
@@ -466,10 +499,10 @@ function findWorkspaceRoot(projectRoot) {
466
499
  dir = parent;
467
500
  }
468
501
  }
469
- function runPlaywright(userArgs, { disableCoverage = false } = {}) {
470
- const configPath = fs$1.existsSync(
471
- path.join(process.cwd(), "playwright.config.ts")
472
- ) ? path.join(process.cwd(), "playwright.config.ts") : path.join(moduleDir, "playwright.config.ts");
502
+ function runPlaywright(userArgs, {
503
+ disableCoverage = false
504
+ } = {}) {
505
+ const configPath = fs$1.existsSync(path.join(process.cwd(), "playwright.config.ts")) ? path.join(process.cwd(), "playwright.config.ts") : path.join(moduleDir, "playwright.config.ts");
473
506
  const hasCustomConfig = userArgs.some((arg) => {
474
507
  if (arg === "--config" || arg === "-c") {
475
508
  return true;
@@ -521,7 +554,9 @@ function resolveCliPath() {
521
554
  const searchRoots = [process.cwd(), moduleDir];
522
555
  for (const base of searchRoots) {
523
556
  try {
524
- const pkgPath = require$1.resolve("@playwright/test/package.json", { paths: [base] });
557
+ const pkgPath = require$1.resolve("@playwright/test/package.json", {
558
+ paths: [base]
559
+ });
525
560
  const cliPath = path.join(path.dirname(pkgPath), "cli.js");
526
561
  if (fs$1.existsSync(cliPath)) {
527
562
  return cliPath;
@@ -535,7 +570,9 @@ function resolveVitestLauncher() {
535
570
  const searchRoots = [process.cwd(), moduleDir];
536
571
  for (const base of searchRoots) {
537
572
  try {
538
- const pkgPath = require$1.resolve("vitest/package.json", { paths: [base] });
573
+ const pkgPath = require$1.resolve("vitest/package.json", {
574
+ paths: [base]
575
+ });
539
576
  const pkgDir = path.dirname(pkgPath);
540
577
  const pkgJson = JSON.parse(fs$1.readFileSync(pkgPath, "utf8"));
541
578
  const binPath = typeof pkgJson.bin === "string" ? pkgJson.bin : pkgJson.bin?.vitest;
@@ -569,11 +606,7 @@ function resolveVitestConfig() {
569
606
  return fs$1.existsSync(bundledConfig) ? bundledConfig : null;
570
607
  }
571
608
  function findVitestConfig(baseDir) {
572
- const candidates = [
573
- "vitest.config.ts",
574
- "vitest.config.js",
575
- "vitest.config.mjs"
576
- ];
609
+ const candidates = ["vitest.config.ts", "vitest.config.js", "vitest.config.mjs"];
577
610
  for (const file of candidates) {
578
611
  const fullPath = path.join(baseDir, file);
579
612
  if (fs$1.existsSync(fullPath)) {
@@ -597,7 +630,9 @@ async function loadVitestCoverageConfig() {
597
630
  };
598
631
  }
599
632
  async function loadPlaywrightCoverageConfig() {
600
- const options = await loadCoverageOptions({ optional: true });
633
+ const options = await loadCoverageOptions({
634
+ optional: true
635
+ });
601
636
  if (!options) {
602
637
  return null;
603
638
  }
@@ -618,14 +653,23 @@ function resolveCombinedCoverage(playwrightCoverage, vitestCoverage) {
618
653
  }
619
654
  async function cleanCoverageArtifacts(config) {
620
655
  await removeCoverageFiles(config);
621
- await fs.rm(config.coverageReportDir, { recursive: true, force: true });
622
- await fs.rm(resolveNodeCoverageDir(config), { recursive: true, force: true });
656
+ await fs.rm(config.coverageReportDir, {
657
+ recursive: true,
658
+ force: true
659
+ });
660
+ await fs.rm(resolveNodeCoverageDir(config), {
661
+ recursive: true,
662
+ force: true
663
+ });
623
664
  }
624
665
  function resolveNodeCoverageDir(config) {
625
666
  return path.join(config.rootDir, "build", "vitest", "test-results", "node-coverage");
626
667
  }
627
668
  async function convertNodeCoverage(coverage) {
628
- const { config, nodeCoverageDir } = coverage;
669
+ const {
670
+ config,
671
+ nodeCoverageDir
672
+ } = coverage;
629
673
  const entries = await fs.readdir(nodeCoverageDir).catch(() => []);
630
674
  const scripts = [];
631
675
  const scriptRoots = resolveCollectCoverageRoots(config.collectCoverageFrom, config.rootDir);
@@ -661,9 +705,14 @@ async function convertNodeCoverage(coverage) {
661
705
  return;
662
706
  }
663
707
  const outDir = path.join(config.rootDir, "build", "vitest", "coverage");
664
- await fs.mkdir(outDir, { recursive: true });
708
+ await fs.mkdir(outDir, {
709
+ recursive: true
710
+ });
665
711
  const outputFile = path.join(outDir, config.coverageFileName);
666
- await fs.writeFile(outputFile, JSON.stringify({ testId: "vitest", scripts }, null, 2), "utf8");
712
+ await fs.writeFile(outputFile, JSON.stringify({
713
+ testId: "vitest",
714
+ scripts
715
+ }, null, 2), "utf8");
667
716
  }
668
717
  async function finalizeCoverage(config) {
669
718
  try {
@@ -720,14 +769,10 @@ function spawnWithLogs({
720
769
  return new Promise((resolve, reject) => {
721
770
  const stdoutBuffer = [];
722
771
  const stderrBuffer = [];
723
- const child = spawn(
724
- launcher.command,
725
- [...launcher.args || [], ...args],
726
- {
727
- shell: false,
728
- env
729
- }
730
- );
772
+ const child = spawn(launcher.command, [...launcher.args || [], ...args], {
773
+ shell: false,
774
+ env
775
+ });
731
776
  child.stdout?.on("data", (data) => {
732
777
  if (!isAider) {
733
778
  process.stdout.write(data);
@@ -774,12 +819,20 @@ function withRegisterShim(baseEnv) {
774
819
  }
775
820
  function ensureJsxRuntimeShim(projectRoot) {
776
821
  const shimDir = path.join(projectRoot, "node_modules", "playwright");
777
- fs$1.mkdirSync(shimDir, { recursive: true });
778
- const shims = [
779
- { file: "jsx-runtime.js", target: "react/jsx-runtime" },
780
- { file: "jsx-dev-runtime.js", target: "react/jsx-dev-runtime" }
781
- ];
782
- for (const { file, target } of shims) {
822
+ fs$1.mkdirSync(shimDir, {
823
+ recursive: true
824
+ });
825
+ const shims = [{
826
+ file: "jsx-runtime.js",
827
+ target: "react/jsx-runtime"
828
+ }, {
829
+ file: "jsx-dev-runtime.js",
830
+ target: "react/jsx-dev-runtime"
831
+ }];
832
+ for (const {
833
+ file,
834
+ target
835
+ } of shims) {
783
836
  const filePath = path.join(shimDir, file);
784
837
  if (!fs$1.existsSync(filePath)) {
785
838
  const content = `export * from "${target}";