@autobe/agent 0.8.0 → 0.9.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/lib/AutoBeAgent.d.ts +183 -12
- package/lib/AutoBeAgent.js +245 -65
- package/lib/AutoBeAgent.js.map +1 -1
- package/lib/constants/AutoBeSystemPromptConstant.d.ts +4 -3
- package/lib/constants/AutoBeSystemPromptConstant.js.map +1 -1
- package/lib/context/AutoBeContext.d.ts +2 -2
- package/lib/factory/index.d.ts +0 -1
- package/lib/factory/index.js +0 -1
- package/lib/factory/index.js.map +1 -1
- package/lib/index.mjs +976 -633
- package/lib/index.mjs.map +1 -1
- package/lib/orchestrate/analyze/AutoBeAnalyzeAgent.js +1 -1
- package/lib/orchestrate/analyze/AutoBeAnalyzeAgent.js.map +1 -1
- package/lib/orchestrate/interface/orchestrateInterface.js +1 -1
- package/lib/orchestrate/interface/orchestrateInterface.js.map +1 -1
- package/lib/orchestrate/prisma/orchestratePrisma.js +1 -1
- package/lib/orchestrate/prisma/orchestratePrisma.js.map +1 -1
- package/lib/orchestrate/prisma/orchestratePrismaCorrect.js +1 -1
- package/lib/orchestrate/prisma/orchestratePrismaCorrect.js.map +1 -1
- package/lib/orchestrate/test/orchestrateTest.js +4 -8
- package/lib/orchestrate/test/orchestrateTest.js.map +1 -1
- package/lib/orchestrate/test/orchestrateTestCorrect.d.ts +2 -2
- package/lib/orchestrate/test/orchestrateTestCorrect.js +89 -57
- package/lib/orchestrate/test/orchestrateTestCorrect.js.map +1 -1
- package/lib/orchestrate/test/orchestrateTestProgress.d.ts +3 -2
- package/lib/orchestrate/test/orchestrateTestProgress.js +73 -46
- package/lib/orchestrate/test/orchestrateTestProgress.js.map +1 -1
- package/lib/orchestrate/test/orchestrateTestScenario.d.ts +2 -2
- package/lib/orchestrate/test/orchestrateTestScenario.js +616 -237
- package/lib/orchestrate/test/orchestrateTestScenario.js.map +1 -1
- package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.d.ts +123 -0
- package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.js +3 -0
- package/lib/orchestrate/test/structures/IAutoBeTestScenarioApplication.js.map +1 -0
- package/lib/orchestrate/test/transformTestCorrectHistories.d.ts +2 -1
- package/lib/orchestrate/test/transformTestCorrectHistories.js +14 -10
- package/lib/orchestrate/test/transformTestCorrectHistories.js.map +1 -1
- package/lib/orchestrate/test/transformTestProgressHistories.d.ts +7 -1
- package/lib/orchestrate/test/transformTestProgressHistories.js +20 -20
- package/lib/orchestrate/test/transformTestProgressHistories.js.map +1 -1
- package/lib/orchestrate/test/transformTestScenarioHistories.d.ts +1 -2
- package/lib/orchestrate/test/transformTestScenarioHistories.js +1 -77
- package/lib/orchestrate/test/transformTestScenarioHistories.js.map +1 -1
- package/lib/structures/IAutoBeConfig.d.ts +48 -10
- package/lib/structures/IAutoBeProps.d.ts +87 -0
- package/lib/structures/IAutoBeVendor.d.ts +64 -22
- package/lib/utils/backoffRetry.d.ts +7 -0
- package/lib/utils/backoffRetry.js +73 -0
- package/lib/utils/backoffRetry.js.map +1 -0
- package/lib/utils/types/BackoffOptions.d.ts +12 -0
- package/lib/utils/types/BackoffOptions.js +3 -0
- package/lib/utils/types/BackoffOptions.js.map +1 -0
- package/package.json +4 -4
- package/src/AutoBeAgent.ts +248 -52
- package/src/constants/AutoBeSystemPromptConstant.ts +4 -3
- package/src/context/AutoBeContext.ts +7 -2
- package/src/factory/index.ts +0 -1
- package/src/orchestrate/analyze/AutoBeAnalyzeAgent.ts +1 -1
- package/src/orchestrate/interface/orchestrateInterface.ts +1 -1
- package/src/orchestrate/prisma/orchestratePrisma.ts +1 -0
- package/src/orchestrate/prisma/orchestratePrismaCorrect.ts +4 -2
- package/src/orchestrate/test/orchestrateTest.ts +6 -13
- package/src/orchestrate/test/orchestrateTestCorrect.ts +125 -72
- package/src/orchestrate/test/orchestrateTestProgress.ts +86 -42
- package/src/orchestrate/test/orchestrateTestScenario.ts +192 -151
- package/src/orchestrate/test/structures/IAutoBeTestScenarioApplication.ts +132 -0
- package/src/orchestrate/test/transformTestCorrectHistories.ts +14 -10
- package/src/orchestrate/test/transformTestProgressHistories.ts +25 -22
- package/src/orchestrate/test/transformTestScenarioHistories.ts +0 -79
- package/src/structures/IAutoBeConfig.ts +48 -10
- package/src/structures/IAutoBeProps.ts +91 -0
- package/src/structures/IAutoBeVendor.ts +64 -22
- package/src/utils/backoffRetry.ts +84 -0
- package/src/utils/types/BackoffOptions.ts +15 -0
|
@@ -1,198 +1,253 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import {
|
|
2
|
+
IAgenticaController,
|
|
3
|
+
IAgenticaHistoryJson,
|
|
4
|
+
MicroAgentica,
|
|
5
|
+
} from "@agentica/core";
|
|
6
|
+
import { AutoBeOpenApi } from "@autobe/interface";
|
|
7
|
+
import { AutoBeTestScenarioEvent } from "@autobe/interface";
|
|
8
|
+
import { ILlmApplication, ILlmSchema, IValidation } from "@samchon/openapi";
|
|
9
|
+
import { IPointer } from "tstl";
|
|
6
10
|
import typia from "typia";
|
|
11
|
+
import { v4 } from "uuid";
|
|
7
12
|
|
|
13
|
+
import { AutoBeSystemPromptConstant } from "../../constants/AutoBeSystemPromptConstant";
|
|
8
14
|
import { AutoBeContext } from "../../context/AutoBeContext";
|
|
9
15
|
import { assertSchemaModel } from "../../context/assertSchemaModel";
|
|
10
16
|
import { divideArray } from "../../utils/divideArray";
|
|
11
17
|
import { enforceToolCall } from "../../utils/enforceToolCall";
|
|
12
|
-
import {
|
|
13
|
-
import { transformTestScenarioHistories } from "./transformTestScenarioHistories";
|
|
18
|
+
import { IAutoBeTestScenarioApplication } from "./structures/IAutoBeTestScenarioApplication";
|
|
14
19
|
|
|
15
20
|
export async function orchestrateTestScenario<Model extends ILlmSchema.Model>(
|
|
16
21
|
ctx: AutoBeContext<Model>,
|
|
17
|
-
capacity: number = 4,
|
|
18
22
|
): Promise<AutoBeTestScenarioEvent> {
|
|
19
|
-
const files = Object.entries(ctx.state().interface?.files ?? {})
|
|
20
|
-
.filter(([filename]) => {
|
|
21
|
-
return filename.startsWith("test/features/api/");
|
|
22
|
-
})
|
|
23
|
-
.reduce<Record<string, string>>((acc, [filename, content]) => {
|
|
24
|
-
return Object.assign(acc, { [filename]: content });
|
|
25
|
-
}, {});
|
|
26
|
-
|
|
27
23
|
const operations = ctx.state().interface?.document.operations ?? [];
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
summary: it.summary,
|
|
34
|
-
description: it.description,
|
|
35
|
-
parameters: it.parameters,
|
|
36
|
-
requestBody: it.requestBody,
|
|
37
|
-
responseBody: it.responseBody,
|
|
38
|
-
};
|
|
39
|
-
});
|
|
24
|
+
if (operations.length === 0) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"Cannot write test scenarios because these are no operations.",
|
|
27
|
+
);
|
|
28
|
+
}
|
|
40
29
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
capacity,
|
|
44
|
-
});
|
|
45
|
-
const start: Date = new Date();
|
|
46
|
-
|
|
47
|
-
let completed: number = 0;
|
|
48
|
-
|
|
49
|
-
const scenarios: AutoBeTest.IScenario[][] = await Promise.all(
|
|
50
|
-
matrix.map(async (e) => {
|
|
51
|
-
const rows: AutoBeTest.IScenario[] = await divideAndConquer(
|
|
52
|
-
ctx,
|
|
53
|
-
e,
|
|
54
|
-
endpoints,
|
|
55
|
-
files,
|
|
56
|
-
3,
|
|
57
|
-
(count) => {
|
|
58
|
-
completed += count;
|
|
59
|
-
},
|
|
60
|
-
);
|
|
61
|
-
ctx.dispatch({
|
|
62
|
-
type: "testScenario",
|
|
63
|
-
scenarios: rows,
|
|
64
|
-
total: rows.flatMap((el) => el.scenarios).length,
|
|
65
|
-
step: ctx.state().test?.step ?? 0,
|
|
66
|
-
completed,
|
|
67
|
-
created_at: start.toISOString(),
|
|
68
|
-
});
|
|
69
|
-
return rows;
|
|
70
|
-
}),
|
|
71
|
-
);
|
|
30
|
+
const exclude: IAutoBeTestScenarioApplication.IScenarioGroup[] = [];
|
|
31
|
+
let include: AutoBeOpenApi.IOperation[] = Array.from(operations);
|
|
72
32
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
scenarios: scenarios.flat(),
|
|
76
|
-
total: scenarios.flat().flatMap((el) => el.scenarios).length,
|
|
77
|
-
step: ctx.state().test?.step ?? 0,
|
|
78
|
-
completed,
|
|
79
|
-
created_at: start.toISOString(),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
33
|
+
do {
|
|
34
|
+
const matrix = divideArray({ array: include, capacity: 30 });
|
|
82
35
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
OpenApiEndpointComparator.equals,
|
|
95
|
-
);
|
|
96
|
-
const scenarios: HashMap<AutoBeOpenApi.IEndpoint, AutoBeTest.Scenario[]> =
|
|
97
|
-
new HashMap(
|
|
98
|
-
OpenApiEndpointComparator.hashCode,
|
|
99
|
-
OpenApiEndpointComparator.equals,
|
|
100
|
-
);
|
|
101
|
-
for (let i: number = 0; i < retry; ++i) {
|
|
102
|
-
if (remained.empty() === true || scenarios.size() >= endpoints.length)
|
|
103
|
-
break;
|
|
104
|
-
const before: number = scenarios.size();
|
|
105
|
-
const newbie: AutoBeTest.IScenario[] = await process(
|
|
106
|
-
ctx,
|
|
107
|
-
Array.from(remained),
|
|
108
|
-
allEndpoints,
|
|
109
|
-
files,
|
|
36
|
+
await Promise.all(
|
|
37
|
+
matrix.map(async (_include) => {
|
|
38
|
+
exclude.push(
|
|
39
|
+
...(await execute(
|
|
40
|
+
ctx,
|
|
41
|
+
operations,
|
|
42
|
+
_include,
|
|
43
|
+
exclude.map((x) => x.endpoint),
|
|
44
|
+
)),
|
|
45
|
+
);
|
|
46
|
+
}),
|
|
110
47
|
);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
48
|
+
|
|
49
|
+
include = include.filter((op) => {
|
|
50
|
+
if (
|
|
51
|
+
exclude.some(
|
|
52
|
+
(pg) =>
|
|
53
|
+
pg.endpoint.method === op.method && pg.endpoint.path === op.path,
|
|
54
|
+
)
|
|
55
|
+
) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
});
|
|
60
|
+
} while (include.length > 0);
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
type: "testScenario",
|
|
64
|
+
step: ctx.state().analyze?.step ?? 0,
|
|
65
|
+
scenarios: exclude.flatMap((pg) => {
|
|
66
|
+
return pg.scenarios.map((plan) => {
|
|
67
|
+
return {
|
|
68
|
+
endpoint: pg.endpoint,
|
|
69
|
+
draft: plan.draft,
|
|
70
|
+
functionName: plan.functionName,
|
|
71
|
+
dependencies: plan.dependsOn,
|
|
72
|
+
} satisfies AutoBeTestScenarioEvent.IScenario;
|
|
73
|
+
});
|
|
74
|
+
}),
|
|
75
|
+
created_at: new Date().toISOString(),
|
|
76
|
+
} as AutoBeTestScenarioEvent;
|
|
121
77
|
}
|
|
122
78
|
|
|
123
|
-
async
|
|
79
|
+
const execute = async <Model extends ILlmSchema.Model>(
|
|
124
80
|
ctx: AutoBeContext<Model>,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
)
|
|
129
|
-
const pointer: IPointer<
|
|
130
|
-
value:
|
|
81
|
+
ops: AutoBeOpenApi.IOperation[],
|
|
82
|
+
include: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
|
|
83
|
+
exclude: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
|
|
84
|
+
) => {
|
|
85
|
+
const pointer: IPointer<IAutoBeTestScenarioApplication.IScenarioGroup[]> = {
|
|
86
|
+
value: [],
|
|
131
87
|
};
|
|
132
|
-
|
|
133
|
-
const agentica = new MicroAgentica({
|
|
88
|
+
const agentica: MicroAgentica<Model> = new MicroAgentica({
|
|
134
89
|
model: ctx.model,
|
|
135
90
|
vendor: ctx.vendor,
|
|
136
91
|
config: {
|
|
137
|
-
...(ctx.config ?? {
|
|
138
|
-
|
|
139
|
-
describe:
|
|
140
|
-
return "Answer only 'completion' or 'failure'.";
|
|
141
|
-
},
|
|
92
|
+
...(ctx.config ?? {}),
|
|
93
|
+
executor: {
|
|
94
|
+
describe: null,
|
|
142
95
|
},
|
|
143
96
|
},
|
|
144
97
|
tokenUsage: ctx.usage(),
|
|
145
|
-
histories:
|
|
146
|
-
...transformTestScenarioHistories(ctx.state(), allEndpoints, files),
|
|
147
|
-
],
|
|
98
|
+
histories: createHistoryProperties(ops, include, exclude),
|
|
148
99
|
controllers: [
|
|
149
100
|
createApplication({
|
|
150
101
|
model: ctx.model,
|
|
151
102
|
build: (next) => {
|
|
152
103
|
pointer.value ??= [];
|
|
153
|
-
pointer.value.push(...next.
|
|
104
|
+
pointer.value.push(...next.scenarioGroups);
|
|
154
105
|
},
|
|
155
106
|
}),
|
|
156
107
|
],
|
|
157
108
|
});
|
|
158
109
|
enforceToolCall(agentica);
|
|
159
110
|
|
|
160
|
-
await agentica.conversate(
|
|
161
|
-
|
|
162
|
-
|
|
111
|
+
await agentica.conversate(`create test scenarios.`);
|
|
112
|
+
if (pointer.value.length === 0) {
|
|
113
|
+
throw new Error("Failed to create test plans.");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return pointer.value;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const createHistoryProperties = (
|
|
120
|
+
operations: AutoBeOpenApi.IOperation[],
|
|
121
|
+
include: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
|
|
122
|
+
exclude: Pick<AutoBeOpenApi.IOperation, "method" | "path">[],
|
|
123
|
+
) => [
|
|
124
|
+
{
|
|
125
|
+
id: v4(),
|
|
126
|
+
created_at: new Date().toISOString(),
|
|
127
|
+
type: "systemMessage",
|
|
128
|
+
text: AutoBeSystemPromptConstant.TEST_SCENARIO,
|
|
129
|
+
} satisfies IAgenticaHistoryJson.ISystemMessage,
|
|
130
|
+
{
|
|
131
|
+
id: v4(),
|
|
132
|
+
created_at: new Date().toISOString(),
|
|
133
|
+
type: "systemMessage",
|
|
134
|
+
text: [
|
|
135
|
+
"Below are the full operations. Please refer to this.",
|
|
136
|
+
"Your role is to draft all test cases for each given Operation.",
|
|
137
|
+
"It is also permissible to write multiple test codes on a single endpoint.",
|
|
138
|
+
"However, rather than meaningless tests, business logic tests should be written and an E2E test situation should be assumed.",
|
|
163
139
|
"",
|
|
164
140
|
"```json",
|
|
165
|
-
JSON.stringify(
|
|
141
|
+
JSON.stringify(
|
|
142
|
+
operations.map((el) => ({
|
|
143
|
+
path: el.path,
|
|
144
|
+
method: el.method,
|
|
145
|
+
summary: el.summary,
|
|
146
|
+
})),
|
|
147
|
+
),
|
|
166
148
|
"```",
|
|
167
149
|
].join("\n"),
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
150
|
+
} satisfies IAgenticaHistoryJson.ISystemMessage,
|
|
151
|
+
{
|
|
152
|
+
id: v4(),
|
|
153
|
+
created_at: new Date().toISOString(),
|
|
154
|
+
type: "systemMessage",
|
|
155
|
+
text: [
|
|
156
|
+
"# Included in Test Plan",
|
|
157
|
+
include
|
|
158
|
+
.map((el) => `- ${el.method.toUpperCase()}: ${el.path}`)
|
|
159
|
+
.join("\n"),
|
|
160
|
+
"",
|
|
161
|
+
"# Excluded from Test Plan",
|
|
162
|
+
"These are the endpoints that have already been used in test codes generated as part of a plan group.",
|
|
163
|
+
"These endpoints do not need to be tested again.",
|
|
164
|
+
"However, it is allowed to reference or depend on these endpoints when writing test codes for other purposes.",
|
|
165
|
+
exclude
|
|
166
|
+
.map((el) => `- ${el.method.toUpperCase()}: ${el.path}`)
|
|
167
|
+
.join("\n"),
|
|
168
|
+
].join("\n"),
|
|
169
|
+
} satisfies IAgenticaHistoryJson.ISystemMessage,
|
|
170
|
+
];
|
|
172
171
|
|
|
173
172
|
function createApplication<Model extends ILlmSchema.Model>(props: {
|
|
174
173
|
model: Model;
|
|
175
|
-
build: (next:
|
|
174
|
+
build: (next: IAutoBeTestScenarioApplication.IProps) => void;
|
|
176
175
|
}): IAgenticaController.IClass<Model> {
|
|
177
176
|
assertSchemaModel(props.model);
|
|
178
177
|
|
|
179
178
|
const application: ILlmApplication<Model> = collection[
|
|
180
179
|
props.model
|
|
181
180
|
] as unknown as ILlmApplication<Model>;
|
|
181
|
+
|
|
182
|
+
application.functions[0].validate = (next: unknown): IValidation => {
|
|
183
|
+
const result: IValidation<IAutoBeTestScenarioApplication.IProps> =
|
|
184
|
+
typia.validate<IAutoBeTestScenarioApplication.IProps>(next);
|
|
185
|
+
if (result.success === false) return result;
|
|
186
|
+
|
|
187
|
+
const errors: IValidation.IError[] = [];
|
|
188
|
+
result.data.scenarioGroups.forEach((pg, i, arr) => {
|
|
189
|
+
arr.forEach((target, j) => {
|
|
190
|
+
if (
|
|
191
|
+
i !== j &&
|
|
192
|
+
target.endpoint.method === pg.endpoint.method &&
|
|
193
|
+
target.endpoint.path === pg.endpoint.path
|
|
194
|
+
) {
|
|
195
|
+
if (
|
|
196
|
+
!errors.some(
|
|
197
|
+
(el) =>
|
|
198
|
+
el.path !== `planGroups[${j}].path` &&
|
|
199
|
+
el.value !== target.endpoint.path,
|
|
200
|
+
)
|
|
201
|
+
) {
|
|
202
|
+
errors.push({
|
|
203
|
+
path: `planGroups[${j}].path`,
|
|
204
|
+
expected: `planGroup's {method + path} cannot duplicated.`,
|
|
205
|
+
value: target.endpoint.path,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (
|
|
210
|
+
!errors.some(
|
|
211
|
+
(el) =>
|
|
212
|
+
el.path !== `planGroups[${j}].method` &&
|
|
213
|
+
el.value !== target.endpoint.method,
|
|
214
|
+
)
|
|
215
|
+
) {
|
|
216
|
+
errors.push({
|
|
217
|
+
path: `planGroups[${j}].method`,
|
|
218
|
+
expected: `planGroup's {method + path} cannot duplicated.`,
|
|
219
|
+
value: target.endpoint.method,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
if (errors.length !== 0) {
|
|
227
|
+
console.log(JSON.stringify(errors, null, 2), "errors");
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
errors,
|
|
231
|
+
data: next,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return result;
|
|
236
|
+
};
|
|
182
237
|
return {
|
|
183
238
|
protocol: "class",
|
|
184
|
-
name: "Make
|
|
239
|
+
name: "Make test plans",
|
|
185
240
|
application,
|
|
186
241
|
execute: {
|
|
187
242
|
makeScenario: (next) => {
|
|
188
243
|
props.build(next);
|
|
189
244
|
},
|
|
190
|
-
} satisfies
|
|
245
|
+
} satisfies IAutoBeTestScenarioApplication,
|
|
191
246
|
};
|
|
192
247
|
}
|
|
193
248
|
|
|
194
249
|
const claude = typia.llm.application<
|
|
195
|
-
|
|
250
|
+
IAutoBeTestScenarioApplication,
|
|
196
251
|
"claude",
|
|
197
252
|
{
|
|
198
253
|
reference: true;
|
|
@@ -200,7 +255,7 @@ const claude = typia.llm.application<
|
|
|
200
255
|
>();
|
|
201
256
|
const collection = {
|
|
202
257
|
chatgpt: typia.llm.application<
|
|
203
|
-
|
|
258
|
+
IAutoBeTestScenarioApplication,
|
|
204
259
|
"chatgpt",
|
|
205
260
|
{ reference: true }
|
|
206
261
|
>(),
|
|
@@ -208,19 +263,5 @@ const collection = {
|
|
|
208
263
|
llama: claude,
|
|
209
264
|
deepseek: claude,
|
|
210
265
|
"3.1": claude,
|
|
211
|
-
"3.0": typia.llm.application<
|
|
266
|
+
"3.0": typia.llm.application<IAutoBeTestScenarioApplication, "3.0">(),
|
|
212
267
|
};
|
|
213
|
-
|
|
214
|
-
interface IApplication {
|
|
215
|
-
/**
|
|
216
|
-
* Make user scenarios for the given endpoints.
|
|
217
|
-
*
|
|
218
|
-
* @param props Properties containing the endpoints and user scenarios.
|
|
219
|
-
*/
|
|
220
|
-
makeScenario(props: IMakeScenarioProps): void;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
interface IMakeScenarioProps {
|
|
224
|
-
/** Array of user scenarios. */
|
|
225
|
-
scenarios: AutoBeTest.IScenario[];
|
|
226
|
-
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { AutoBeOpenApi } from "@autobe/interface";
|
|
2
|
+
|
|
3
|
+
export interface IAutoBeTestScenarioApplication {
|
|
4
|
+
/**
|
|
5
|
+
* Make test scenarios for the given endpoints.
|
|
6
|
+
*
|
|
7
|
+
* @param props Properties containing the endpoints and test scenarios.
|
|
8
|
+
*/
|
|
9
|
+
makeScenario(props: IAutoBeTestScenarioApplication.IProps): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export namespace IAutoBeTestScenarioApplication {
|
|
13
|
+
export interface IProps {
|
|
14
|
+
/** Array of test scenario groups. */
|
|
15
|
+
scenarioGroups: IAutoBeTestScenarioApplication.IScenarioGroup[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface IScenarioGroup {
|
|
19
|
+
/** Target API endpoint to test. */
|
|
20
|
+
endpoint: AutoBeOpenApi.IEndpoint;
|
|
21
|
+
|
|
22
|
+
/** Array of test scenarios. */
|
|
23
|
+
scenarios: IScenario[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Represents a test scenario for a single API operation.
|
|
28
|
+
*
|
|
29
|
+
* This interface extends `AutoBeOpenApi.IEndpoint`, inheriting its HTTP
|
|
30
|
+
* method and path information, and adds two key properties:
|
|
31
|
+
*
|
|
32
|
+
* - `draft`: A free-form, human-readable test scenario description for the API
|
|
33
|
+
* endpoint.
|
|
34
|
+
* - `dependsOn`: A list of other API endpoints that must be invoked beforehand
|
|
35
|
+
* in order to prepare the context for this test. Each dependency includes
|
|
36
|
+
* the purpose of the dependency.
|
|
37
|
+
*
|
|
38
|
+
* This structure is intended to help organize test specifications for complex
|
|
39
|
+
* workflows and ensure that all prerequisites are explicitly declared.
|
|
40
|
+
*/
|
|
41
|
+
export interface IScenario {
|
|
42
|
+
/**
|
|
43
|
+
* A detailed natural language description of how this API endpoint should
|
|
44
|
+
* be tested. This should include both successful and failure scenarios,
|
|
45
|
+
* business rule validations, edge cases, and any sequence of steps
|
|
46
|
+
* necessary to perform the test. A subsequent agent will use this draft to
|
|
47
|
+
* generate multiple test scenarios.
|
|
48
|
+
*/
|
|
49
|
+
draft: string;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Descriptive function name derived from the user scenario.
|
|
53
|
+
*
|
|
54
|
+
* The function name serves as a concise, technical identifier that clearly
|
|
55
|
+
* represents the specific user scenario being described. It should be
|
|
56
|
+
* immediately understandable and directly correspond to the user situation
|
|
57
|
+
* without requiring additional context.
|
|
58
|
+
*
|
|
59
|
+
* ## Naming Convention
|
|
60
|
+
*
|
|
61
|
+
* - Must start with `test_` prefix (mandatory requirement)
|
|
62
|
+
* - Use snake_case formatting throughout
|
|
63
|
+
* - Include the primary user action (create, get, update, delete, list, etc.)
|
|
64
|
+
* - Specify the target resource (user, product, order, profile, etc.)
|
|
65
|
+
* - Add scenario-specific context (valid_data, invalid_email, not_found,
|
|
66
|
+
* etc.)
|
|
67
|
+
*
|
|
68
|
+
* ## Content Structure
|
|
69
|
+
*
|
|
70
|
+
* Function names should follow this pattern:
|
|
71
|
+
* `test_[user_action]_[resource]_[scenario_context]`
|
|
72
|
+
*
|
|
73
|
+
* Where:
|
|
74
|
+
*
|
|
75
|
+
* - `user_action`: What the user is trying to do
|
|
76
|
+
* - `resource`: What the user is interacting with
|
|
77
|
+
* - `scenario_context`: The specific situation or condition
|
|
78
|
+
*
|
|
79
|
+
* ## User-Focused Examples
|
|
80
|
+
*
|
|
81
|
+
* - `test_create_user_profile_with_complete_information` - User providing all
|
|
82
|
+
* available profile data
|
|
83
|
+
* - `test_retrieve_user_profile_when_profile_exists` - User accessing their
|
|
84
|
+
* existing profile
|
|
85
|
+
* - `test_update_user_email_with_valid_new_address` - User changing their
|
|
86
|
+
* email to a valid new one
|
|
87
|
+
* - `test_delete_user_account_when_user_lacks_permission` - User attempting
|
|
88
|
+
* account deletion without authorization
|
|
89
|
+
* - `test_search_user_profiles_with_pagination_preferences` - User browsing
|
|
90
|
+
* profiles with specific pagination
|
|
91
|
+
*
|
|
92
|
+
* ## Clarity Guidelines
|
|
93
|
+
*
|
|
94
|
+
* - Prioritize clarity over brevity
|
|
95
|
+
* - Avoid technical jargon or implementation terms
|
|
96
|
+
* - Use terminology that reflects user perspective
|
|
97
|
+
* - Ensure the name alone conveys the user's intent
|
|
98
|
+
* - Make it understandable to non-technical stakeholders
|
|
99
|
+
* - Keep consistent with user scenario description
|
|
100
|
+
*
|
|
101
|
+
* ## Single Endpoint Alignment
|
|
102
|
+
*
|
|
103
|
+
* Function names must reflect scenarios that:
|
|
104
|
+
*
|
|
105
|
+
* - Accomplish user goals through this single endpoint only
|
|
106
|
+
* - Don't imply dependency on other API operations
|
|
107
|
+
* - Represent complete user interactions
|
|
108
|
+
*/
|
|
109
|
+
functionName: string;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* A list of other API endpoints that must be executed before this test
|
|
113
|
+
* scenario. This helps express dependencies such as data creation or
|
|
114
|
+
* authentication steps required to reach the intended test state.
|
|
115
|
+
*/
|
|
116
|
+
dependsOn: IDependsOn[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface IDependsOn {
|
|
120
|
+
/** Target API endpoint that must be executed before the main operation. */
|
|
121
|
+
endpoint: AutoBeOpenApi.IEndpoint;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* A concise exscenarioation of why this API call is required before
|
|
125
|
+
* executing the test for the main operation.
|
|
126
|
+
*
|
|
127
|
+
* Example: "Creates a category so that a product can be linked to it during
|
|
128
|
+
* creation."
|
|
129
|
+
*/
|
|
130
|
+
purpose: string;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { IAgenticaHistoryJson } from "@agentica/core";
|
|
2
|
+
import { AutoBeOpenApi } from "@autobe/interface";
|
|
2
3
|
import { v4 } from "uuid";
|
|
3
4
|
|
|
4
5
|
import { AutoBeSystemPromptConstant } from "../../constants/AutoBeSystemPromptConstant";
|
|
5
6
|
|
|
6
7
|
export const transformTestCorrectHistories = (
|
|
7
|
-
|
|
8
|
-
dtoFiles: Record<string, string>,
|
|
8
|
+
document: AutoBeOpenApi.IDocument | null,
|
|
9
9
|
): Array<
|
|
10
10
|
IAgenticaHistoryJson.IAssistantMessage | IAgenticaHistoryJson.ISystemMessage
|
|
11
11
|
> => {
|
|
@@ -33,15 +33,19 @@ export const transformTestCorrectHistories = (
|
|
|
33
33
|
"- Keep all tests deterministic and reliable.",
|
|
34
34
|
"",
|
|
35
35
|
"## File References",
|
|
36
|
-
"###
|
|
37
|
-
"```
|
|
38
|
-
JSON.stringify(
|
|
39
|
-
"```",
|
|
40
|
-
"",
|
|
41
|
-
"### DTO Files",
|
|
42
|
-
"```typescript",
|
|
43
|
-
JSON.stringify(dtoFiles, null, 2),
|
|
36
|
+
"### OpenAPI Like Document",
|
|
37
|
+
"```json",
|
|
38
|
+
JSON.stringify(document),
|
|
44
39
|
"```",
|
|
40
|
+
// "### API Files",
|
|
41
|
+
// "```typescript",
|
|
42
|
+
// JSON.stringify(apiFiles, null, 2),
|
|
43
|
+
// "```",
|
|
44
|
+
// "",
|
|
45
|
+
// "### DTO Files",
|
|
46
|
+
// "```typescript",
|
|
47
|
+
// JSON.stringify(dtoFiles, null, 2),
|
|
48
|
+
// "```",
|
|
45
49
|
"",
|
|
46
50
|
"Now Fix the E2E test function based on the given error information.",
|
|
47
51
|
"Only output a single `async function` named `test_api_{...}`. No explanation, no commentary.",
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { IAgenticaHistoryJson } from "@agentica/core";
|
|
2
|
+
import { AutoBeTestScenarioEvent } from "@autobe/interface";
|
|
2
3
|
import { v4 } from "uuid";
|
|
3
4
|
|
|
4
5
|
import { AutoBeSystemPromptConstant } from "../../constants/AutoBeSystemPromptConstant";
|
|
5
6
|
|
|
6
|
-
export const transformTestProgressHistories = (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export const transformTestProgressHistories = (props: {
|
|
8
|
+
scenario: AutoBeTestScenarioEvent.IScenario;
|
|
9
|
+
dto: Record<string, string>;
|
|
10
|
+
sdk: Record<string, string>;
|
|
11
|
+
e2e: Record<string, string>;
|
|
12
|
+
}): Array<
|
|
10
13
|
IAgenticaHistoryJson.IAssistantMessage | IAgenticaHistoryJson.ISystemMessage
|
|
11
14
|
> => {
|
|
12
15
|
return [
|
|
@@ -21,30 +24,30 @@ export const transformTestProgressHistories = (
|
|
|
21
24
|
created_at: new Date().toISOString(),
|
|
22
25
|
type: "assistantMessage",
|
|
23
26
|
text: [
|
|
24
|
-
"
|
|
25
|
-
"You will be given a **scenario**, and your job is to generate the corresponding **E2E test code** using only the provided API functions and DTOs.",
|
|
27
|
+
"Here is the list of input material composition.",
|
|
26
28
|
"",
|
|
27
|
-
"
|
|
28
|
-
"- Follow the base E2E test style strictly. Never use other frameworks like Jest or Mocha.",
|
|
29
|
-
"- Use `TestValidator.equals(...)` and `typia.assert(...)` to verify results.",
|
|
30
|
-
"- Use `HubApi.functional.XXX` for all API calls. These are defined in API Files.",
|
|
31
|
-
"- Use helper functions like `generate_random_xxx(...)` **only if** they already exist in the base test imports.",
|
|
32
|
-
"- Do not invent new helpers or use utilities that are not explicitly shown.",
|
|
33
|
-
"- Keep all tests deterministic and reliable.",
|
|
29
|
+
"Make e2e test functions based on the following information.",
|
|
34
30
|
"",
|
|
35
|
-
"##
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
JSON.stringify(apiFiles, null, 2),
|
|
31
|
+
"## Secnario Plan",
|
|
32
|
+
"```json",
|
|
33
|
+
JSON.stringify(props.scenario),
|
|
39
34
|
"```",
|
|
40
35
|
"",
|
|
41
|
-
"
|
|
42
|
-
"```
|
|
43
|
-
JSON.stringify(
|
|
36
|
+
"## DTO Definitions",
|
|
37
|
+
"```json",
|
|
38
|
+
JSON.stringify(props.dto),
|
|
39
|
+
"```",
|
|
40
|
+
"",
|
|
41
|
+
"## API (SDK) Functions",
|
|
42
|
+
"```json",
|
|
43
|
+
JSON.stringify(props.sdk),
|
|
44
|
+
"```",
|
|
45
|
+
"",
|
|
46
|
+
"## E2E Mockup Functions",
|
|
47
|
+
"```json",
|
|
48
|
+
JSON.stringify(props.e2e),
|
|
44
49
|
"```",
|
|
45
50
|
"",
|
|
46
|
-
"Now generate the E2E test function based on the given scenario.",
|
|
47
|
-
"Only output a single `async function` named `test_api_{...}`. No explanation, no commentary.",
|
|
48
51
|
].join("\n"),
|
|
49
52
|
},
|
|
50
53
|
];
|