@testspectra/react 1.1.8-rc.18 → 1.1.8-rc.20

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 (2) hide show
  1. package/package.json +4 -3
  2. package/vitest.config.ts +117 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testspectra/react",
3
- "version": "1.1.8-rc.18",
3
+ "version": "1.1.8-rc.20",
4
4
  "description": "Bundled Vitest browser-mode runner for React component testing with the TestSpectra Spectra.* DSL",
5
5
  "keywords": [
6
6
  "testspectra",
@@ -31,7 +31,8 @@
31
31
  },
32
32
  "files": [
33
33
  "dist",
34
- "bin"
34
+ "bin",
35
+ "vitest.config.ts"
35
36
  ],
36
37
  "dependencies": {
37
38
  "@testing-library/react": "^16.0.0",
@@ -41,7 +42,7 @@
41
42
  "cross-spawn": "^7.0.6",
42
43
  "playwright": "^1.48.0",
43
44
  "vitest": "^2.1.8",
44
- "@testspectra/matchers": "1.1.8-rc.18"
45
+ "@testspectra/matchers": "1.1.8-rc.20"
45
46
  },
46
47
  "peerDependencies": {
47
48
  "react": ">=18.0.0",
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Bundled Vitest browser-mode configuration for @testspectra/react.
3
+ *
4
+ * Consumers never author this file themselves — `spectra test` / `testspectra-react test` loads
5
+ * it programmatically (see src/cli.ts). `root` is deliberately kept fixed at THIS package's own
6
+ * directory (not the consumer's project) — `@vitest/browser`'s transitive dependencies
7
+ * (`@testing-library/dom`, `@testing-library/user-event`) live under this package's own
8
+ * `node_modules` under pnpm's strict per-package isolation, and Vite's dependency optimizer
9
+ * fails to resolve them if `root` points elsewhere. Test discovery and auto-import instead use
10
+ * absolute paths built from `TESTSPECTRA_TEST_ROOT` (see auto_import.ts and cli.ts).
11
+ */
12
+
13
+ import { readdirSync, existsSync } from 'node:fs';
14
+ import path from 'node:path';
15
+ import { fileURLToPath } from 'node:url';
16
+
17
+ import react from '@vitejs/plugin-react';
18
+ import { defineConfig } from 'vitest/config';
19
+
20
+ const packageDir = fileURLToPath(new URL('.', import.meta.url));
21
+ const setupFile = path.join(packageDir, 'src/setup.ts');
22
+ const testRoot = (process.env.TESTSPECTRA_TEST_ROOT || process.cwd()).replace(/\\/g, '/');
23
+
24
+ /** Scans <testRoot>/page-objects, /support/steps, /fixtures — mirrors the Rust orchestrator's
25
+ * AutoImportManifest scan for E2E (docs/v2/cli/ambient-types-generator.md), reimplemented here
26
+ * in Node (this config file), since there is no Rust orchestrator in this mode. */
27
+ function buildAutoImportManifest(root: string) {
28
+ function scanEntityDir(subdir: string, filePattern: (platform: string) => string) {
29
+ const dir = path.join(root, subdir);
30
+ if (!existsSync(dir)) return [] as Array<{ name: string; path: string }>;
31
+ const entries: Array<{ name: string; path: string }> = [];
32
+ for (const name of readdirSync(dir, { withFileTypes: true })) {
33
+ if (!name.isDirectory()) continue;
34
+ for (const platform of ['web', 'common']) {
35
+ for (const ext of ['tsx', 'ts']) {
36
+ const candidate = path.join(dir, name.name, filePattern(platform).replace(/\.tsx?$/, `.${ext}`));
37
+ if (existsSync(candidate)) {
38
+ entries.push({ name: name.name, path: candidate.replace(/\\/g, '/') });
39
+ break;
40
+ }
41
+ }
42
+ if (entries.at(-1)?.name === name.name) break;
43
+ }
44
+ }
45
+ return entries;
46
+ }
47
+
48
+ function scanFixtures(): Array<{ name: string; path: string }> {
49
+ const dir = path.join(root, 'fixtures');
50
+ if (!existsSync(dir)) return [];
51
+ return readdirSync(dir)
52
+ .filter((f) => f.endsWith('.json'))
53
+ .map((f) => ({ name: f.replace(/\.json$/, ''), path: path.join(dir, f).replace(/\\/g, '/') }));
54
+ }
55
+
56
+ return {
57
+ pageObjects: scanEntityDir('page-objects', (p) => `${p}.tsx`),
58
+ steps: scanEntityDir('support/steps', (p) => `${p}.step.tsx`),
59
+ fixtures: scanFixtures(),
60
+ };
61
+ }
62
+
63
+ export default defineConfig({
64
+ root: packageDir,
65
+ plugins: [react()],
66
+ define: {
67
+ __TESTSPECTRA_AUTO_IMPORT_MANIFEST__: JSON.stringify(buildAutoImportManifest(testRoot)),
68
+ __TESTSPECTRA_STEP_DELAY_MS__: JSON.stringify(Number(process.env.TESTSPECTRA_STEP_DELAY) || 0),
69
+ __TESTSPECTRA_SEMANTIC_REPORTER__: JSON.stringify(process.env.TESTSPECTRA_SEMANTIC_REPORTER === '1'),
70
+ },
71
+ server: {
72
+ fs: { allow: [packageDir, testRoot] },
73
+ },
74
+ test: {
75
+ globals: true,
76
+ setupFiles: [setupFile],
77
+ // When spectra test drives this run, @testspectra/cli's own Reporter (the same semantic,
78
+ // natural-English reporter E2E uses) owns 100% of the terminal output, fed by the
79
+ // [TESTSPECTRA_*] lines emitEvent() now prints (see prelude.ts) — Vitest's own console
80
+ // reporter would just double/clutter that output, so it's silenced here. Standalone
81
+ // `pnpm test` / `testspectra-react test` (this env var unset) keeps Vitest's normal reporter.
82
+ reporters: process.env.TESTSPECTRA_SEMANTIC_REPORTER === '1' ? [] : 'default',
83
+ // When TESTSPECTRA_TEST_ROOT is unset, this is the package's own `pnpm test` run (no consumer
84
+ // spawning it) — discover its own smoke test instead of a nonexistent specs/ under packageDir.
85
+ // When set (spawned by cli.ts for a real consumer), only that consumer's specs/ are included —
86
+ // deliberately NOT this package's own src/__tests__/**, so a consumer's `spectra test` output
87
+ // never shows this package's internal smoke test mixed in.
88
+ dir: process.env.TESTSPECTRA_TEST_ROOT ? testRoot : undefined,
89
+ include: process.env.TESTSPECTRA_TEST_ROOT
90
+ ? ['specs/**/web.test.tsx', 'specs/**/*.test.tsx']
91
+ : ['src/**/*.test.tsx'],
92
+ browser: {
93
+ enabled: true,
94
+ provider: 'playwright',
95
+ name: 'chromium',
96
+ // Vitest's CLI does NOT reliably override a `browser.headless` value already set here by
97
+ // `--browser.headless=false` (verified empirically: the spawned Chromium process still
98
+ // carried `--headless` even with the CLI flag passed) — so headed/headless is threaded
99
+ // through as an env var (set by cli.ts) that this config file, which we fully control,
100
+ // reads directly, instead of depending on Vitest's CLI/config-file merge semantics.
101
+ headless: process.env.TESTSPECTRA_HEADLESS !== 'false',
102
+ // Vitest 2.x browser mode has no numeric worker-count knob (unlike the E2E Rust orchestrator's
103
+ // WorkerSizingEngine) — only this parallel/sequential switch. `spectra test --concurrency 1`
104
+ // maps to sequential; any other value (or omitted) keeps Vitest's own parallel default.
105
+ fileParallelism: process.env.TESTSPECTRA_FILE_PARALLELISM !== 'false',
106
+ // Zero browser-discovery logic lives in this package (see cli.ts's RunComponentTestsOptions
107
+ // comment) — `spectra test` locates the Chrome-for-Testing binary `spectra doctor` already
108
+ // manages for the E2E CDP driver and passes it in via this env var, so component testing
109
+ // reuses that install instead of requiring a separate `playwright install` download. Omitted
110
+ // when run standalone (e.g. this package's own `pnpm test`), where Playwright falls back to
111
+ // its own bundled/downloaded browser.
112
+ providerOptions: process.env.TESTSPECTRA_BROWSER_EXECUTABLE
113
+ ? { launch: { executablePath: process.env.TESTSPECTRA_BROWSER_EXECUTABLE } }
114
+ : undefined,
115
+ },
116
+ },
117
+ });