donobu 5.23.0 → 5.24.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/apis/SuitesApi.d.ts +36 -0
- package/dist/apis/SuitesApi.js +68 -0
- package/dist/apis/TestsApi.d.ts +40 -0
- package/dist/apis/TestsApi.js +86 -0
- package/dist/assets/openapi-schema.yaml +15 -0
- package/dist/esm/apis/SuitesApi.d.ts +36 -0
- package/dist/esm/apis/SuitesApi.js +68 -0
- package/dist/esm/apis/TestsApi.d.ts +40 -0
- package/dist/esm/apis/TestsApi.js +86 -0
- package/dist/esm/assets/openapi-schema.yaml +15 -0
- package/dist/esm/main.d.ts +1 -0
- package/dist/esm/managers/AdminApiController.d.ts +8 -0
- package/dist/esm/managers/AdminApiController.js +29 -0
- package/dist/esm/managers/DonobuFlowsManager.d.ts +29 -1
- package/dist/esm/managers/DonobuFlowsManager.js +74 -28
- package/dist/esm/managers/DonobuStack.js +1 -1
- package/dist/esm/managers/FederatedPagination.js +10 -1
- package/dist/esm/managers/FlowCatalog.js +31 -39
- package/dist/esm/managers/FlowDependencyAnalyzer.js +12 -0
- package/dist/esm/managers/SuitesManager.js +23 -6
- package/dist/esm/managers/TestsManager.d.ts +24 -3
- package/dist/esm/managers/TestsManager.js +123 -28
- package/dist/esm/models/BrowserConfig.d.ts +3 -0
- package/dist/esm/models/BrowserStateFlowReference.d.ts +3 -0
- package/dist/esm/models/BrowserStateFlowReference.js +13 -2
- package/dist/esm/models/CreateDonobuFlow.d.ts +4 -0
- package/dist/esm/models/CreateDonobuFlow.js +4 -0
- package/dist/esm/models/CreateSuite.d.ts +3 -0
- package/dist/esm/models/CreateTest.d.ts +3 -0
- package/dist/esm/models/FlowMetadata.d.ts +4 -0
- package/dist/esm/models/FlowMetadata.js +8 -0
- package/dist/esm/models/RunConfig.d.ts +6 -0
- package/dist/esm/models/SuiteMetadata.d.ts +3 -0
- package/dist/esm/models/TargetConfig.d.ts +3 -0
- package/dist/esm/models/TestMetadata.d.ts +3 -0
- package/dist/esm/persistence/flows/FlowsPersistenceDonobuApi.js +7 -0
- package/dist/esm/persistence/flows/FlowsPersistenceSqlite.js +11 -0
- package/dist/esm/persistence/flows/FlowsPersistenceVolatile.js +7 -1
- package/dist/esm/tools/AssertPageTool.d.ts +2 -2
- package/dist/esm/tools/TriggerDonobuFlowTool.d.ts +8 -0
- package/dist/esm/utils/MiscUtils.d.ts +13 -0
- package/dist/esm/utils/MiscUtils.js +21 -0
- package/dist/main.d.ts +1 -0
- package/dist/managers/AdminApiController.d.ts +8 -0
- package/dist/managers/AdminApiController.js +29 -0
- package/dist/managers/DonobuFlowsManager.d.ts +29 -1
- package/dist/managers/DonobuFlowsManager.js +74 -28
- package/dist/managers/DonobuStack.js +1 -1
- package/dist/managers/FederatedPagination.js +10 -1
- package/dist/managers/FlowCatalog.js +31 -39
- package/dist/managers/FlowDependencyAnalyzer.js +12 -0
- package/dist/managers/SuitesManager.js +23 -6
- package/dist/managers/TestsManager.d.ts +24 -3
- package/dist/managers/TestsManager.js +123 -28
- package/dist/models/BrowserConfig.d.ts +3 -0
- package/dist/models/BrowserStateFlowReference.d.ts +3 -0
- package/dist/models/BrowserStateFlowReference.js +13 -2
- package/dist/models/CreateDonobuFlow.d.ts +4 -0
- package/dist/models/CreateDonobuFlow.js +4 -0
- package/dist/models/CreateSuite.d.ts +3 -0
- package/dist/models/CreateTest.d.ts +3 -0
- package/dist/models/FlowMetadata.d.ts +4 -0
- package/dist/models/FlowMetadata.js +8 -0
- package/dist/models/RunConfig.d.ts +6 -0
- package/dist/models/SuiteMetadata.d.ts +3 -0
- package/dist/models/TargetConfig.d.ts +3 -0
- package/dist/models/TestMetadata.d.ts +3 -0
- package/dist/persistence/flows/FlowsPersistenceDonobuApi.js +7 -0
- package/dist/persistence/flows/FlowsPersistenceSqlite.js +11 -0
- package/dist/persistence/flows/FlowsPersistenceVolatile.js +7 -1
- package/dist/tools/AssertPageTool.d.ts +2 -2
- package/dist/tools/TriggerDonobuFlowTool.d.ts +8 -0
- package/dist/utils/MiscUtils.d.ts +13 -0
- package/dist/utils/MiscUtils.js +21 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Request, Response } from 'express';
|
|
2
|
+
import type { SuitesManager } from '../managers/SuitesManager';
|
|
3
|
+
import type { TestsManager } from '../managers/TestsManager';
|
|
4
|
+
/**
|
|
5
|
+
* API controller for managing suites.
|
|
6
|
+
*/
|
|
7
|
+
export declare class SuitesApi {
|
|
8
|
+
private readonly suitesManager;
|
|
9
|
+
private readonly testsManager;
|
|
10
|
+
constructor(suitesManager: SuitesManager, testsManager: TestsManager);
|
|
11
|
+
/**
|
|
12
|
+
* GET /api/suites — list suites with optional filtering and pagination.
|
|
13
|
+
*/
|
|
14
|
+
getSuites(req: Request, res: Response): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* POST /api/suites — create a new suite.
|
|
17
|
+
*/
|
|
18
|
+
createSuite(req: Request, res: Response): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/suites/:suiteId — get a suite by ID.
|
|
21
|
+
*/
|
|
22
|
+
getSuite(req: Request, res: Response): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* PUT /api/suites/:suiteId — update an existing suite.
|
|
25
|
+
*/
|
|
26
|
+
updateSuite(req: Request, res: Response): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* DELETE /api/suites/:suiteId — delete a suite (tests are orphaned).
|
|
29
|
+
*/
|
|
30
|
+
deleteSuite(req: Request, res: Response): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* GET /api/suites/:suiteId/tests — list tests in a suite.
|
|
33
|
+
*/
|
|
34
|
+
getSuiteTests(req: Request, res: Response): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=SuitesApi.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SuitesApi = void 0;
|
|
4
|
+
const CreateSuite_1 = require("../models/CreateSuite");
|
|
5
|
+
const SuiteMetadata_1 = require("../models/SuiteMetadata");
|
|
6
|
+
/**
|
|
7
|
+
* API controller for managing suites.
|
|
8
|
+
*/
|
|
9
|
+
class SuitesApi {
|
|
10
|
+
constructor(suitesManager, testsManager) {
|
|
11
|
+
this.suitesManager = suitesManager;
|
|
12
|
+
this.testsManager = testsManager;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* GET /api/suites — list suites with optional filtering and pagination.
|
|
16
|
+
*/
|
|
17
|
+
async getSuites(req, res) {
|
|
18
|
+
const query = SuiteMetadata_1.SuitesQuerySchema.parse(req.query);
|
|
19
|
+
const result = await this.suitesManager.getSuites(query);
|
|
20
|
+
res.json({ suites: result.items, nextPageToken: result.nextPageToken });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* POST /api/suites — create a new suite.
|
|
24
|
+
*/
|
|
25
|
+
async createSuite(req, res) {
|
|
26
|
+
const params = CreateSuite_1.CreateSuiteSchema.parse(req.body);
|
|
27
|
+
const suite = await this.suitesManager.createSuite(params);
|
|
28
|
+
res.json(suite);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* GET /api/suites/:suiteId — get a suite by ID.
|
|
32
|
+
*/
|
|
33
|
+
async getSuite(req, res) {
|
|
34
|
+
const suiteId = String(req.params.suiteId);
|
|
35
|
+
const suite = await this.suitesManager.getSuiteById(suiteId);
|
|
36
|
+
res.json(suite);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* PUT /api/suites/:suiteId — update an existing suite.
|
|
40
|
+
*/
|
|
41
|
+
async updateSuite(req, res) {
|
|
42
|
+
const suiteId = String(req.params.suiteId);
|
|
43
|
+
const suiteMetadata = SuiteMetadata_1.SuiteMetadataSchema.parse({
|
|
44
|
+
...req.body,
|
|
45
|
+
id: suiteId,
|
|
46
|
+
});
|
|
47
|
+
await this.suitesManager.updateSuite(suiteMetadata);
|
|
48
|
+
res.json(suiteMetadata);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* DELETE /api/suites/:suiteId — delete a suite (tests are orphaned).
|
|
52
|
+
*/
|
|
53
|
+
async deleteSuite(req, res) {
|
|
54
|
+
const suiteId = String(req.params.suiteId);
|
|
55
|
+
await this.suitesManager.deleteSuite(suiteId);
|
|
56
|
+
res.status(200).json({ deleted: true });
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* GET /api/suites/:suiteId/tests — list tests in a suite.
|
|
60
|
+
*/
|
|
61
|
+
async getSuiteTests(req, res) {
|
|
62
|
+
const suiteId = String(req.params.suiteId);
|
|
63
|
+
const result = await this.testsManager.getTests({ suiteId });
|
|
64
|
+
res.json({ tests: result.items, nextPageToken: result.nextPageToken });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.SuitesApi = SuitesApi;
|
|
68
|
+
//# sourceMappingURL=SuitesApi.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Request, Response } from 'express';
|
|
2
|
+
import type { DonobuFlowsManager } from '../managers/DonobuFlowsManager';
|
|
3
|
+
import type { TestsManager } from '../managers/TestsManager';
|
|
4
|
+
/**
|
|
5
|
+
* API controller for managing tests.
|
|
6
|
+
*/
|
|
7
|
+
export declare class TestsApi {
|
|
8
|
+
private readonly testsManager;
|
|
9
|
+
private readonly flowsManager;
|
|
10
|
+
constructor(testsManager: TestsManager, flowsManager: DonobuFlowsManager);
|
|
11
|
+
/**
|
|
12
|
+
* GET /api/tests — list tests with optional filtering and pagination.
|
|
13
|
+
*/
|
|
14
|
+
getTests(req: Request, res: Response): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* POST /api/tests — create a new test.
|
|
17
|
+
*/
|
|
18
|
+
createTest(req: Request, res: Response): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/tests/:testId — get a test by ID.
|
|
21
|
+
*/
|
|
22
|
+
getTest(req: Request, res: Response): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* PUT /api/tests/:testId — update an existing test.
|
|
25
|
+
*/
|
|
26
|
+
updateTest(req: Request, res: Response): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* DELETE /api/tests/:testId — delete a test and all its flows.
|
|
29
|
+
*/
|
|
30
|
+
deleteTest(req: Request, res: Response): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* GET /api/tests/:testId/flows — list flows for a test.
|
|
33
|
+
*/
|
|
34
|
+
getTestFlows(req: Request, res: Response): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* POST /api/tests/:testId/run — execute a test (create a new flow from it).
|
|
37
|
+
*/
|
|
38
|
+
runTest(req: Request, res: Response): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=TestsApi.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TestsApi = void 0;
|
|
4
|
+
const CreateTest_1 = require("../models/CreateTest");
|
|
5
|
+
const TestMetadata_1 = require("../models/TestMetadata");
|
|
6
|
+
/**
|
|
7
|
+
* API controller for managing tests.
|
|
8
|
+
*/
|
|
9
|
+
class TestsApi {
|
|
10
|
+
constructor(testsManager, flowsManager) {
|
|
11
|
+
this.testsManager = testsManager;
|
|
12
|
+
this.flowsManager = flowsManager;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* GET /api/tests — list tests with optional filtering and pagination.
|
|
16
|
+
*/
|
|
17
|
+
async getTests(req, res) {
|
|
18
|
+
const query = TestMetadata_1.TestsQuerySchema.parse(req.query);
|
|
19
|
+
const result = await this.testsManager.getTests(query);
|
|
20
|
+
res.json({ tests: result.items, nextPageToken: result.nextPageToken });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* POST /api/tests — create a new test.
|
|
24
|
+
*/
|
|
25
|
+
async createTest(req, res) {
|
|
26
|
+
const params = CreateTest_1.CreateTestSchema.parse(req.body);
|
|
27
|
+
const test = await this.testsManager.createTest(params);
|
|
28
|
+
res.json(test);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* GET /api/tests/:testId — get a test by ID.
|
|
32
|
+
*/
|
|
33
|
+
async getTest(req, res) {
|
|
34
|
+
const testId = String(req.params.testId);
|
|
35
|
+
const test = await this.testsManager.getTestById(testId);
|
|
36
|
+
res.json(test);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* PUT /api/tests/:testId — update an existing test.
|
|
40
|
+
*/
|
|
41
|
+
async updateTest(req, res) {
|
|
42
|
+
const testId = String(req.params.testId);
|
|
43
|
+
const testMetadata = TestMetadata_1.TestMetadataSchema.parse({
|
|
44
|
+
...req.body,
|
|
45
|
+
id: testId,
|
|
46
|
+
});
|
|
47
|
+
await this.testsManager.updateTest(testMetadata);
|
|
48
|
+
res.json(testMetadata);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* DELETE /api/tests/:testId — delete a test and all its flows.
|
|
52
|
+
*/
|
|
53
|
+
async deleteTest(req, res) {
|
|
54
|
+
const testId = String(req.params.testId);
|
|
55
|
+
await this.testsManager.deleteTest(testId);
|
|
56
|
+
res.status(200).json({ deleted: true });
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* GET /api/tests/:testId/flows — list flows for a test.
|
|
60
|
+
*/
|
|
61
|
+
async getTestFlows(req, res) {
|
|
62
|
+
const testId = String(req.params.testId);
|
|
63
|
+
const flows = await this.flowsManager.getFlows({ testId });
|
|
64
|
+
res.json({ flows: flows.items, nextPageToken: flows.nextPageToken });
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* POST /api/tests/:testId/run — execute a test (create a new flow from it).
|
|
68
|
+
*/
|
|
69
|
+
async runTest(req, res) {
|
|
70
|
+
const testId = String(req.params.testId);
|
|
71
|
+
const newFlowConfig = await this.testsManager.getNewFlowFromTest(testId);
|
|
72
|
+
const flowHandle = await this.flowsManager.createFlow(newFlowConfig);
|
|
73
|
+
// After starting an autonomous run, switch the test to deterministic
|
|
74
|
+
// so subsequent runs replay the recorded actions.
|
|
75
|
+
if (newFlowConfig.initialRunMode === 'AUTONOMOUS') {
|
|
76
|
+
const test = await this.testsManager.getTestById(testId);
|
|
77
|
+
await this.testsManager.updateTest({
|
|
78
|
+
...test,
|
|
79
|
+
nextRunMode: 'DETERMINISTIC',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
res.json(flowHandle.donobuFlow.metadata);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.TestsApi = TestsApi;
|
|
86
|
+
//# sourceMappingURL=TestsApi.js.map
|
|
@@ -1496,6 +1496,7 @@ components:
|
|
|
1496
1496
|
to restore when starting a flow. Exactly one variant should be provided:
|
|
1497
1497
|
- `id` — Reference a flow by its ID and restore its persisted browser state.
|
|
1498
1498
|
- `name` — Reference a flow by its name and restore its persisted browser state.
|
|
1499
|
+
- `testId` — Reference a test by its ID and restore browser state from the most recent successful flow belonging to that test.
|
|
1499
1500
|
- `json` — Provide the browser state inline as a JSON object.
|
|
1500
1501
|
oneOf:
|
|
1501
1502
|
- type: 'object'
|
|
@@ -1526,6 +1527,20 @@ components:
|
|
|
1526
1527
|
value:
|
|
1527
1528
|
type: 'string'
|
|
1528
1529
|
description: 'The name of the flow whose browser state should be restored.'
|
|
1530
|
+
- type: 'object'
|
|
1531
|
+
description: 'Reference a test by ID to restore browser state from its most recent successful flow.'
|
|
1532
|
+
required:
|
|
1533
|
+
- 'type'
|
|
1534
|
+
- 'value'
|
|
1535
|
+
properties:
|
|
1536
|
+
type:
|
|
1537
|
+
type: 'string'
|
|
1538
|
+
enum:
|
|
1539
|
+
- 'testId'
|
|
1540
|
+
description: 'Indicates the value is a test ID.'
|
|
1541
|
+
value:
|
|
1542
|
+
type: 'string'
|
|
1543
|
+
description: 'A test ID. The browser state will be restored from the most recent successful flow belonging to this test.'
|
|
1529
1544
|
- type: 'object'
|
|
1530
1545
|
description: 'Provide browser state inline as a JSON object.'
|
|
1531
1546
|
required:
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Request, Response } from 'express';
|
|
2
|
+
import type { SuitesManager } from '../managers/SuitesManager';
|
|
3
|
+
import type { TestsManager } from '../managers/TestsManager';
|
|
4
|
+
/**
|
|
5
|
+
* API controller for managing suites.
|
|
6
|
+
*/
|
|
7
|
+
export declare class SuitesApi {
|
|
8
|
+
private readonly suitesManager;
|
|
9
|
+
private readonly testsManager;
|
|
10
|
+
constructor(suitesManager: SuitesManager, testsManager: TestsManager);
|
|
11
|
+
/**
|
|
12
|
+
* GET /api/suites — list suites with optional filtering and pagination.
|
|
13
|
+
*/
|
|
14
|
+
getSuites(req: Request, res: Response): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* POST /api/suites — create a new suite.
|
|
17
|
+
*/
|
|
18
|
+
createSuite(req: Request, res: Response): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/suites/:suiteId — get a suite by ID.
|
|
21
|
+
*/
|
|
22
|
+
getSuite(req: Request, res: Response): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* PUT /api/suites/:suiteId — update an existing suite.
|
|
25
|
+
*/
|
|
26
|
+
updateSuite(req: Request, res: Response): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* DELETE /api/suites/:suiteId — delete a suite (tests are orphaned).
|
|
29
|
+
*/
|
|
30
|
+
deleteSuite(req: Request, res: Response): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* GET /api/suites/:suiteId/tests — list tests in a suite.
|
|
33
|
+
*/
|
|
34
|
+
getSuiteTests(req: Request, res: Response): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=SuitesApi.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SuitesApi = void 0;
|
|
4
|
+
const CreateSuite_1 = require("../models/CreateSuite");
|
|
5
|
+
const SuiteMetadata_1 = require("../models/SuiteMetadata");
|
|
6
|
+
/**
|
|
7
|
+
* API controller for managing suites.
|
|
8
|
+
*/
|
|
9
|
+
class SuitesApi {
|
|
10
|
+
constructor(suitesManager, testsManager) {
|
|
11
|
+
this.suitesManager = suitesManager;
|
|
12
|
+
this.testsManager = testsManager;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* GET /api/suites — list suites with optional filtering and pagination.
|
|
16
|
+
*/
|
|
17
|
+
async getSuites(req, res) {
|
|
18
|
+
const query = SuiteMetadata_1.SuitesQuerySchema.parse(req.query);
|
|
19
|
+
const result = await this.suitesManager.getSuites(query);
|
|
20
|
+
res.json({ suites: result.items, nextPageToken: result.nextPageToken });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* POST /api/suites — create a new suite.
|
|
24
|
+
*/
|
|
25
|
+
async createSuite(req, res) {
|
|
26
|
+
const params = CreateSuite_1.CreateSuiteSchema.parse(req.body);
|
|
27
|
+
const suite = await this.suitesManager.createSuite(params);
|
|
28
|
+
res.json(suite);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* GET /api/suites/:suiteId — get a suite by ID.
|
|
32
|
+
*/
|
|
33
|
+
async getSuite(req, res) {
|
|
34
|
+
const suiteId = String(req.params.suiteId);
|
|
35
|
+
const suite = await this.suitesManager.getSuiteById(suiteId);
|
|
36
|
+
res.json(suite);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* PUT /api/suites/:suiteId — update an existing suite.
|
|
40
|
+
*/
|
|
41
|
+
async updateSuite(req, res) {
|
|
42
|
+
const suiteId = String(req.params.suiteId);
|
|
43
|
+
const suiteMetadata = SuiteMetadata_1.SuiteMetadataSchema.parse({
|
|
44
|
+
...req.body,
|
|
45
|
+
id: suiteId,
|
|
46
|
+
});
|
|
47
|
+
await this.suitesManager.updateSuite(suiteMetadata);
|
|
48
|
+
res.json(suiteMetadata);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* DELETE /api/suites/:suiteId — delete a suite (tests are orphaned).
|
|
52
|
+
*/
|
|
53
|
+
async deleteSuite(req, res) {
|
|
54
|
+
const suiteId = String(req.params.suiteId);
|
|
55
|
+
await this.suitesManager.deleteSuite(suiteId);
|
|
56
|
+
res.status(200).json({ deleted: true });
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* GET /api/suites/:suiteId/tests — list tests in a suite.
|
|
60
|
+
*/
|
|
61
|
+
async getSuiteTests(req, res) {
|
|
62
|
+
const suiteId = String(req.params.suiteId);
|
|
63
|
+
const result = await this.testsManager.getTests({ suiteId });
|
|
64
|
+
res.json({ tests: result.items, nextPageToken: result.nextPageToken });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.SuitesApi = SuitesApi;
|
|
68
|
+
//# sourceMappingURL=SuitesApi.js.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Request, Response } from 'express';
|
|
2
|
+
import type { DonobuFlowsManager } from '../managers/DonobuFlowsManager';
|
|
3
|
+
import type { TestsManager } from '../managers/TestsManager';
|
|
4
|
+
/**
|
|
5
|
+
* API controller for managing tests.
|
|
6
|
+
*/
|
|
7
|
+
export declare class TestsApi {
|
|
8
|
+
private readonly testsManager;
|
|
9
|
+
private readonly flowsManager;
|
|
10
|
+
constructor(testsManager: TestsManager, flowsManager: DonobuFlowsManager);
|
|
11
|
+
/**
|
|
12
|
+
* GET /api/tests — list tests with optional filtering and pagination.
|
|
13
|
+
*/
|
|
14
|
+
getTests(req: Request, res: Response): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* POST /api/tests — create a new test.
|
|
17
|
+
*/
|
|
18
|
+
createTest(req: Request, res: Response): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* GET /api/tests/:testId — get a test by ID.
|
|
21
|
+
*/
|
|
22
|
+
getTest(req: Request, res: Response): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* PUT /api/tests/:testId — update an existing test.
|
|
25
|
+
*/
|
|
26
|
+
updateTest(req: Request, res: Response): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* DELETE /api/tests/:testId — delete a test and all its flows.
|
|
29
|
+
*/
|
|
30
|
+
deleteTest(req: Request, res: Response): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* GET /api/tests/:testId/flows — list flows for a test.
|
|
33
|
+
*/
|
|
34
|
+
getTestFlows(req: Request, res: Response): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* POST /api/tests/:testId/run — execute a test (create a new flow from it).
|
|
37
|
+
*/
|
|
38
|
+
runTest(req: Request, res: Response): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=TestsApi.d.ts.map
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TestsApi = void 0;
|
|
4
|
+
const CreateTest_1 = require("../models/CreateTest");
|
|
5
|
+
const TestMetadata_1 = require("../models/TestMetadata");
|
|
6
|
+
/**
|
|
7
|
+
* API controller for managing tests.
|
|
8
|
+
*/
|
|
9
|
+
class TestsApi {
|
|
10
|
+
constructor(testsManager, flowsManager) {
|
|
11
|
+
this.testsManager = testsManager;
|
|
12
|
+
this.flowsManager = flowsManager;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* GET /api/tests — list tests with optional filtering and pagination.
|
|
16
|
+
*/
|
|
17
|
+
async getTests(req, res) {
|
|
18
|
+
const query = TestMetadata_1.TestsQuerySchema.parse(req.query);
|
|
19
|
+
const result = await this.testsManager.getTests(query);
|
|
20
|
+
res.json({ tests: result.items, nextPageToken: result.nextPageToken });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* POST /api/tests — create a new test.
|
|
24
|
+
*/
|
|
25
|
+
async createTest(req, res) {
|
|
26
|
+
const params = CreateTest_1.CreateTestSchema.parse(req.body);
|
|
27
|
+
const test = await this.testsManager.createTest(params);
|
|
28
|
+
res.json(test);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* GET /api/tests/:testId — get a test by ID.
|
|
32
|
+
*/
|
|
33
|
+
async getTest(req, res) {
|
|
34
|
+
const testId = String(req.params.testId);
|
|
35
|
+
const test = await this.testsManager.getTestById(testId);
|
|
36
|
+
res.json(test);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* PUT /api/tests/:testId — update an existing test.
|
|
40
|
+
*/
|
|
41
|
+
async updateTest(req, res) {
|
|
42
|
+
const testId = String(req.params.testId);
|
|
43
|
+
const testMetadata = TestMetadata_1.TestMetadataSchema.parse({
|
|
44
|
+
...req.body,
|
|
45
|
+
id: testId,
|
|
46
|
+
});
|
|
47
|
+
await this.testsManager.updateTest(testMetadata);
|
|
48
|
+
res.json(testMetadata);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* DELETE /api/tests/:testId — delete a test and all its flows.
|
|
52
|
+
*/
|
|
53
|
+
async deleteTest(req, res) {
|
|
54
|
+
const testId = String(req.params.testId);
|
|
55
|
+
await this.testsManager.deleteTest(testId);
|
|
56
|
+
res.status(200).json({ deleted: true });
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* GET /api/tests/:testId/flows — list flows for a test.
|
|
60
|
+
*/
|
|
61
|
+
async getTestFlows(req, res) {
|
|
62
|
+
const testId = String(req.params.testId);
|
|
63
|
+
const flows = await this.flowsManager.getFlows({ testId });
|
|
64
|
+
res.json({ flows: flows.items, nextPageToken: flows.nextPageToken });
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* POST /api/tests/:testId/run — execute a test (create a new flow from it).
|
|
68
|
+
*/
|
|
69
|
+
async runTest(req, res) {
|
|
70
|
+
const testId = String(req.params.testId);
|
|
71
|
+
const newFlowConfig = await this.testsManager.getNewFlowFromTest(testId);
|
|
72
|
+
const flowHandle = await this.flowsManager.createFlow(newFlowConfig);
|
|
73
|
+
// After starting an autonomous run, switch the test to deterministic
|
|
74
|
+
// so subsequent runs replay the recorded actions.
|
|
75
|
+
if (newFlowConfig.initialRunMode === 'AUTONOMOUS') {
|
|
76
|
+
const test = await this.testsManager.getTestById(testId);
|
|
77
|
+
await this.testsManager.updateTest({
|
|
78
|
+
...test,
|
|
79
|
+
nextRunMode: 'DETERMINISTIC',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
res.json(flowHandle.donobuFlow.metadata);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
exports.TestsApi = TestsApi;
|
|
86
|
+
//# sourceMappingURL=TestsApi.js.map
|
|
@@ -1496,6 +1496,7 @@ components:
|
|
|
1496
1496
|
to restore when starting a flow. Exactly one variant should be provided:
|
|
1497
1497
|
- `id` — Reference a flow by its ID and restore its persisted browser state.
|
|
1498
1498
|
- `name` — Reference a flow by its name and restore its persisted browser state.
|
|
1499
|
+
- `testId` — Reference a test by its ID and restore browser state from the most recent successful flow belonging to that test.
|
|
1499
1500
|
- `json` — Provide the browser state inline as a JSON object.
|
|
1500
1501
|
oneOf:
|
|
1501
1502
|
- type: 'object'
|
|
@@ -1526,6 +1527,20 @@ components:
|
|
|
1526
1527
|
value:
|
|
1527
1528
|
type: 'string'
|
|
1528
1529
|
description: 'The name of the flow whose browser state should be restored.'
|
|
1530
|
+
- type: 'object'
|
|
1531
|
+
description: 'Reference a test by ID to restore browser state from its most recent successful flow.'
|
|
1532
|
+
required:
|
|
1533
|
+
- 'type'
|
|
1534
|
+
- 'value'
|
|
1535
|
+
properties:
|
|
1536
|
+
type:
|
|
1537
|
+
type: 'string'
|
|
1538
|
+
enum:
|
|
1539
|
+
- 'testId'
|
|
1540
|
+
description: 'Indicates the value is a test ID.'
|
|
1541
|
+
value:
|
|
1542
|
+
type: 'string'
|
|
1543
|
+
description: 'A test ID. The browser state will be restored from the most recent successful flow belonging to this test.'
|
|
1529
1544
|
- type: 'object'
|
|
1530
1545
|
description: 'Provide browser state inline as a JSON object.'
|
|
1531
1546
|
required:
|
package/dist/esm/main.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export type * from './managers/TargetInspector';
|
|
|
30
30
|
export { ToolManager } from './managers/ToolManager';
|
|
31
31
|
export { createDefaultToolRegistry, type ToolRegistry, } from './managers/ToolRegistry';
|
|
32
32
|
export * from './managers/WebTargetInspector';
|
|
33
|
+
export type * from './models/AiQuery';
|
|
33
34
|
export type * from './models/AuditReport';
|
|
34
35
|
export * from './models/BrowserStorageState';
|
|
35
36
|
export * from './models/CodeGenerationOptions';
|
|
@@ -105,6 +105,14 @@ export declare class AdminApiController {
|
|
|
105
105
|
* Registers flow-related routes.
|
|
106
106
|
*/
|
|
107
107
|
private static registerFlowRoutes;
|
|
108
|
+
/**
|
|
109
|
+
* Registers test-related routes.
|
|
110
|
+
*/
|
|
111
|
+
private static registerTestRoutes;
|
|
112
|
+
/**
|
|
113
|
+
* Registers suite-related routes.
|
|
114
|
+
*/
|
|
115
|
+
private static registerSuiteRoutes;
|
|
108
116
|
/**
|
|
109
117
|
* Registers utility routes (version, ping).
|
|
110
118
|
*/
|
|
@@ -16,7 +16,9 @@ const FlowsToolCallsApi_1 = require("../apis/FlowsToolCallsApi");
|
|
|
16
16
|
const GptConfigsApi_1 = require("../apis/GptConfigsApi");
|
|
17
17
|
const PingApi_1 = require("../apis/PingApi");
|
|
18
18
|
const SchemaApi_1 = require("../apis/SchemaApi");
|
|
19
|
+
const SuitesApi_1 = require("../apis/SuitesApi");
|
|
19
20
|
const TargetsApi_1 = require("../apis/TargetsApi");
|
|
21
|
+
const TestsApi_1 = require("../apis/TestsApi");
|
|
20
22
|
const ToolsApi_1 = require("../apis/ToolsApi");
|
|
21
23
|
const DonobuException_1 = require("../exceptions/DonobuException");
|
|
22
24
|
const Logger_1 = require("../utils/Logger");
|
|
@@ -239,6 +241,8 @@ class AdminApiController {
|
|
|
239
241
|
flowsFilesApi: new FlowsFilesApi_1.FlowsFilesApi(donobuStack.flowsPersistenceRegistry),
|
|
240
242
|
flowsToolCallsApi: new FlowsToolCallsApi_1.FlowsToolCallsApi(donobuStack.flowsManager),
|
|
241
243
|
flowsAiQueriesApi: new FlowsAiQueriesApi_1.FlowsAiQueriesApi(donobuStack.flowsManager),
|
|
244
|
+
testsApi: new TestsApi_1.TestsApi(donobuStack.testsManager, donobuStack.flowsManager),
|
|
245
|
+
suitesApi: new SuitesApi_1.SuitesApi(donobuStack.suitesManager, donobuStack.testsManager),
|
|
242
246
|
pingApi: new PingApi_1.PingApi(),
|
|
243
247
|
schemaApi: new SchemaApi_1.SchemaApi(),
|
|
244
248
|
targetsApi: new TargetsApi_1.TargetsApi(donobuStack.targetRuntimePlugins),
|
|
@@ -290,6 +294,8 @@ class AdminApiController {
|
|
|
290
294
|
app.get('/api/tools', this.asyncHandler(apis.toolsApi.getSupportedTools.bind(apis.toolsApi)));
|
|
291
295
|
app.get('/api/targets', this.asyncHandler(apis.targetsApi.getTargets.bind(apis.targetsApi)));
|
|
292
296
|
this.registerFlowRoutes(app, apis);
|
|
297
|
+
this.registerTestRoutes(app, apis);
|
|
298
|
+
this.registerSuiteRoutes(app, apis);
|
|
293
299
|
this.registerUtilityRoutes(app, apis);
|
|
294
300
|
}
|
|
295
301
|
/**
|
|
@@ -313,6 +319,29 @@ class AdminApiController {
|
|
|
313
319
|
app.get('/api/flows/:flowId/ai-queries', this.asyncHandler(apis.flowsAiQueriesApi.getAiQueries.bind(apis.flowsAiQueriesApi)));
|
|
314
320
|
app.get('/api/flows/:flowId/logs', this.asyncHandler(apis.flowsApi.getFlowLogs.bind(apis.flowsApi)));
|
|
315
321
|
}
|
|
322
|
+
/**
|
|
323
|
+
* Registers test-related routes.
|
|
324
|
+
*/
|
|
325
|
+
static registerTestRoutes(app, apis) {
|
|
326
|
+
app.get('/api/tests', this.asyncHandler(apis.testsApi.getTests.bind(apis.testsApi)));
|
|
327
|
+
app.post('/api/tests', this.asyncHandler(apis.testsApi.createTest.bind(apis.testsApi)));
|
|
328
|
+
app.get('/api/tests/:testId', this.asyncHandler(apis.testsApi.getTest.bind(apis.testsApi)));
|
|
329
|
+
app.put('/api/tests/:testId', this.asyncHandler(apis.testsApi.updateTest.bind(apis.testsApi)));
|
|
330
|
+
app.delete('/api/tests/:testId', this.asyncHandler(apis.testsApi.deleteTest.bind(apis.testsApi)));
|
|
331
|
+
app.get('/api/tests/:testId/flows', this.asyncHandler(apis.testsApi.getTestFlows.bind(apis.testsApi)));
|
|
332
|
+
app.post('/api/tests/:testId/run', this.asyncHandler(apis.testsApi.runTest.bind(apis.testsApi)));
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Registers suite-related routes.
|
|
336
|
+
*/
|
|
337
|
+
static registerSuiteRoutes(app, apis) {
|
|
338
|
+
app.get('/api/suites', this.asyncHandler(apis.suitesApi.getSuites.bind(apis.suitesApi)));
|
|
339
|
+
app.post('/api/suites', this.asyncHandler(apis.suitesApi.createSuite.bind(apis.suitesApi)));
|
|
340
|
+
app.get('/api/suites/:suiteId', this.asyncHandler(apis.suitesApi.getSuite.bind(apis.suitesApi)));
|
|
341
|
+
app.put('/api/suites/:suiteId', this.asyncHandler(apis.suitesApi.updateSuite.bind(apis.suitesApi)));
|
|
342
|
+
app.delete('/api/suites/:suiteId', this.asyncHandler(apis.suitesApi.deleteSuite.bind(apis.suitesApi)));
|
|
343
|
+
app.get('/api/suites/:suiteId/tests', this.asyncHandler(apis.suitesApi.getSuiteTests.bind(apis.suitesApi)));
|
|
344
|
+
}
|
|
316
345
|
/**
|
|
317
346
|
* Registers utility routes (version, ping).
|
|
318
347
|
*/
|
|
@@ -18,6 +18,8 @@ import type { FlowMetadata } from '../models/FlowMetadata';
|
|
|
18
18
|
import type { FlowsQuery } from '../models/FlowMetadata';
|
|
19
19
|
import type { PaginatedResult } from '../models/PaginatedResult';
|
|
20
20
|
import type { ProposedToolCall } from '../models/ProposedToolCall';
|
|
21
|
+
import type { RunConfig } from '../models/RunConfig';
|
|
22
|
+
import type { RunMode } from '../models/RunMode';
|
|
21
23
|
import type { ToolCall } from '../models/ToolCall';
|
|
22
24
|
import type { FlowsPersistenceRegistry } from '../persistence/flows/FlowsPersistenceRegistry';
|
|
23
25
|
import type { TargetRuntimePluginRegistry } from '../targets/TargetRuntimePlugin';
|
|
@@ -64,14 +66,40 @@ export declare class DonobuFlowsManager {
|
|
|
64
66
|
createFlow(flowParams: CreateDonobuFlow, gptClient?: GptClient, browserContextOverride?: BrowserContext): Promise<FlowHandle>;
|
|
65
67
|
getFlowLogs(flowId: string): Promise<FlowLogSnapshot>;
|
|
66
68
|
renameFlow(flowId: string, name: string | null): Promise<FlowMetadata>;
|
|
69
|
+
/**
|
|
70
|
+
* Converts a prior flow's tool calls into a list of tool calls to invoke when
|
|
71
|
+
* starting a new flow as a rerun (i.e. without agentic decisioning).
|
|
72
|
+
*
|
|
73
|
+
* @param priorFlowMetadata The metadata of the flow to prepare as a rerun.
|
|
74
|
+
* @param options The code generation options to use for the rerun.
|
|
75
|
+
*
|
|
76
|
+
* @returns A list of tool calls to invoke when starting the flow.
|
|
77
|
+
*/
|
|
78
|
+
getToolCallsForRerun(priorFlowMetadata: FlowMetadata, options: CodeGenerationOptions): Promise<ProposedToolCall[]>;
|
|
67
79
|
/**
|
|
68
80
|
* Loads the given flow by ID and returns a `CreateDonobuFlow` object that can be passed to `createFlow`
|
|
69
|
-
*
|
|
81
|
+
* to execute the flow as a rerun (i.e. without agentic decisioning).
|
|
70
82
|
*
|
|
71
83
|
* @param flowId The ID of the flow to prepare as a rerun.
|
|
72
84
|
* @returns Parameters that can be passed to createFlow to execute the flow as a rerun.
|
|
73
85
|
*/
|
|
74
86
|
getFlowAsRerun(flowId: string, options: CodeGenerationOptions): Promise<CreateDonobuFlow>;
|
|
87
|
+
/**
|
|
88
|
+
* Takes a RunConfig object, or anything derived from it (FlowMetadata,
|
|
89
|
+
* TestMetadata), plus some additional parameters, and returns a
|
|
90
|
+
* CreateDonobuFlow object that can be passed to `createFlow` to execute the
|
|
91
|
+
* flow.
|
|
92
|
+
*
|
|
93
|
+
* @param name The name for the new flow
|
|
94
|
+
* @param runMode The run mode to be used for the flow
|
|
95
|
+
* @param config The RunConfig object
|
|
96
|
+
* @param toolCallsOnStart An ordered series of tool calls to invoke when
|
|
97
|
+
* starting the flow
|
|
98
|
+
*
|
|
99
|
+
* @returns A CreateDonobuFlow object that can be passed to createFlow to
|
|
100
|
+
* execute the flow.
|
|
101
|
+
*/
|
|
102
|
+
getFlowFromConfigAndToolCalls(name: string, runMode: RunMode, config: RunConfig, toolCallsOnStart: ProposedToolCall[]): CreateDonobuFlow;
|
|
75
103
|
/** Add a proposed tool call the tool call queue for the given flow by ID. */
|
|
76
104
|
proposeToolCall(flowId: string, toolName: string, parameters: Record<string, unknown>): Promise<void>;
|
|
77
105
|
/**
|