@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,335 @@
|
|
|
1
|
+
import * as http from 'http';
|
|
2
|
+
|
|
3
|
+
export interface TestFailure {
|
|
4
|
+
suiteName: string;
|
|
5
|
+
testName: string;
|
|
6
|
+
error: Error;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface TestCaseResult {
|
|
10
|
+
suiteName: string;
|
|
11
|
+
testName: string;
|
|
12
|
+
status: 'passed' | 'failed' | 'skipped';
|
|
13
|
+
durationMs: number;
|
|
14
|
+
error?: Error;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface TestSuiteResult {
|
|
18
|
+
suiteName: string;
|
|
19
|
+
passed: number;
|
|
20
|
+
failed: number;
|
|
21
|
+
skipped: number;
|
|
22
|
+
durationMs: number;
|
|
23
|
+
cases: TestCaseResult[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface TestSummary {
|
|
27
|
+
total: number;
|
|
28
|
+
passed: number;
|
|
29
|
+
failed: number;
|
|
30
|
+
skipped: number;
|
|
31
|
+
durationMs: number;
|
|
32
|
+
failures: TestFailure[];
|
|
33
|
+
suiteResults: TestSuiteResult[];
|
|
34
|
+
logOutput: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type TestCaseFn = () => Promise<void> | void;
|
|
38
|
+
export type LifecycleHookFn = () => Promise<void> | void;
|
|
39
|
+
|
|
40
|
+
export interface TestCase {
|
|
41
|
+
name: string;
|
|
42
|
+
fn: TestCaseFn;
|
|
43
|
+
timeoutMs?: number;
|
|
44
|
+
skip?: boolean;
|
|
45
|
+
only?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface TestSuite {
|
|
49
|
+
name: string;
|
|
50
|
+
cases: TestCase[];
|
|
51
|
+
beforeAllHooks: LifecycleHookFn[];
|
|
52
|
+
afterAllHooks: LifecycleHookFn[];
|
|
53
|
+
beforeEachHooks: LifecycleHookFn[];
|
|
54
|
+
afterEachHooks: LifecycleHookFn[];
|
|
55
|
+
skip?: boolean;
|
|
56
|
+
only?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface TestProgressEvent {
|
|
60
|
+
type: 'suite_start' | 'suite_complete' | 'test_start' | 'test_complete';
|
|
61
|
+
suiteName: string;
|
|
62
|
+
testName?: string;
|
|
63
|
+
status?: 'passed' | 'failed' | 'skipped';
|
|
64
|
+
completedCount: number;
|
|
65
|
+
totalCount: number;
|
|
66
|
+
passedCount: number;
|
|
67
|
+
failedCount: number;
|
|
68
|
+
skippedCount: number;
|
|
69
|
+
error?: Error;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface TestRunOptions {
|
|
73
|
+
maxDurationMs?: number;
|
|
74
|
+
defaultTestTimeoutMs?: number;
|
|
75
|
+
filter?: string | RegExp;
|
|
76
|
+
onProgress?: (event: TestProgressEvent) => void;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ExpectMatcher {
|
|
80
|
+
toBe(expected: any): void;
|
|
81
|
+
toEqual(expected: any): void;
|
|
82
|
+
toStrictEqual(expected: any): void;
|
|
83
|
+
toBeTruthy(): void;
|
|
84
|
+
toBeFalsy(): void;
|
|
85
|
+
toBeNull(): void;
|
|
86
|
+
toBeUndefined(): void;
|
|
87
|
+
toBeDefined(): void;
|
|
88
|
+
toBeNaN(): void;
|
|
89
|
+
toBeInstanceOf(expectedConstructor: any): void;
|
|
90
|
+
toBeGreaterThan(expected: number | bigint): void;
|
|
91
|
+
toBeGreaterThanOrEqual(expected: number | bigint): void;
|
|
92
|
+
toBeLessThan(expected: number | bigint): void;
|
|
93
|
+
toBeLessThanOrEqual(expected: number | bigint): void;
|
|
94
|
+
toBeCloseTo(expected: number, numDigits?: number): void;
|
|
95
|
+
toContain(item: any): void;
|
|
96
|
+
toContainEqual(item: any): void;
|
|
97
|
+
toHaveLength(expectedLength: number): void;
|
|
98
|
+
toHaveProperty(keyPath: string | string[], expectedValue?: any): void;
|
|
99
|
+
toMatch(expected: string | RegExp): void;
|
|
100
|
+
toMatchObject(expected: Record<string, any> | any[]): void;
|
|
101
|
+
toThrow(expectedError?: string | RegExp | Error | (new (...args: any[]) => Error)): void;
|
|
102
|
+
toHaveBeenCalled(): void;
|
|
103
|
+
toHaveBeenCalledTimes(expectedCount: number): void;
|
|
104
|
+
toHaveBeenCalledWith(...expectedArgs: any[]): void;
|
|
105
|
+
toHaveBeenLastCalledWith(...expectedArgs: any[]): void;
|
|
106
|
+
not: ExpectMatcher;
|
|
107
|
+
resolves: AsyncExpectMatcher;
|
|
108
|
+
rejects: AsyncExpectMatcher;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface AsyncExpectMatcher {
|
|
112
|
+
toBe(expected: any): Promise<void>;
|
|
113
|
+
toEqual(expected: any): Promise<void>;
|
|
114
|
+
toStrictEqual(expected: any): Promise<void>;
|
|
115
|
+
toBeTruthy(): Promise<void>;
|
|
116
|
+
toBeFalsy(): Promise<void>;
|
|
117
|
+
toBeNull(): Promise<void>;
|
|
118
|
+
toBeUndefined(): Promise<void>;
|
|
119
|
+
toBeDefined(): Promise<void>;
|
|
120
|
+
toContain(item: any): Promise<void>;
|
|
121
|
+
toMatch(expected: string | RegExp): Promise<void>;
|
|
122
|
+
toMatchObject(expected: Record<string, any> | any[]): Promise<void>;
|
|
123
|
+
toThrow(expectedError?: string | RegExp | Error | (new (...args: any[]) => Error)): Promise<void>;
|
|
124
|
+
not: AsyncExpectMatcher;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface MockCallRecord<TArgs extends any[] = any[], TReturn = any> {
|
|
128
|
+
args: TArgs;
|
|
129
|
+
type: 'return' | 'throw';
|
|
130
|
+
value: TReturn;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface MockState<TArgs extends any[] = any[], TReturn = any> {
|
|
134
|
+
calls: TArgs[];
|
|
135
|
+
results: Array<{ type: 'return' | 'throw'; value: TReturn }>;
|
|
136
|
+
instances: any[];
|
|
137
|
+
lastCall?: TArgs;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface MockFunction<TArgs extends any[] = any[], TReturn = any> {
|
|
141
|
+
(...args: TArgs): TReturn;
|
|
142
|
+
_isMockFunction: true;
|
|
143
|
+
mock: MockState<TArgs, TReturn>;
|
|
144
|
+
mockImplementation(fn: (...args: TArgs) => TReturn): this;
|
|
145
|
+
mockImplementationOnce(fn: (...args: TArgs) => TReturn): this;
|
|
146
|
+
mockReturnValue(value: TReturn): this;
|
|
147
|
+
mockReturnValueOnce(value: TReturn): this;
|
|
148
|
+
mockResolvedValue(value: Awaited<TReturn>): this;
|
|
149
|
+
mockResolvedValueOnce(value: Awaited<TReturn>): this;
|
|
150
|
+
mockRejectedValue(err: any): this;
|
|
151
|
+
mockRejectedValueOnce(err: any): this;
|
|
152
|
+
mockClear(): this;
|
|
153
|
+
mockReset(): this;
|
|
154
|
+
mockRestore(): void;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface WebviewLiveTestSpec {
|
|
158
|
+
id: string;
|
|
159
|
+
name: string;
|
|
160
|
+
timeoutMs?: number;
|
|
161
|
+
/**
|
|
162
|
+
* JavaScript code string or function to execute inside the live <webview> context.
|
|
163
|
+
* Inside the webview, pushing to `window.__testErrors` or throwing an Error fails the test.
|
|
164
|
+
*/
|
|
165
|
+
code: string | (() => Promise<void> | void);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface WebviewExecutionResult {
|
|
169
|
+
ok: boolean;
|
|
170
|
+
errors: string[];
|
|
171
|
+
error?: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface WaitForScreenLoadOptions {
|
|
175
|
+
/**
|
|
176
|
+
* Required DOM element IDs that must exist in the webview document before tests start.
|
|
177
|
+
*/
|
|
178
|
+
requiredElementIds?: string[];
|
|
179
|
+
/**
|
|
180
|
+
* Required CSS selectors that must match in the webview document before tests start.
|
|
181
|
+
*/
|
|
182
|
+
requiredSelectors?: string[];
|
|
183
|
+
/**
|
|
184
|
+
* Custom JavaScript boolean expression evaluated inside the webview to check readiness.
|
|
185
|
+
*/
|
|
186
|
+
customPredicateCode?: string;
|
|
187
|
+
/**
|
|
188
|
+
* Maximum time to wait for screen readiness in ms (default: 4000).
|
|
189
|
+
*/
|
|
190
|
+
timeoutMs?: number;
|
|
191
|
+
/**
|
|
192
|
+
* Polling interval in ms (default: 100).
|
|
193
|
+
*/
|
|
194
|
+
pollIntervalMs?: number;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export type HttpRouteHandler = (
|
|
198
|
+
req: http.IncomingMessage,
|
|
199
|
+
res: http.ServerResponse,
|
|
200
|
+
context: { projectRootDir: string; reqPath: string; reqUrl: string }
|
|
201
|
+
) => Promise<boolean | void> | boolean | void;
|
|
202
|
+
|
|
203
|
+
export interface TestHttpServerOptions {
|
|
204
|
+
projectRootDir: string;
|
|
205
|
+
defaultEntryFile?: string;
|
|
206
|
+
host?: string;
|
|
207
|
+
port?: number;
|
|
208
|
+
ignore404Paths?: string[];
|
|
209
|
+
customMimeTypes?: Record<string, string>;
|
|
210
|
+
onHttp404?: (reqPath: string, resolvedFilePath: string) => void;
|
|
211
|
+
routeHandler?: HttpRouteHandler;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface GraphicalOverlayOptions {
|
|
215
|
+
title?: string;
|
|
216
|
+
subtitle?: string;
|
|
217
|
+
enableWebview?: boolean;
|
|
218
|
+
webviewPartition?: string;
|
|
219
|
+
allowNwInWebview?: boolean;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export interface NwjsHarnessConfig {
|
|
223
|
+
/**
|
|
224
|
+
* Display title in the graphical overlay card and log file header.
|
|
225
|
+
* E.g. "HAEditor Live Webview Test Runner"
|
|
226
|
+
*/
|
|
227
|
+
title?: string;
|
|
228
|
+
/**
|
|
229
|
+
* Header title written into desktop-tests.log.
|
|
230
|
+
* E.g. "HAEditor Desktop Client Test Harness Log"
|
|
231
|
+
*/
|
|
232
|
+
logHeaderTitle?: string;
|
|
233
|
+
/**
|
|
234
|
+
* Root directory of the project being tested.
|
|
235
|
+
*/
|
|
236
|
+
projectRootDir?: string;
|
|
237
|
+
/**
|
|
238
|
+
* Path to the output test log file (default: `<projectRootDir>/testrunner/test-results/desktop-tests.log`).
|
|
239
|
+
*/
|
|
240
|
+
testLogPath?: string;
|
|
241
|
+
/**
|
|
242
|
+
* Prefix for temporary sandbox directory created in `os.tmpdir()`.
|
|
243
|
+
*/
|
|
244
|
+
sandboxPrefix?: string;
|
|
245
|
+
/**
|
|
246
|
+
* Initialization timeout in milliseconds before aborting if harness/webview fails to start (default: 8000).
|
|
247
|
+
*/
|
|
248
|
+
initTimeoutMs?: number;
|
|
249
|
+
/**
|
|
250
|
+
* Global hard deadline timeout in milliseconds for the entire test run (default: 35000).
|
|
251
|
+
*/
|
|
252
|
+
globalTimeoutMs?: number;
|
|
253
|
+
/**
|
|
254
|
+
* Maximum duration in milliseconds allocated to unit test suites in `runner.runAll()` (default: 15000).
|
|
255
|
+
*/
|
|
256
|
+
unitSuiteTimeoutMs?: number;
|
|
257
|
+
/**
|
|
258
|
+
* Default timeout per individual unit test case in ms (default: 2000).
|
|
259
|
+
*/
|
|
260
|
+
defaultTestTimeoutMs?: number;
|
|
261
|
+
/**
|
|
262
|
+
* Optional filter string or RegExp for unit test names.
|
|
263
|
+
*/
|
|
264
|
+
testFilter?: string | RegExp;
|
|
265
|
+
/**
|
|
266
|
+
* Whether to load a target client page inside the `<webview>` element (default: auto-detected from `webviewEntryHtml` or `liveWebviewTests`).
|
|
267
|
+
*/
|
|
268
|
+
enableWebview?: boolean;
|
|
269
|
+
/**
|
|
270
|
+
* Entry HTML file relative to `projectRootDir` to load into the `<webview>` via local HTTP server (default: `"index.html"`).
|
|
271
|
+
*/
|
|
272
|
+
webviewEntryHtml?: string;
|
|
273
|
+
/**
|
|
274
|
+
* Custom query parameters appended to the `<webview>` URL (`projectRoot` and `configDir` are included automatically unless disabled).
|
|
275
|
+
*/
|
|
276
|
+
webviewQueryParams?: Record<string, string>;
|
|
277
|
+
/**
|
|
278
|
+
* Whether to pass `?projectRoot=<sandboxDir>&configDir=<configDir>` to the webview URL (default: true).
|
|
279
|
+
*/
|
|
280
|
+
injectSandboxQueryParams?: boolean;
|
|
281
|
+
/**
|
|
282
|
+
* Custom HTTP route handler for mocking backend/AI endpoints during `<webview>` tests.
|
|
283
|
+
*/
|
|
284
|
+
httpRouteHandler?: HttpRouteHandler;
|
|
285
|
+
/**
|
|
286
|
+
* Paths that should not trigger an HTTP 404 error when requested by the webview (default: `['/favicon.ico']`).
|
|
287
|
+
*/
|
|
288
|
+
ignore404Paths?: string[];
|
|
289
|
+
/**
|
|
290
|
+
* Minimum console message level from `<webview>` to record as a test failure (`2` = error in Chromium webview; default: `2`).
|
|
291
|
+
*/
|
|
292
|
+
webviewConsoleErrorLevel?: number;
|
|
293
|
+
/**
|
|
294
|
+
* Screen load readiness check options for the `<webview>`.
|
|
295
|
+
*/
|
|
296
|
+
screenLoadOptions?: WaitForScreenLoadOptions;
|
|
297
|
+
/**
|
|
298
|
+
* Callback to programmatically register suites on the `TestRunner` instance.
|
|
299
|
+
*/
|
|
300
|
+
registerSuites?: (runner: any, context: { projectRootDir: string; sandboxDir: string; configDir: string }) => Promise<void> | void;
|
|
301
|
+
/**
|
|
302
|
+
* Paths or glob-like file paths (relative to `projectRootDir` or absolute) of test modules to `require()` before running.
|
|
303
|
+
* Modules can either use global/imported `describe`/`it`/`expect` or export a `registerTestSuites(runner)` / `registerSuites(runner)` function.
|
|
304
|
+
*/
|
|
305
|
+
testFiles?: string[];
|
|
306
|
+
/**
|
|
307
|
+
* Live DOM integration tests to execute sequentially inside the `<webview>`.
|
|
308
|
+
*/
|
|
309
|
+
liveWebviewTests?: WebviewLiveTestSpec[];
|
|
310
|
+
/**
|
|
311
|
+
* Whether to automatically call `process.exit(exitCode)` when tests complete (default: true).
|
|
312
|
+
*/
|
|
313
|
+
autoExit?: boolean;
|
|
314
|
+
/**
|
|
315
|
+
* Keep the graphical NW.js window open after test completion for visual inspection (default: false).
|
|
316
|
+
*/
|
|
317
|
+
keepOpen?: boolean;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export interface NwjsCliOptions {
|
|
321
|
+
projectRootDir?: string;
|
|
322
|
+
configPath?: string;
|
|
323
|
+
testFiles?: string[];
|
|
324
|
+
testFilter?: string;
|
|
325
|
+
logPath?: string;
|
|
326
|
+
title?: string;
|
|
327
|
+
webviewEntryHtml?: string;
|
|
328
|
+
enableWebview?: boolean;
|
|
329
|
+
initTimeoutMs?: number;
|
|
330
|
+
globalTimeoutMs?: number;
|
|
331
|
+
userDataDir?: string;
|
|
332
|
+
nwExecutablePath?: string;
|
|
333
|
+
keepOpen?: boolean;
|
|
334
|
+
headlessArgs?: string[];
|
|
335
|
+
}
|