@nexustools/nwjstestrunner 0.0.0-stage → 1.0.0-beta.1

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 (79) hide show
  1. package/AGENTS.md +21 -0
  2. package/README.md +142 -2
  3. package/bin/nwjstestrunner.js +13 -0
  4. package/dist/cli/nwjs-cli-launcher.d.ts +10 -0
  5. package/dist/cli/nwjs-cli-launcher.d.ts.map +1 -0
  6. package/dist/cli/nwjs-cli-launcher.js +281 -0
  7. package/dist/cli/nwjs-cli-launcher.js.map +1 -0
  8. package/dist/config/harness-config-loader.d.ts +10 -0
  9. package/dist/config/harness-config-loader.d.ts.map +1 -0
  10. package/dist/config/harness-config-loader.js +242 -0
  11. package/dist/config/harness-config-loader.js.map +1 -0
  12. package/dist/core/test-runner.d.ts +61 -0
  13. package/dist/core/test-runner.d.ts.map +1 -0
  14. package/dist/core/test-runner.js +450 -0
  15. package/dist/core/test-runner.js.map +1 -0
  16. package/dist/esm/index.d.mts +2 -0
  17. package/dist/esm/index.mjs +26 -0
  18. package/dist/harness/graphical-overlay-view.d.ts +18 -0
  19. package/dist/harness/graphical-overlay-view.d.ts.map +1 -0
  20. package/dist/harness/graphical-overlay-view.js +213 -0
  21. package/dist/harness/graphical-overlay-view.js.map +1 -0
  22. package/dist/harness/nwjs-graphical-test-harness.d.ts +40 -0
  23. package/dist/harness/nwjs-graphical-test-harness.d.ts.map +1 -0
  24. package/dist/harness/nwjs-graphical-test-harness.js +398 -0
  25. package/dist/harness/nwjs-graphical-test-harness.js.map +1 -0
  26. package/dist/harness/test-http-server.d.ts +12 -0
  27. package/dist/harness/test-http-server.d.ts.map +1 -0
  28. package/dist/harness/test-http-server.js +183 -0
  29. package/dist/harness/test-http-server.js.map +1 -0
  30. package/dist/harness/test-log-writer.d.ts +29 -0
  31. package/dist/harness/test-log-writer.d.ts.map +1 -0
  32. package/dist/harness/test-log-writer.js +173 -0
  33. package/dist/harness/test-log-writer.js.map +1 -0
  34. package/dist/harness/webview-test-controller.d.ts +18 -0
  35. package/dist/harness/webview-test-controller.d.ts.map +1 -0
  36. package/dist/harness/webview-test-controller.js +163 -0
  37. package/dist/harness/webview-test-controller.js.map +1 -0
  38. package/dist/index.d.ts +13 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +52 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/matchers/deep-equality-helper.d.ts +10 -0
  43. package/dist/matchers/deep-equality-helper.d.ts.map +1 -0
  44. package/dist/matchers/deep-equality-helper.js +188 -0
  45. package/dist/matchers/deep-equality-helper.js.map +1 -0
  46. package/dist/matchers/expect-matcher.d.ts +7 -0
  47. package/dist/matchers/expect-matcher.d.ts.map +1 -0
  48. package/dist/matchers/expect-matcher.js +261 -0
  49. package/dist/matchers/expect-matcher.js.map +1 -0
  50. package/dist/mock/jest-mock-factory.d.ts +20 -0
  51. package/dist/mock/jest-mock-factory.d.ts.map +1 -0
  52. package/dist/mock/jest-mock-factory.js +141 -0
  53. package/dist/mock/jest-mock-factory.js.map +1 -0
  54. package/dist/tests/NwjsTestRunnerSuites.d.ts +3 -0
  55. package/dist/tests/NwjsTestRunnerSuites.d.ts.map +1 -0
  56. package/dist/tests/NwjsTestRunnerSuites.js +266 -0
  57. package/dist/tests/NwjsTestRunnerSuites.js.map +1 -0
  58. package/dist/types/test-runner-types.d.ts +321 -0
  59. package/dist/types/test-runner-types.d.ts.map +1 -0
  60. package/dist/types/test-runner-types.js +3 -0
  61. package/dist/types/test-runner-types.js.map +1 -0
  62. package/package.json +56 -4
  63. package/runner/demo-client.html +70 -0
  64. package/runner/index.html +223 -0
  65. package/runner/package.json +27 -0
  66. package/src/cli/nwjs-cli-launcher.ts +243 -0
  67. package/src/config/harness-config-loader.ts +214 -0
  68. package/src/core/test-runner.ts +553 -0
  69. package/src/harness/graphical-overlay-view.ts +219 -0
  70. package/src/harness/nwjs-graphical-test-harness.ts +468 -0
  71. package/src/harness/test-http-server.ts +162 -0
  72. package/src/harness/test-log-writer.ts +154 -0
  73. package/src/harness/webview-test-controller.ts +192 -0
  74. package/src/index.ts +28 -0
  75. package/src/matchers/deep-equality-helper.ts +193 -0
  76. package/src/matchers/expect-matcher.ts +361 -0
  77. package/src/mock/jest-mock-factory.ts +170 -0
  78. package/src/tests/NwjsTestRunnerSuites.ts +267 -0
  79. package/src/types/test-runner-types.ts +335 -0
@@ -0,0 +1,214 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { NwjsCliOptions, NwjsHarnessConfig } from '../types/test-runner-types';
4
+
5
+ export class HarnessConfigLoader {
6
+ public static resolveProjectRoot(explicitRoot?: string): string {
7
+ if (explicitRoot) {
8
+ return path.resolve(explicitRoot);
9
+ }
10
+ const envRoot = process.env.NWJS_TEST_PROJECT_ROOT;
11
+ if (envRoot) {
12
+ return path.resolve(envRoot);
13
+ }
14
+ const cwd = process.cwd();
15
+ if (path.basename(cwd).toLowerCase() === 'testrunner' || path.basename(cwd).toLowerCase() === 'runner') {
16
+ const parentPkg = path.resolve(cwd, '..', 'package.json');
17
+ if (fs.existsSync(parentPkg)) {
18
+ return path.resolve(cwd, '..');
19
+ }
20
+ }
21
+ return cwd;
22
+ }
23
+
24
+ public static findConfigFile(projectRootDir: string, explicitConfigPath?: string): string | null {
25
+ if (explicitConfigPath) {
26
+ const resolved = path.isAbsolute(explicitConfigPath)
27
+ ? explicitConfigPath
28
+ : path.resolve(projectRootDir, explicitConfigPath);
29
+ return fs.existsSync(resolved) ? resolved : null;
30
+ }
31
+
32
+ const envConfig = process.env.NWJS_TEST_CONFIG_PATH;
33
+ if (envConfig && fs.existsSync(envConfig)) {
34
+ return path.resolve(envConfig);
35
+ }
36
+
37
+ const candidates = [
38
+ 'nwjstestrunner.config.cjs',
39
+ 'nwjstestrunner.config.js',
40
+ 'nwjstestrunner.config.json'
41
+ ];
42
+ for (const filename of candidates) {
43
+ const candidatePath = path.join(projectRootDir, filename);
44
+ if (fs.existsSync(candidatePath) && fs.statSync(candidatePath).isFile()) {
45
+ return candidatePath;
46
+ }
47
+ }
48
+
49
+ return null;
50
+ }
51
+
52
+ public static loadConfig(
53
+ projectRootDir?: string,
54
+ explicitConfigPath?: string,
55
+ cliOverrides?: NwjsCliOptions
56
+ ): NwjsHarnessConfig {
57
+ const resolvedRoot = HarnessConfigLoader.resolveProjectRoot(
58
+ cliOverrides?.projectRootDir || projectRootDir
59
+ );
60
+ let loadedConfig: Partial<NwjsHarnessConfig> = {};
61
+
62
+ const configFile = HarnessConfigLoader.findConfigFile(
63
+ resolvedRoot,
64
+ cliOverrides?.configPath || explicitConfigPath
65
+ );
66
+
67
+ if (configFile) {
68
+ if (configFile.endsWith('.json')) {
69
+ const raw = fs.readFileSync(configFile, 'utf-8');
70
+ loadedConfig = JSON.parse(raw);
71
+ } else {
72
+ // Clear require cache so fresh config is loaded
73
+ try {
74
+ delete require.cache[require.resolve(configFile)];
75
+ } catch (_e) {}
76
+ const mod = require(configFile);
77
+ loadedConfig = mod && mod.default ? mod.default : mod;
78
+ }
79
+ } else {
80
+ const pkgJsonPath = path.join(resolvedRoot, 'package.json');
81
+ if (fs.existsSync(pkgJsonPath)) {
82
+ try {
83
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8'));
84
+ if (pkg && pkg.nwjstestrunner && typeof pkg.nwjstestrunner === 'object') {
85
+ loadedConfig = pkg.nwjstestrunner;
86
+ }
87
+ } catch (_e) {}
88
+ }
89
+ }
90
+
91
+ const envOverrides: Partial<NwjsHarnessConfig> = {};
92
+ if (process.env.NWJS_TEST_CLI_OVERRIDES) {
93
+ try {
94
+ Object.assign(envOverrides, JSON.parse(process.env.NWJS_TEST_CLI_OVERRIDES));
95
+ } catch (_e) {}
96
+ }
97
+
98
+ const merged: NwjsHarnessConfig = {
99
+ projectRootDir: resolvedRoot,
100
+ ...loadedConfig,
101
+ ...envOverrides
102
+ };
103
+
104
+ if (cliOverrides) {
105
+ if (cliOverrides.projectRootDir) merged.projectRootDir = path.resolve(cliOverrides.projectRootDir);
106
+ if (cliOverrides.testFiles && cliOverrides.testFiles.length > 0) {
107
+ merged.testFiles = cliOverrides.testFiles;
108
+ }
109
+ if (cliOverrides.testFilter !== undefined) merged.testFilter = cliOverrides.testFilter;
110
+ if (cliOverrides.logPath) merged.testLogPath = path.resolve(resolvedRoot, cliOverrides.logPath);
111
+ if (cliOverrides.title) merged.title = cliOverrides.title;
112
+ if (cliOverrides.webviewEntryHtml) merged.webviewEntryHtml = cliOverrides.webviewEntryHtml;
113
+ if (cliOverrides.enableWebview !== undefined) merged.enableWebview = cliOverrides.enableWebview;
114
+ if (cliOverrides.initTimeoutMs !== undefined) merged.initTimeoutMs = cliOverrides.initTimeoutMs;
115
+ if (cliOverrides.globalTimeoutMs !== undefined) merged.globalTimeoutMs = cliOverrides.globalTimeoutMs;
116
+ if (cliOverrides.keepOpen !== undefined) merged.keepOpen = cliOverrides.keepOpen;
117
+ }
118
+
119
+ return merged;
120
+ }
121
+
122
+ public static resolveTestFiles(projectRootDir: string, patterns?: string[]): string[] {
123
+ const root = path.resolve(projectRootDir);
124
+ if (patterns && patterns.length > 0) {
125
+ const resolved = new Set<string>();
126
+ for (const pattern of patterns) {
127
+ if (!pattern.includes('*')) {
128
+ const direct = path.isAbsolute(pattern) ? pattern : path.resolve(root, pattern);
129
+ if (fs.existsSync(direct) && fs.statSync(direct).isFile()) {
130
+ resolved.add(direct);
131
+ }
132
+ } else {
133
+ const matches = HarnessConfigLoader.walkMatchingFiles(root, pattern);
134
+ for (const m of matches) {
135
+ resolved.add(m);
136
+ }
137
+ }
138
+ }
139
+ return Array.from(resolved);
140
+ }
141
+
142
+ // Default auto-discovery in dist/ or tests/
143
+ const searchDirs = ['dist', 'tests', 'test'];
144
+ const discovered: string[] = [];
145
+ for (const sub of searchDirs) {
146
+ const dirPath = path.join(root, sub);
147
+ if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
148
+ HarnessConfigLoader.collectDefaultTestFiles(dirPath, discovered);
149
+ }
150
+ }
151
+ return discovered;
152
+ }
153
+
154
+ private static collectDefaultTestFiles(dir: string, out: string[]): void {
155
+ let entries: fs.Dirent[] = [];
156
+ try {
157
+ entries = fs.readdirSync(dir, { withFileTypes: true });
158
+ } catch (_e) {
159
+ return;
160
+ }
161
+ for (const entry of entries) {
162
+ if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue;
163
+ const fullPath = path.join(dir, entry.name);
164
+ if (entry.isDirectory()) {
165
+ HarnessConfigLoader.collectDefaultTestFiles(fullPath, out);
166
+ } else if (
167
+ entry.isFile() &&
168
+ (entry.name.endsWith('.test.js') ||
169
+ entry.name.endsWith('.spec.js') ||
170
+ entry.name.endsWith('Suites.js'))
171
+ ) {
172
+ out.push(fullPath);
173
+ }
174
+ }
175
+ }
176
+
177
+ private static walkMatchingFiles(rootDir: string, pattern: string): string[] {
178
+ const normalizedPattern = pattern.replace(/\\/g, '/');
179
+ const regexStr =
180
+ '^' +
181
+ normalizedPattern
182
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
183
+ .replace(/\*\*\//g, '(?:.+/)?')
184
+ .replace(/\*\*/g, '.*')
185
+ .replace(/\*/g, '[^/]*') +
186
+ '$';
187
+ const regex = new RegExp(regexStr, 'i');
188
+ const results: string[] = [];
189
+
190
+ const walk = (currentDir: string) => {
191
+ let entries: fs.Dirent[] = [];
192
+ try {
193
+ entries = fs.readdirSync(currentDir, { withFileTypes: true });
194
+ } catch (_e) {
195
+ return;
196
+ }
197
+ for (const entry of entries) {
198
+ if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue;
199
+ const fullPath = path.join(currentDir, entry.name);
200
+ if (entry.isDirectory()) {
201
+ walk(fullPath);
202
+ } else if (entry.isFile()) {
203
+ const rel = path.relative(rootDir, fullPath).replace(/\\/g, '/');
204
+ if (regex.test(rel)) {
205
+ results.push(fullPath);
206
+ }
207
+ }
208
+ }
209
+ };
210
+
211
+ walk(rootDir);
212
+ return results;
213
+ }
214
+ }