@wp-tester/cli 0.0.4 → 0.1.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.
@@ -4,34 +4,50 @@ import * as clack from '../../cli/theme.js';
4
4
  import { runSmokeTests } from "@wp-tester/smoke-tests";
5
5
  import { runPhpunitTests } from "@wp-tester/phpunit";
6
6
  import { mergeReports, printSummary } from "@wp-tester/results";
7
- import { mergePhpunitArgs } from "@wp-tester/config";
7
+ import { resolveConfig } from "@wp-tester/config";
8
+ import { validateConfig } from "../config/validate.js";
9
+ import { getConfigPath } from "@wp-tester/config";
10
+ /**
11
+ * Apply --failed-only CLI override to config reporters.
12
+ * Sets all filter options to false except failed: true.
13
+ */
14
+ function applyFailedOnlyOverride(config) {
15
+ const failedOnlyFilter = {
16
+ passed: false,
17
+ failed: true,
18
+ skipped: false,
19
+ pending: false,
20
+ other: false,
21
+ };
22
+ return {
23
+ ...config,
24
+ reporters: {
25
+ ...config.reporters,
26
+ default: config.reporters?.default !== undefined
27
+ ? typeof config.reporters.default === "object"
28
+ ? { ...config.reporters.default, ...failedOnlyFilter }
29
+ : failedOnlyFilter
30
+ : failedOnlyFilter,
31
+ },
32
+ };
33
+ }
8
34
  async function resolveConfigPath(configPath) {
9
- const resolvedPath = path.resolve(process.cwd(), configPath);
35
+ const resolvedPath = getConfigPath(configPath);
10
36
  try {
11
37
  const stats = await stat(resolvedPath);
12
38
  if (stats.isDirectory()) {
13
- const configFile = path.join(resolvedPath, "wp-tester.json");
14
- try {
15
- await access(configFile, constants.F_OK);
16
- return configFile;
17
- }
18
- catch {
19
- clack.log.error(`Config file not found in directory: ${resolvedPath}`);
20
- clack.log.error("Please provide a path to a valid WP Tester config file.");
21
- process.exit(1);
22
- }
39
+ return path.join(resolvedPath, "wp-tester.json");
23
40
  }
24
41
  }
25
42
  catch {
26
- clack.log.error(`Path not found: ${resolvedPath}`);
27
- clack.log.error("Please provide a path to a valid WP Tester config file.");
28
- process.exit(1);
43
+ // File doesn't exist yet, but that's ok - return the resolved path
44
+ // The caller will handle the missing file case
29
45
  }
30
46
  return resolvedPath;
31
47
  }
32
48
  async function checkConfigExists(configPath) {
33
49
  try {
34
- const resolvedPath = path.resolve(process.cwd(), configPath);
50
+ const resolvedPath = getConfigPath(configPath);
35
51
  await access(resolvedPath, constants.F_OK);
36
52
  return true;
37
53
  }
@@ -50,31 +66,22 @@ function getSmokeTestFilter(testType) {
50
66
  }
51
67
  return smokeTestTypes.includes(testType) ? testType : false;
52
68
  }
53
- export const runTests = async (configPath, testType, phpunitArgs) => {
54
- let finalConfigPath = await resolveConfigPath(configPath);
55
- // Check if config file exists
56
- while (!(await checkConfigExists(finalConfigPath))) {
57
- const resolvedPath = path.resolve(process.cwd(), finalConfigPath);
58
- clack.log.error(`Config file not found: ${resolvedPath}`);
59
- const newPath = await clack.text({
60
- message: "Enter the correct path to your config file:",
61
- placeholder: "./wp-tester.json",
62
- validate: (value) => {
63
- if (!value)
64
- return "Config path is required";
65
- },
66
- });
67
- if (clack.isCancel(newPath)) {
68
- clack.cancel("Test cancelled.");
69
- process.exit(0);
70
- }
71
- finalConfigPath = newPath;
69
+ /**
70
+ * Execute tests and return results without exiting the process.
71
+ * Used internally and by watch mode.
72
+ */
73
+ export const executeTests = async (configPath, options) => {
74
+ const { testType, extraArgs, failedOnly } = options || {};
75
+ const finalConfigPath = await resolveConfigPath(configPath);
76
+ // Validate configuration before running tests
77
+ const isValid = await validateConfig(finalConfigPath);
78
+ if (!isValid) {
79
+ process.exit(1);
72
80
  }
73
- const absoluteConfigPath = path.resolve(process.cwd(), finalConfigPath);
74
- // Load and merge config with CLI args
75
- let configForTests = absoluteConfigPath;
76
- if (phpunitArgs && phpunitArgs.length > 0) {
77
- configForTests = await mergePhpunitArgs(absoluteConfigPath, phpunitArgs);
81
+ // Resolve config and apply CLI overrides
82
+ let resolvedConfig = await resolveConfig(finalConfigPath);
83
+ if (failedOnly) {
84
+ resolvedConfig = applyFailedOnlyOverride(resolvedConfig);
78
85
  }
79
86
  // Run all test suites and collect results
80
87
  const reports = [];
@@ -82,29 +89,76 @@ export const runTests = async (configPath, testType, phpunitArgs) => {
82
89
  const shouldRunPhpUnit = !testType || testType === "phpunit";
83
90
  // Run smoke tests (wp, plugin, theme) - smoke tests package handles whether to run
84
91
  const smokeTestFilter = getSmokeTestFilter(testType);
85
- const smokeTestReport = await runSmokeTests(absoluteConfigPath, smokeTestFilter);
86
- if (smokeTestReport.results.summary.tests > 0) {
87
- reports.push(smokeTestReport);
92
+ if (smokeTestFilter !== false) {
93
+ const smokeTestReport = await runSmokeTests(resolvedConfig, smokeTestFilter, extraArgs);
94
+ if (smokeTestReport.results.summary.tests > 0) {
95
+ reports.push(smokeTestReport);
96
+ }
88
97
  }
89
98
  // Run PHPUnit tests
90
99
  if (shouldRunPhpUnit) {
91
- const phpunitReport = await runPhpunitTests(configForTests);
100
+ const phpunitReport = await runPhpunitTests(resolvedConfig, extraArgs);
101
+ // Always include report if PHPUnit was configured to run
102
+ // This ensures bootstrap failures are visible
92
103
  if (phpunitReport.results.summary.tests > 0) {
93
104
  reports.push(phpunitReport);
94
105
  }
95
106
  }
96
- // Merge all reports
107
+ // No tests were run
97
108
  if (reports.length === 0) {
98
109
  clack.log.error("No tests were run. Check your configuration.");
99
- process.exit(1);
110
+ return { success: false, hasTests: false };
100
111
  }
101
112
  // Merge results from all test suites
102
113
  const mergedReport = mergeReports(reports);
103
114
  // Display unified summary
104
115
  const { summary } = mergedReport.results;
105
116
  const success = summary.failed === 0;
106
- // Print final combined summary
107
- printSummary(summary);
108
- process.exit(success ? 0 : 1);
117
+ // Print final combined summary with default reporter options
118
+ const defaultReporterOptions = resolvedConfig.reporters?.default;
119
+ // Convert reporter options to summary options (handle boolean shorthand)
120
+ // When false or true (boolean shorthand), pass undefined to use printSummary defaults
121
+ // When an object, pass it directly since SummaryOptions now matches BaseReporterOptions
122
+ const summaryOptions = typeof defaultReporterOptions === "object"
123
+ ? defaultReporterOptions
124
+ : undefined;
125
+ printSummary(summary, summaryOptions);
126
+ return { success, hasTests: true };
127
+ };
128
+ export const runTests = async (configPath, options) => {
129
+ const { passWithNoTests } = options || {};
130
+ let finalConfigPath = await resolveConfigPath(configPath);
131
+ // Check if config file exists
132
+ while (!(await checkConfigExists(finalConfigPath))) {
133
+ const resolvedPath = getConfigPath(finalConfigPath);
134
+ clack.log.error(`Config file not found: ${resolvedPath}`);
135
+ const newPath = await clack.text({
136
+ message: "Enter the correct path to your config file:",
137
+ placeholder: "./wp-tester.json",
138
+ validate: (value) => {
139
+ if (!value)
140
+ return "Config path is required";
141
+ },
142
+ });
143
+ if (clack.isCancel(newPath)) {
144
+ clack.cancel("Test cancelled.");
145
+ process.exit(0);
146
+ }
147
+ finalConfigPath = newPath;
148
+ }
149
+ const result = await executeTests(finalConfigPath, options);
150
+ if (!result.hasTests) {
151
+ // If passWithNoTests is enabled, treat no tests as success
152
+ if (passWithNoTests) {
153
+ clack.log.info("No tests were run. Check your configuration.");
154
+ process.exit(0);
155
+ }
156
+ process.exit(1);
157
+ }
158
+ // Determine exit code based on test results
159
+ if (!result.success) {
160
+ process.exit(1);
161
+ }
162
+ process.exit(0);
109
163
  };
110
164
  //# sourceMappingURL=runner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/commands/test/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/commands/test/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface WatchOptions {
2
+ configPath: string;
3
+ onRunTests: () => Promise<void>;
4
+ }
5
+ export declare function runWatchMode(options: WatchOptions): Promise<void>;
6
+ //# sourceMappingURL=watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../../src/commands/test/watcher.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAiDD,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsJvE"}
@@ -0,0 +1,173 @@
1
+ import { watch } from 'fs';
2
+ import picomatch from 'picomatch';
3
+ import * as clack from '../../cli/theme.js';
4
+ import { getProjectDir, readConfigFile, normalizeConfigPath } from '@wp-tester/config';
5
+ // Default patterns to exclude when watching for changes
6
+ const DEFAULT_EXCLUDE_PATTERNS = [
7
+ '**/node_modules/**',
8
+ '**/vendor/**',
9
+ '**/.git/**',
10
+ '**/.svn/**',
11
+ '**/.hg/**',
12
+ '**/.DS_Store',
13
+ '**/Thumbs.db',
14
+ ];
15
+ function createWatchMatcher(watchConfig) {
16
+ // Merge default excludes with user-provided excludes
17
+ const excludePatterns = watchConfig?.exclude ?? DEFAULT_EXCLUDE_PATTERNS;
18
+ const includePatterns = watchConfig?.include;
19
+ // Create picomatch matchers
20
+ const excludeMatcher = picomatch(excludePatterns, { dot: true });
21
+ const includeMatcher = includePatterns
22
+ ? picomatch(includePatterns, { dot: true })
23
+ : null;
24
+ return {
25
+ shouldWatch: (filePath) => {
26
+ // Normalize path separators for cross-platform compatibility
27
+ const normalizedPath = filePath.replace(/\\/g, '/');
28
+ // Check if file should be excluded
29
+ if (excludeMatcher(normalizedPath)) {
30
+ return false;
31
+ }
32
+ // Check include patterns if specified
33
+ if (includeMatcher) {
34
+ return includeMatcher(normalizedPath);
35
+ }
36
+ // No include patterns means watch everything (that's not excluded)
37
+ return true;
38
+ },
39
+ };
40
+ }
41
+ export async function runWatchMode(options) {
42
+ const { configPath, onRunTests } = options;
43
+ // Resolve config to get the project directory and watch settings
44
+ const config = await readConfigFile(configPath);
45
+ // Normalize config path to handle directory paths (appends wp-tester.json if needed)
46
+ const normalizedConfigPath = normalizeConfigPath(configPath);
47
+ const projectDir = getProjectDir(config, normalizedConfigPath);
48
+ const watchConfig = config.tests.watch;
49
+ // Create the file matcher
50
+ const matcher = createWatchMatcher(watchConfig);
51
+ // Always watch the project directory, use matcher to filter files
52
+ clack.log.info(`Watching for changes in: ${projectDir}`);
53
+ if (watchConfig?.include) {
54
+ clack.log.step(`Include patterns: ${watchConfig.include.join(", ")}`);
55
+ }
56
+ if (watchConfig?.exclude) {
57
+ clack.log.step(`Exclude patterns: ${watchConfig.exclude.join(", ")}`);
58
+ }
59
+ clack.log.info("Press Enter to re-run tests, or q to quit.\n");
60
+ let isRunning = false;
61
+ let pendingRun = false;
62
+ let debounceTimer = null;
63
+ let watcher = null;
64
+ const runTests = async () => {
65
+ if (isRunning) {
66
+ pendingRun = true;
67
+ return;
68
+ }
69
+ isRunning = true;
70
+ // Clear screen and move cursor to top-left using ANSI escape codes
71
+ // \x1b[2J clears the entire screen, \x1b[3J clears scrollback, \x1b[H moves cursor to home
72
+ // This is more reliable than console.clear() in watch mode
73
+ process.stdout.write('\x1b[2J\x1b[3J\x1b[H');
74
+ clack.log.info(" Test run\n");
75
+ try {
76
+ await onRunTests();
77
+ }
78
+ catch (error) {
79
+ // Tests may exit with non-zero code, which is expected
80
+ if (error instanceof Error && !error.message.includes("process.exit")) {
81
+ clack.log.error(`Error running tests: ${error.message}`);
82
+ }
83
+ }
84
+ finally {
85
+ isRunning = false;
86
+ clack.log.info("Watching for changes... (Enter to re-run, q to quit)");
87
+ if (pendingRun) {
88
+ pendingRun = false;
89
+ await runTests();
90
+ }
91
+ }
92
+ };
93
+ const scheduleRun = () => {
94
+ if (debounceTimer) {
95
+ clearTimeout(debounceTimer);
96
+ }
97
+ // Debounce file changes - wait 300ms before running tests
98
+ debounceTimer = setTimeout(() => {
99
+ void runTests();
100
+ }, 300);
101
+ };
102
+ // Set up file watcher
103
+ try {
104
+ watcher = watch(projectDir, { recursive: true }, (eventType, filename) => {
105
+ if (filename && matcher.shouldWatch(filename)) {
106
+ scheduleRun();
107
+ }
108
+ });
109
+ watcher.on("error", (error) => {
110
+ clack.log.error(`Watcher error: ${error.message}`);
111
+ });
112
+ }
113
+ catch (error) {
114
+ if (error instanceof Error) {
115
+ clack.log.error(`Failed to start watcher: ${error.message}`);
116
+ }
117
+ process.exit(1);
118
+ }
119
+ // Set up keyboard input handling
120
+ if (process.stdin.isTTY) {
121
+ process.stdin.setRawMode(true);
122
+ process.stdin.resume();
123
+ process.stdin.setEncoding("utf8");
124
+ process.stdin.on("data", (key) => {
125
+ // Handle Ctrl+C
126
+ if (key === "\u0003") {
127
+ cleanup();
128
+ process.exit(0);
129
+ }
130
+ // Handle 'q' or 'Q' to quit
131
+ if (key === "q" || key === "Q") {
132
+ cleanup();
133
+ process.exit(0);
134
+ }
135
+ // Handle Enter to re-run tests
136
+ if (key === "\r" || key === "\n") {
137
+ scheduleRun();
138
+ }
139
+ });
140
+ }
141
+ const onSigint = () => {
142
+ cleanup();
143
+ process.exit(0);
144
+ };
145
+ const onSigterm = () => {
146
+ cleanup();
147
+ process.exit(0);
148
+ };
149
+ const cleanup = () => {
150
+ if (debounceTimer) {
151
+ clearTimeout(debounceTimer);
152
+ }
153
+ if (watcher) {
154
+ watcher.close();
155
+ }
156
+ if (process.stdin.isTTY) {
157
+ process.stdin.setRawMode(false);
158
+ }
159
+ process.off("SIGINT", onSigint);
160
+ process.off("SIGTERM", onSigterm);
161
+ clack.log.info('\nWatch mode stopped.');
162
+ };
163
+ // Handle process termination
164
+ process.on("SIGINT", onSigint);
165
+ process.on("SIGTERM", onSigterm);
166
+ // Run tests initially
167
+ await runTests();
168
+ // Keep the process alive
169
+ await new Promise(() => {
170
+ // This promise never resolves, keeping watch mode running
171
+ });
172
+ }
173
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../../src/commands/test/watcher.ts"],"names":[],"mappings":"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"}