@testsmith/testblocks 0.5.0 → 0.7.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.
- package/dist/cli/executor.d.ts +4 -1
- package/dist/cli/executor.js +101 -5
- package/dist/cli/index.js +78 -3
- package/dist/cli/reporters/ConsoleReporter.d.ts +12 -0
- package/dist/cli/reporters/ConsoleReporter.js +39 -0
- package/dist/cli/reporters/HTMLReporter.d.ts +19 -0
- package/dist/cli/reporters/HTMLReporter.js +506 -0
- package/dist/cli/reporters/JSONReporter.d.ts +15 -0
- package/dist/cli/reporters/JSONReporter.js +80 -0
- package/dist/cli/reporters/JUnitReporter.d.ts +19 -0
- package/dist/cli/reporters/JUnitReporter.js +105 -0
- package/dist/cli/reporters/index.d.ts +17 -0
- package/dist/cli/reporters/index.js +31 -0
- package/dist/cli/reporters/types.d.ts +28 -0
- package/dist/cli/reporters/types.js +2 -0
- package/dist/cli/reporters/utils.d.ts +31 -0
- package/dist/cli/reporters/utils.js +136 -0
- package/dist/cli/reporters.d.ts +13 -62
- package/dist/cli/reporters.js +16 -719
- package/dist/client/assets/index-Boo8ZrY_.js +2195 -0
- package/dist/client/assets/{index-qyomBgyC.js.map → index-Boo8ZrY_.js.map} +1 -1
- package/dist/client/assets/index-OxNH9dW-.css +1 -0
- package/dist/client/index.html +2 -2
- package/dist/core/blocks/api.js +3 -6
- package/dist/core/blocks/assertions.d.ts +31 -0
- package/dist/core/blocks/assertions.js +72 -0
- package/dist/core/blocks/index.d.ts +1 -0
- package/dist/core/blocks/index.js +6 -1
- package/dist/core/blocks/lifecycle.js +5 -3
- package/dist/core/blocks/logic.js +2 -3
- package/dist/core/blocks/playwright/assertions.d.ts +5 -0
- package/dist/core/blocks/playwright/assertions.js +321 -0
- package/dist/core/blocks/playwright/index.d.ts +17 -0
- package/dist/core/blocks/playwright/index.js +49 -0
- package/dist/core/blocks/playwright/interactions.d.ts +5 -0
- package/dist/core/blocks/playwright/interactions.js +191 -0
- package/dist/core/blocks/playwright/navigation.d.ts +5 -0
- package/dist/core/blocks/playwright/navigation.js +133 -0
- package/dist/core/blocks/playwright/retrieval.d.ts +5 -0
- package/dist/core/blocks/playwright/retrieval.js +144 -0
- package/dist/core/blocks/playwright/types.d.ts +65 -0
- package/dist/core/blocks/playwright/types.js +5 -0
- package/dist/core/blocks/playwright/utils.d.ts +26 -0
- package/dist/core/blocks/playwright/utils.js +137 -0
- package/dist/core/blocks/playwright.d.ts +13 -2
- package/dist/core/blocks/playwright.js +14 -761
- package/dist/core/executor/BaseTestExecutor.d.ts +60 -0
- package/dist/core/executor/BaseTestExecutor.js +297 -0
- package/dist/core/executor/index.d.ts +1 -0
- package/dist/core/executor/index.js +5 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +4 -0
- package/dist/core/types.d.ts +12 -0
- package/dist/core/utils/blocklyParser.d.ts +18 -0
- package/dist/core/utils/blocklyParser.js +84 -0
- package/dist/core/utils/dataLoader.d.ts +9 -0
- package/dist/core/utils/dataLoader.js +117 -0
- package/dist/core/utils/index.d.ts +2 -0
- package/dist/core/utils/index.js +12 -0
- package/dist/core/utils/logger.d.ts +14 -0
- package/dist/core/utils/logger.js +48 -0
- package/dist/core/utils/variableResolver.d.ts +24 -0
- package/dist/core/utils/variableResolver.js +92 -0
- package/dist/server/executor.d.ts +6 -0
- package/dist/server/executor.js +207 -47
- package/dist/server/globals.d.ts +6 -1
- package/dist/server/globals.js +7 -0
- package/dist/server/startServer.js +15 -0
- package/package.json +1 -1
- package/dist/client/assets/index-oTTttNKd.css +0 -1
- package/dist/client/assets/index-qyomBgyC.js +0 -2193
package/dist/cli/executor.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { TestFile, TestCase, TestResult, Plugin, TestDataSet } from '../core';
|
|
1
|
+
import { TestFile, TestCase, TestResult, Plugin, ProcedureDefinition, TestDataSet } from '../core';
|
|
2
2
|
export interface ExecutorOptions {
|
|
3
3
|
headless?: boolean;
|
|
4
4
|
timeout?: number;
|
|
5
5
|
baseUrl?: string;
|
|
6
6
|
variables?: Record<string, unknown>;
|
|
7
7
|
plugins?: Plugin[];
|
|
8
|
+
procedures?: Record<string, ProcedureDefinition>;
|
|
8
9
|
}
|
|
9
10
|
export declare class TestExecutor {
|
|
10
11
|
private options;
|
|
@@ -23,11 +24,13 @@ export declare class TestExecutor {
|
|
|
23
24
|
runTest(test: TestCase, testFile: TestFile): Promise<TestResult>;
|
|
24
25
|
private runSteps;
|
|
25
26
|
private resolveVariableDefaults;
|
|
27
|
+
private registerCustomBlocksFromProcedures;
|
|
26
28
|
private extractStepsFromBlocklyState;
|
|
27
29
|
private blocksToSteps;
|
|
28
30
|
private blockToStep;
|
|
29
31
|
private runStep;
|
|
30
32
|
private executeProcedure;
|
|
33
|
+
private resolveVariablePlaceholders;
|
|
31
34
|
private resolveParams;
|
|
32
35
|
private createLogger;
|
|
33
36
|
}
|
package/dist/cli/executor.js
CHANGED
|
@@ -20,6 +20,13 @@ class TestExecutor {
|
|
|
20
20
|
this.plugins.set(plugin.name, plugin);
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
+
// Register project-level procedures from options
|
|
24
|
+
if (options.procedures) {
|
|
25
|
+
for (const [name, procedure] of Object.entries(options.procedures)) {
|
|
26
|
+
this.procedures.set(name, procedure);
|
|
27
|
+
}
|
|
28
|
+
this.registerCustomBlocksFromProcedures(options.procedures);
|
|
29
|
+
}
|
|
23
30
|
}
|
|
24
31
|
async initialize() {
|
|
25
32
|
this.browser = await playwright_1.chromium.launch({
|
|
@@ -81,6 +88,8 @@ class TestExecutor {
|
|
|
81
88
|
for (const [name, procedure] of Object.entries(testFile.procedures)) {
|
|
82
89
|
this.procedures.set(name, procedure);
|
|
83
90
|
}
|
|
91
|
+
// Also register them as custom blocks so custom_xxx blocks work
|
|
92
|
+
this.registerCustomBlocksFromProcedures(testFile.procedures);
|
|
84
93
|
}
|
|
85
94
|
// Create base context for hooks
|
|
86
95
|
const baseContext = this.createBaseContext(testFile.variables);
|
|
@@ -122,7 +131,7 @@ class TestExecutor {
|
|
|
122
131
|
return {
|
|
123
132
|
variables: new Map(Object.entries({
|
|
124
133
|
...this.resolveVariableDefaults(fileVariables),
|
|
125
|
-
...this.options.variables,
|
|
134
|
+
...this.resolveVariableDefaults(this.options.variables),
|
|
126
135
|
})),
|
|
127
136
|
results: [],
|
|
128
137
|
browser: this.browser,
|
|
@@ -347,6 +356,56 @@ class TestExecutor {
|
|
|
347
356
|
}
|
|
348
357
|
return resolved;
|
|
349
358
|
}
|
|
359
|
+
registerCustomBlocksFromProcedures(procedures) {
|
|
360
|
+
Object.entries(procedures).forEach(([_name, proc]) => {
|
|
361
|
+
if (!proc.steps || proc.steps.length === 0)
|
|
362
|
+
return;
|
|
363
|
+
const blockType = `custom_${proc.name.toLowerCase().replace(/\s+/g, '_')}`;
|
|
364
|
+
// Check if already registered
|
|
365
|
+
if ((0, core_1.getBlock)(blockType))
|
|
366
|
+
return;
|
|
367
|
+
const blockDef = {
|
|
368
|
+
type: blockType,
|
|
369
|
+
category: 'Custom',
|
|
370
|
+
color: '#607D8B',
|
|
371
|
+
tooltip: proc.description || `Custom block: ${proc.name}`,
|
|
372
|
+
inputs: (proc.params || []).map(param => ({
|
|
373
|
+
name: param.name.toUpperCase(),
|
|
374
|
+
type: 'field',
|
|
375
|
+
fieldType: param.type === 'number' ? 'number' : 'text',
|
|
376
|
+
default: param.default,
|
|
377
|
+
})),
|
|
378
|
+
previousStatement: true,
|
|
379
|
+
nextStatement: true,
|
|
380
|
+
execute: async (params, context) => {
|
|
381
|
+
context.logger.info(`Executing custom block: ${proc.name}`);
|
|
382
|
+
// Set procedure parameters in context.variables so ${paramName} references work
|
|
383
|
+
// Resolve any ${variable} placeholders in the parameter values first
|
|
384
|
+
(proc.params || []).forEach(p => {
|
|
385
|
+
const paramKey = p.name.toUpperCase();
|
|
386
|
+
let value = params[paramKey];
|
|
387
|
+
if (value !== undefined) {
|
|
388
|
+
// Resolve variable placeholders like ${email} from context
|
|
389
|
+
if (typeof value === 'string') {
|
|
390
|
+
value = this.resolveVariablePlaceholders(value, context);
|
|
391
|
+
}
|
|
392
|
+
context.variables.set(p.name, value);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
// Execute the procedure's steps directly
|
|
396
|
+
const steps = this.extractStepsFromBlocklyState(proc.steps);
|
|
397
|
+
for (const step of steps) {
|
|
398
|
+
const result = await this.runStep(step, context);
|
|
399
|
+
if (result.status !== 'passed') {
|
|
400
|
+
throw new Error(`Procedure ${proc.name} failed: ${result.error?.message}`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return { customBlock: true, name: proc.name };
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
(0, core_1.registerBlock)(blockDef);
|
|
407
|
+
});
|
|
408
|
+
}
|
|
350
409
|
extractStepsFromBlocklyState(state) {
|
|
351
410
|
if (!state || typeof state !== 'object')
|
|
352
411
|
return [];
|
|
@@ -482,9 +541,20 @@ class TestExecutor {
|
|
|
482
541
|
throw new Error(`Procedure not found: ${name}`);
|
|
483
542
|
}
|
|
484
543
|
context.logger.info(` Executing procedure: ${name}`);
|
|
485
|
-
//
|
|
544
|
+
// Save original variable values to restore after procedure execution
|
|
545
|
+
const savedValues = new Map();
|
|
546
|
+
// Set up parameter variables (procedure steps reference them directly as ${paramName})
|
|
486
547
|
for (const [key, value] of Object.entries(args)) {
|
|
487
|
-
|
|
548
|
+
// Resolve any ${variable} placeholders in the argument value
|
|
549
|
+
let resolvedValue = value;
|
|
550
|
+
if (typeof value === 'string' && value.includes('${')) {
|
|
551
|
+
resolvedValue = this.resolveVariablePlaceholders(value, context);
|
|
552
|
+
}
|
|
553
|
+
// Save original value if it exists
|
|
554
|
+
if (context.variables.has(key)) {
|
|
555
|
+
savedValues.set(key, context.variables.get(key));
|
|
556
|
+
}
|
|
557
|
+
context.variables.set(key, resolvedValue);
|
|
488
558
|
}
|
|
489
559
|
// Execute procedure steps
|
|
490
560
|
const steps = this.extractStepsFromBlocklyState(procedure.steps);
|
|
@@ -503,12 +573,38 @@ class TestExecutor {
|
|
|
503
573
|
}
|
|
504
574
|
}
|
|
505
575
|
}
|
|
506
|
-
//
|
|
576
|
+
// Restore original variable values
|
|
577
|
+
for (const [key, originalValue] of savedValues) {
|
|
578
|
+
context.variables.set(key, originalValue);
|
|
579
|
+
}
|
|
580
|
+
// Remove variables that didn't exist before
|
|
507
581
|
for (const key of Object.keys(args)) {
|
|
508
|
-
|
|
582
|
+
if (!savedValues.has(key)) {
|
|
583
|
+
context.variables.delete(key);
|
|
584
|
+
}
|
|
509
585
|
}
|
|
510
586
|
return returnValue;
|
|
511
587
|
}
|
|
588
|
+
resolveVariablePlaceholders(text, context) {
|
|
589
|
+
return text.replace(/\$\{([\w.]+)\}/g, (match, path) => {
|
|
590
|
+
const parts = path.split('.');
|
|
591
|
+
const varName = parts[0];
|
|
592
|
+
let value = context.variables.get(varName);
|
|
593
|
+
// Handle dot notation for nested object access
|
|
594
|
+
if (parts.length > 1 && value !== undefined && value !== null) {
|
|
595
|
+
for (let i = 1; i < parts.length; i++) {
|
|
596
|
+
if (value === undefined || value === null)
|
|
597
|
+
break;
|
|
598
|
+
value = value[parts[i]];
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (value === undefined || value === null)
|
|
602
|
+
return match;
|
|
603
|
+
if (typeof value === 'object')
|
|
604
|
+
return JSON.stringify(value);
|
|
605
|
+
return String(value);
|
|
606
|
+
});
|
|
607
|
+
}
|
|
512
608
|
async resolveParams(params, context) {
|
|
513
609
|
const resolved = {};
|
|
514
610
|
for (const [key, value] of Object.entries(params)) {
|
package/dist/cli/index.js
CHANGED
|
@@ -41,6 +41,21 @@ const glob_1 = require("glob");
|
|
|
41
41
|
const executor_1 = require("./executor");
|
|
42
42
|
const reporters_1 = require("./reporters");
|
|
43
43
|
const startServer_1 = require("../server/startServer");
|
|
44
|
+
/**
|
|
45
|
+
* Search up the directory tree for globals.json starting from the given directory
|
|
46
|
+
*/
|
|
47
|
+
function findGlobalsFile(startDir) {
|
|
48
|
+
let currentDir = path.resolve(startDir);
|
|
49
|
+
const root = path.parse(currentDir).root;
|
|
50
|
+
while (currentDir !== root) {
|
|
51
|
+
const globalsPath = path.join(currentDir, 'globals.json');
|
|
52
|
+
if (fs.existsSync(globalsPath)) {
|
|
53
|
+
return globalsPath;
|
|
54
|
+
}
|
|
55
|
+
currentDir = path.dirname(currentDir);
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
44
59
|
const program = new commander_1.Command();
|
|
45
60
|
program
|
|
46
61
|
.name('testblocks')
|
|
@@ -73,9 +88,15 @@ program
|
|
|
73
88
|
process.exit(1);
|
|
74
89
|
}
|
|
75
90
|
console.log(`Found ${files.length} test file(s)\n`);
|
|
76
|
-
// Load globals.json if
|
|
91
|
+
// Load globals.json - search up directory tree from first test file if not explicitly specified
|
|
77
92
|
let globalVariables = {};
|
|
78
|
-
|
|
93
|
+
let globalProcedures = {};
|
|
94
|
+
let globalsPath = path.resolve(options.globals);
|
|
95
|
+
// If default globals path doesn't exist, search up from first test file
|
|
96
|
+
if (!fs.existsSync(globalsPath) && options.globals === './globals.json' && files.length > 0) {
|
|
97
|
+
const testDir = path.dirname(files[0]);
|
|
98
|
+
globalsPath = findGlobalsFile(testDir) || globalsPath;
|
|
99
|
+
}
|
|
79
100
|
if (fs.existsSync(globalsPath)) {
|
|
80
101
|
try {
|
|
81
102
|
const globalsContent = fs.readFileSync(globalsPath, 'utf-8');
|
|
@@ -83,6 +104,9 @@ program
|
|
|
83
104
|
if (globals.variables && typeof globals.variables === 'object') {
|
|
84
105
|
globalVariables = globals.variables;
|
|
85
106
|
}
|
|
107
|
+
if (globals.procedures && typeof globals.procedures === 'object') {
|
|
108
|
+
globalProcedures = globals.procedures;
|
|
109
|
+
}
|
|
86
110
|
}
|
|
87
111
|
catch (e) {
|
|
88
112
|
console.warn(`Warning: Could not load globals from ${globalsPath}: ${e.message}`);
|
|
@@ -111,6 +135,7 @@ program
|
|
|
111
135
|
timeout: parseInt(options.timeout, 10),
|
|
112
136
|
baseUrl: options.baseUrl,
|
|
113
137
|
variables,
|
|
138
|
+
procedures: globalProcedures,
|
|
114
139
|
};
|
|
115
140
|
// Create reporter
|
|
116
141
|
const reporter = createReporter(options.reporter, options.output);
|
|
@@ -248,7 +273,7 @@ program
|
|
|
248
273
|
'test:junit': 'testblocks run tests/**/*.testblocks.json -r junit -o reports',
|
|
249
274
|
},
|
|
250
275
|
devDependencies: {
|
|
251
|
-
'@testsmith/testblocks': '^0.
|
|
276
|
+
'@testsmith/testblocks': '^0.7.0',
|
|
252
277
|
},
|
|
253
278
|
};
|
|
254
279
|
fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2));
|
|
@@ -354,6 +379,56 @@ Thumbs.db
|
|
|
354
379
|
fs.writeFileSync(gitignorePath, gitignore);
|
|
355
380
|
console.log(' Created: .gitignore');
|
|
356
381
|
}
|
|
382
|
+
// Create GitHub Actions workflow
|
|
383
|
+
const workflowDir = path.join(projectDir, '.github', 'workflows');
|
|
384
|
+
if (!fs.existsSync(workflowDir)) {
|
|
385
|
+
fs.mkdirSync(workflowDir, { recursive: true });
|
|
386
|
+
console.log(' Created: .github/workflows/');
|
|
387
|
+
}
|
|
388
|
+
const workflowPath = path.join(workflowDir, 'testblocks.yml');
|
|
389
|
+
if (!fs.existsSync(workflowPath)) {
|
|
390
|
+
const workflow = `name: TestBlocks Tests
|
|
391
|
+
|
|
392
|
+
on:
|
|
393
|
+
push:
|
|
394
|
+
branches: [main, master]
|
|
395
|
+
pull_request:
|
|
396
|
+
branches: [main, master]
|
|
397
|
+
|
|
398
|
+
jobs:
|
|
399
|
+
test:
|
|
400
|
+
runs-on: ubuntu-latest
|
|
401
|
+
|
|
402
|
+
steps:
|
|
403
|
+
- name: Checkout repository
|
|
404
|
+
uses: actions/checkout@v4
|
|
405
|
+
|
|
406
|
+
- name: Setup Node.js
|
|
407
|
+
uses: actions/setup-node@v4
|
|
408
|
+
with:
|
|
409
|
+
node-version: '20'
|
|
410
|
+
cache: 'npm'
|
|
411
|
+
|
|
412
|
+
- name: Install dependencies
|
|
413
|
+
run: npm ci
|
|
414
|
+
|
|
415
|
+
- name: Install Playwright browsers
|
|
416
|
+
run: npx playwright install --with-deps chromium
|
|
417
|
+
|
|
418
|
+
- name: Run tests
|
|
419
|
+
run: npm test
|
|
420
|
+
|
|
421
|
+
- name: Upload test reports
|
|
422
|
+
uses: actions/upload-artifact@v4
|
|
423
|
+
if: always()
|
|
424
|
+
with:
|
|
425
|
+
name: test-reports
|
|
426
|
+
path: reports/
|
|
427
|
+
retention-days: 30
|
|
428
|
+
`;
|
|
429
|
+
fs.writeFileSync(workflowPath, workflow);
|
|
430
|
+
console.log(' Created: .github/workflows/testblocks.yml');
|
|
431
|
+
}
|
|
357
432
|
console.log('\n✓ Project initialized successfully!\n');
|
|
358
433
|
console.log('Next steps:');
|
|
359
434
|
console.log(' 1. cd ' + (directory === '.' ? '' : directory));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TestFile, TestResult } from '../../core';
|
|
2
|
+
import { Reporter } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Console reporter - outputs results to the terminal
|
|
5
|
+
*/
|
|
6
|
+
export declare class ConsoleReporter implements Reporter {
|
|
7
|
+
onTestFileComplete(file: string, testFile: TestFile, results: TestResult[]): void;
|
|
8
|
+
onComplete(allResults: {
|
|
9
|
+
file: string;
|
|
10
|
+
results: TestResult[];
|
|
11
|
+
}[]): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConsoleReporter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Console reporter - outputs results to the terminal
|
|
6
|
+
*/
|
|
7
|
+
class ConsoleReporter {
|
|
8
|
+
onTestFileComplete(file, testFile, results) {
|
|
9
|
+
console.log('');
|
|
10
|
+
for (const result of results) {
|
|
11
|
+
const icon = result.status === 'passed' ? '✓' : '✗';
|
|
12
|
+
const color = result.status === 'passed' ? '\x1b[32m' : '\x1b[31m';
|
|
13
|
+
const reset = '\x1b[0m';
|
|
14
|
+
console.log(`${color} ${icon} ${result.testName}${reset} (${result.duration}ms)`);
|
|
15
|
+
if (result.error) {
|
|
16
|
+
console.log(` ${result.error.message}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
console.log('');
|
|
20
|
+
}
|
|
21
|
+
onComplete(allResults) {
|
|
22
|
+
const totalTests = allResults.reduce((sum, r) => sum + r.results.length, 0);
|
|
23
|
+
const passed = allResults.reduce((sum, r) => sum + r.results.filter(t => t.status === 'passed').length, 0);
|
|
24
|
+
const failed = allResults.reduce((sum, r) => sum + r.results.filter(t => t.status !== 'passed').length, 0);
|
|
25
|
+
const totalDuration = allResults.reduce((sum, r) => sum + r.results.reduce((s, t) => s + t.duration, 0), 0);
|
|
26
|
+
console.log('─'.repeat(50));
|
|
27
|
+
console.log(`Tests: ${passed} passed, ${failed} failed, ${totalTests} total`);
|
|
28
|
+
console.log(`Duration: ${(totalDuration / 1000).toFixed(2)}s`);
|
|
29
|
+
console.log(`Test Files: ${allResults.length}`);
|
|
30
|
+
console.log('─'.repeat(50));
|
|
31
|
+
if (failed > 0) {
|
|
32
|
+
console.log('\n\x1b[31mTest run failed\x1b[0m\n');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.log('\n\x1b[32mAll tests passed!\x1b[0m\n');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.ConsoleReporter = ConsoleReporter;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TestFile, TestResult } from '../../core';
|
|
2
|
+
import { Reporter, ReportData } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* HTML reporter - generates a styled HTML report
|
|
5
|
+
*/
|
|
6
|
+
export declare class HTMLReporter implements Reporter {
|
|
7
|
+
private outputDir;
|
|
8
|
+
private allResults;
|
|
9
|
+
constructor(outputDir: string);
|
|
10
|
+
onTestFileComplete(file: string, testFile: TestFile, results: TestResult[]): void;
|
|
11
|
+
onComplete(allResults: {
|
|
12
|
+
file: string;
|
|
13
|
+
results: TestResult[];
|
|
14
|
+
}[]): void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Generate HTML report from report data
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateHTMLReport(data: ReportData): string;
|