@testsmith/testblocks 0.1.0 → 0.3.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 +1 -0
- package/dist/cli/executor.js +32 -1
- package/dist/cli/index.js +25 -7
- package/dist/cli/reporters.js +324 -43
- package/dist/client/assets/index-CIvp_myM.css +1 -0
- package/dist/client/assets/index-DOJk7uTQ.js +2193 -0
- package/dist/client/assets/index-DOJk7uTQ.js.map +1 -0
- package/dist/client/index.html +2 -2
- package/dist/core/types.d.ts +7 -0
- package/dist/server/executor.d.ts +1 -0
- package/dist/server/executor.js +32 -1
- package/dist/server/index.js +74 -7
- package/package.json +1 -1
- package/dist/client/assets/index-Cq84-VIf.js +0 -2137
- package/dist/client/assets/index-Cq84-VIf.js.map +0 -1
- package/dist/client/assets/index-Dnk1ti7l.css +0 -1
package/dist/client/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
overflow: hidden;
|
|
17
17
|
}
|
|
18
18
|
</style>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
20
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-DOJk7uTQ.js"></script>
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CIvp_myM.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="root"></div>
|
package/dist/core/types.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare class TestExecutor {
|
|
|
17
17
|
constructor(options?: ExecutorOptions);
|
|
18
18
|
initialize(): Promise<void>;
|
|
19
19
|
cleanup(): Promise<void>;
|
|
20
|
+
private requiresBrowser;
|
|
20
21
|
runTestFile(testFile: TestFile): Promise<TestResult[]>;
|
|
21
22
|
private runLifecycleSteps;
|
|
22
23
|
/**
|
package/dist/server/executor.js
CHANGED
|
@@ -130,13 +130,44 @@ class TestExecutor {
|
|
|
130
130
|
this.context = null;
|
|
131
131
|
this.browser = null;
|
|
132
132
|
}
|
|
133
|
+
requiresBrowser(testFile) {
|
|
134
|
+
const hasWebStep = (steps) => {
|
|
135
|
+
return steps.some(step => step.type.startsWith('web_'));
|
|
136
|
+
};
|
|
137
|
+
const hasWebStepInState = (state) => {
|
|
138
|
+
const steps = this.extractStepsFromBlocklyState(state);
|
|
139
|
+
return hasWebStep(steps);
|
|
140
|
+
};
|
|
141
|
+
// Check beforeAll/afterAll hooks
|
|
142
|
+
if (testFile.beforeAll && hasWebStepInState(testFile.beforeAll))
|
|
143
|
+
return true;
|
|
144
|
+
if (testFile.afterAll && hasWebStepInState(testFile.afterAll))
|
|
145
|
+
return true;
|
|
146
|
+
if (testFile.beforeEach && hasWebStepInState(testFile.beforeEach))
|
|
147
|
+
return true;
|
|
148
|
+
if (testFile.afterEach && hasWebStepInState(testFile.afterEach))
|
|
149
|
+
return true;
|
|
150
|
+
// Check all tests
|
|
151
|
+
for (const test of testFile.tests) {
|
|
152
|
+
if (hasWebStepInState(test.steps))
|
|
153
|
+
return true;
|
|
154
|
+
if (test.beforeEach && hasWebStepInState(test.beforeEach))
|
|
155
|
+
return true;
|
|
156
|
+
if (test.afterEach && hasWebStepInState(test.afterEach))
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
133
161
|
async runTestFile(testFile) {
|
|
134
162
|
const results = [];
|
|
135
163
|
// Register custom blocks from procedures
|
|
136
164
|
if (testFile.procedures) {
|
|
137
165
|
this.registerCustomBlocksFromProcedures(testFile.procedures);
|
|
138
166
|
}
|
|
139
|
-
|
|
167
|
+
// Only initialize browser if test file contains web steps
|
|
168
|
+
if (this.requiresBrowser(testFile)) {
|
|
169
|
+
await this.initialize();
|
|
170
|
+
}
|
|
140
171
|
// Create shared execution context for lifecycle hooks
|
|
141
172
|
const sharedContext = {
|
|
142
173
|
variables: new Map(Object.entries({
|
package/dist/server/index.js
CHANGED
|
@@ -7,6 +7,11 @@ exports.TestExecutor = void 0;
|
|
|
7
7
|
const express_1 = __importDefault(require("express"));
|
|
8
8
|
const cors_1 = __importDefault(require("cors"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
// Read version from package.json
|
|
12
|
+
const packageJsonPath = path_1.default.join(__dirname, '../../package.json');
|
|
13
|
+
const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
|
|
14
|
+
const VERSION = packageJson.version || '0.0.0';
|
|
10
15
|
const executor_1 = require("./executor");
|
|
11
16
|
Object.defineProperty(exports, "TestExecutor", { enumerable: true, get: function () { return executor_1.TestExecutor; } });
|
|
12
17
|
const reporters_1 = require("../cli/reporters");
|
|
@@ -27,13 +32,70 @@ const globalsDir = process.env.GLOBALS_DIR || path_1.default.join(process.cwd(),
|
|
|
27
32
|
}).catch(err => {
|
|
28
33
|
console.error('Failed to load plugins:', err);
|
|
29
34
|
});
|
|
35
|
+
/**
|
|
36
|
+
* Merge folder hooks into a test file.
|
|
37
|
+
* Folder hooks are ordered from outermost to innermost folder.
|
|
38
|
+
* - beforeAll: run parent hooks first, then child hooks, then test file hooks
|
|
39
|
+
* - afterAll: run test file hooks first, then child hooks, then parent hooks
|
|
40
|
+
* - beforeEach/afterEach: same pattern
|
|
41
|
+
*/
|
|
42
|
+
function mergeFolderHooksIntoTestFile(testFile, folderHooks) {
|
|
43
|
+
if (!folderHooks || folderHooks.length === 0) {
|
|
44
|
+
return testFile;
|
|
45
|
+
}
|
|
46
|
+
// Collect all steps from folder hooks (parent to child order is already provided)
|
|
47
|
+
const beforeAllSteps = [];
|
|
48
|
+
const afterAllSteps = [];
|
|
49
|
+
const beforeEachSteps = [];
|
|
50
|
+
const afterEachSteps = [];
|
|
51
|
+
// Parent to child order for beforeAll/beforeEach
|
|
52
|
+
for (const hooks of folderHooks) {
|
|
53
|
+
if (hooks.beforeAll)
|
|
54
|
+
beforeAllSteps.push(...hooks.beforeAll);
|
|
55
|
+
if (hooks.beforeEach)
|
|
56
|
+
beforeEachSteps.push(...hooks.beforeEach);
|
|
57
|
+
}
|
|
58
|
+
// Child to parent order for afterAll/afterEach
|
|
59
|
+
for (let i = folderHooks.length - 1; i >= 0; i--) {
|
|
60
|
+
const hooks = folderHooks[i];
|
|
61
|
+
if (hooks.afterAll)
|
|
62
|
+
afterAllSteps.unshift(...hooks.afterAll);
|
|
63
|
+
if (hooks.afterEach)
|
|
64
|
+
afterEachSteps.unshift(...hooks.afterEach);
|
|
65
|
+
}
|
|
66
|
+
// Merge with test file hooks
|
|
67
|
+
const merged = {
|
|
68
|
+
...testFile,
|
|
69
|
+
beforeAll: [
|
|
70
|
+
...beforeAllSteps,
|
|
71
|
+
...(testFile.beforeAll || []),
|
|
72
|
+
],
|
|
73
|
+
afterAll: [
|
|
74
|
+
...(testFile.afterAll || []),
|
|
75
|
+
...afterAllSteps,
|
|
76
|
+
],
|
|
77
|
+
beforeEach: [
|
|
78
|
+
...beforeEachSteps,
|
|
79
|
+
...(testFile.beforeEach || []),
|
|
80
|
+
],
|
|
81
|
+
afterEach: [
|
|
82
|
+
...(testFile.afterEach || []),
|
|
83
|
+
...afterEachSteps,
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
return merged;
|
|
87
|
+
}
|
|
30
88
|
const app = (0, express_1.default)();
|
|
31
89
|
const PORT = process.env.PORT || 3001;
|
|
32
90
|
app.use((0, cors_1.default)());
|
|
33
91
|
app.use(express_1.default.json({ limit: '10mb' }));
|
|
34
92
|
// Health check
|
|
35
93
|
app.get('/api/health', (req, res) => {
|
|
36
|
-
res.json({ status: 'ok', version:
|
|
94
|
+
res.json({ status: 'ok', version: VERSION });
|
|
95
|
+
});
|
|
96
|
+
// Version endpoint
|
|
97
|
+
app.get('/api/version', (req, res) => {
|
|
98
|
+
res.json({ version: VERSION });
|
|
37
99
|
});
|
|
38
100
|
// List available plugins (with full block definitions for client registration)
|
|
39
101
|
app.get('/api/plugins', (req, res) => {
|
|
@@ -90,11 +152,13 @@ app.put('/api/globals/test-id-attribute', (req, res) => {
|
|
|
90
152
|
// Run tests
|
|
91
153
|
app.post('/api/run', async (req, res) => {
|
|
92
154
|
try {
|
|
93
|
-
const testFile = req.body;
|
|
155
|
+
const { testFile, folderHooks } = req.body;
|
|
94
156
|
if (!testFile || !testFile.tests) {
|
|
95
157
|
return res.status(400).json({ error: 'Invalid test file format' });
|
|
96
158
|
}
|
|
97
159
|
console.log(`Running ${testFile.tests.length} tests from "${testFile.name}"...`);
|
|
160
|
+
// Merge folder hooks into test file (parent to child order for beforeAll, child to parent for afterAll)
|
|
161
|
+
const mergedTestFile = mergeFolderHooksIntoTestFile(testFile, folderHooks || []);
|
|
98
162
|
// Merge global variables with test file variables
|
|
99
163
|
const globalVars = (0, globals_1.getGlobalVariables)();
|
|
100
164
|
const testIdAttr = (0, globals_1.getTestIdAttribute)();
|
|
@@ -105,7 +169,7 @@ app.post('/api/run', async (req, res) => {
|
|
|
105
169
|
testIdAttribute: testIdAttr, // Pass test ID attribute
|
|
106
170
|
baseDir: globalsDir, // Base directory for resolving relative file paths
|
|
107
171
|
});
|
|
108
|
-
const results = await executor.runTestFile(
|
|
172
|
+
const results = await executor.runTestFile(mergedTestFile);
|
|
109
173
|
const passed = results.filter(r => r.status === 'passed').length;
|
|
110
174
|
const failed = results.filter(r => r.status === 'failed').length;
|
|
111
175
|
console.log(`Results: ${passed} passed, ${failed} failed`);
|
|
@@ -124,12 +188,15 @@ app.post('/api/run', async (req, res) => {
|
|
|
124
188
|
// Run a single test
|
|
125
189
|
app.post('/api/run/:testId', async (req, res) => {
|
|
126
190
|
try {
|
|
127
|
-
const testFile = req.body;
|
|
191
|
+
const { testFile, folderHooks } = req.body;
|
|
128
192
|
const { testId } = req.params;
|
|
129
193
|
const test = testFile.tests.find(t => t.id === testId);
|
|
130
194
|
if (!test) {
|
|
131
195
|
return res.status(404).json({ error: `Test not found: ${testId}` });
|
|
132
196
|
}
|
|
197
|
+
// For single test runs, merge folder beforeEach/afterEach hooks
|
|
198
|
+
// (beforeAll/afterAll are handled at suite level)
|
|
199
|
+
const mergedTestFile = mergeFolderHooksIntoTestFile(testFile, folderHooks || []);
|
|
133
200
|
// Merge global variables
|
|
134
201
|
const globalVars = (0, globals_1.getGlobalVariables)();
|
|
135
202
|
const testIdAttr = (0, globals_1.getTestIdAttribute)();
|
|
@@ -141,11 +208,11 @@ app.post('/api/run/:testId', async (req, res) => {
|
|
|
141
208
|
baseDir: globalsDir, // Base directory for resolving relative file paths
|
|
142
209
|
});
|
|
143
210
|
// Register custom blocks from procedures before running the test
|
|
144
|
-
if (
|
|
145
|
-
executor.registerProcedures(
|
|
211
|
+
if (mergedTestFile.procedures) {
|
|
212
|
+
executor.registerProcedures(mergedTestFile.procedures);
|
|
146
213
|
}
|
|
147
214
|
await executor.initialize();
|
|
148
|
-
const result = await executor.runTest(test,
|
|
215
|
+
const result = await executor.runTest(test, mergedTestFile.variables);
|
|
149
216
|
await executor.cleanup();
|
|
150
217
|
res.json(result);
|
|
151
218
|
}
|