@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.
- package/AGENTS.md +21 -0
- package/README.md +142 -2
- package/bin/nwjstestrunner.js +13 -0
- package/dist/cli/nwjs-cli-launcher.d.ts +10 -0
- package/dist/cli/nwjs-cli-launcher.d.ts.map +1 -0
- package/dist/cli/nwjs-cli-launcher.js +281 -0
- package/dist/cli/nwjs-cli-launcher.js.map +1 -0
- package/dist/config/harness-config-loader.d.ts +10 -0
- package/dist/config/harness-config-loader.d.ts.map +1 -0
- package/dist/config/harness-config-loader.js +242 -0
- package/dist/config/harness-config-loader.js.map +1 -0
- package/dist/core/test-runner.d.ts +61 -0
- package/dist/core/test-runner.d.ts.map +1 -0
- package/dist/core/test-runner.js +450 -0
- package/dist/core/test-runner.js.map +1 -0
- package/dist/esm/index.d.mts +2 -0
- package/dist/esm/index.mjs +26 -0
- package/dist/harness/graphical-overlay-view.d.ts +18 -0
- package/dist/harness/graphical-overlay-view.d.ts.map +1 -0
- package/dist/harness/graphical-overlay-view.js +213 -0
- package/dist/harness/graphical-overlay-view.js.map +1 -0
- package/dist/harness/nwjs-graphical-test-harness.d.ts +40 -0
- package/dist/harness/nwjs-graphical-test-harness.d.ts.map +1 -0
- package/dist/harness/nwjs-graphical-test-harness.js +398 -0
- package/dist/harness/nwjs-graphical-test-harness.js.map +1 -0
- package/dist/harness/test-http-server.d.ts +12 -0
- package/dist/harness/test-http-server.d.ts.map +1 -0
- package/dist/harness/test-http-server.js +183 -0
- package/dist/harness/test-http-server.js.map +1 -0
- package/dist/harness/test-log-writer.d.ts +29 -0
- package/dist/harness/test-log-writer.d.ts.map +1 -0
- package/dist/harness/test-log-writer.js +173 -0
- package/dist/harness/test-log-writer.js.map +1 -0
- package/dist/harness/webview-test-controller.d.ts +18 -0
- package/dist/harness/webview-test-controller.d.ts.map +1 -0
- package/dist/harness/webview-test-controller.js +163 -0
- package/dist/harness/webview-test-controller.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/dist/matchers/deep-equality-helper.d.ts +10 -0
- package/dist/matchers/deep-equality-helper.d.ts.map +1 -0
- package/dist/matchers/deep-equality-helper.js +188 -0
- package/dist/matchers/deep-equality-helper.js.map +1 -0
- package/dist/matchers/expect-matcher.d.ts +7 -0
- package/dist/matchers/expect-matcher.d.ts.map +1 -0
- package/dist/matchers/expect-matcher.js +261 -0
- package/dist/matchers/expect-matcher.js.map +1 -0
- package/dist/mock/jest-mock-factory.d.ts +20 -0
- package/dist/mock/jest-mock-factory.d.ts.map +1 -0
- package/dist/mock/jest-mock-factory.js +141 -0
- package/dist/mock/jest-mock-factory.js.map +1 -0
- package/dist/tests/NwjsTestRunnerSuites.d.ts +3 -0
- package/dist/tests/NwjsTestRunnerSuites.d.ts.map +1 -0
- package/dist/tests/NwjsTestRunnerSuites.js +266 -0
- package/dist/tests/NwjsTestRunnerSuites.js.map +1 -0
- package/dist/types/test-runner-types.d.ts +321 -0
- package/dist/types/test-runner-types.d.ts.map +1 -0
- package/dist/types/test-runner-types.js +3 -0
- package/dist/types/test-runner-types.js.map +1 -0
- package/package.json +56 -4
- package/runner/demo-client.html +70 -0
- package/runner/index.html +223 -0
- package/runner/package.json +27 -0
- package/src/cli/nwjs-cli-launcher.ts +243 -0
- package/src/config/harness-config-loader.ts +214 -0
- package/src/core/test-runner.ts +553 -0
- package/src/harness/graphical-overlay-view.ts +219 -0
- package/src/harness/nwjs-graphical-test-harness.ts +468 -0
- package/src/harness/test-http-server.ts +162 -0
- package/src/harness/test-log-writer.ts +154 -0
- package/src/harness/webview-test-controller.ts +192 -0
- package/src/index.ts +28 -0
- package/src/matchers/deep-equality-helper.ts +193 -0
- package/src/matchers/expect-matcher.ts +361 -0
- package/src/mock/jest-mock-factory.ts +170 -0
- package/src/tests/NwjsTestRunnerSuites.ts +267 -0
- 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
|
+
}
|