feat(scenarios): add timeoutSeconds to scenarios and steps

- add timeoutSeconds field to scenario and step entities
- add timeoutSeconds to create/update DTOs for scenario and step
- enforce timeout via scheduler: abort run if step exceeds limit
- expose timeoutSeconds in MCP create/update scenario and step tools
- add client-side type, API, i18n, and form support for timeoutSeconds
- add integration tests for timeout persistence via REST and MCP
This commit is contained in:
2026-04-17 13:46:30 +03:00
parent 8dbd319bba
commit a50dce2755
19 changed files with 402 additions and 12 deletions
+30 -2
View File
@@ -476,14 +476,21 @@ export class McpService {
.uuid()
.optional()
.describe("Optional linked environment ID"),
timeoutSeconds: z
.number()
.int()
.min(1)
.optional()
.describe("Scenario-level timeout in seconds (default 600)"),
},
},
async ({ name, description, environmentId }) => {
async ({ name, description, environmentId, timeoutSeconds }) => {
try {
const scenario = await this.scenarioService.create({
name,
description,
environmentId,
timeoutSeconds,
});
return {
content: [
@@ -515,14 +522,22 @@ export class McpService {
.nullable()
.optional()
.describe("Linked environment ID (null to unlink)"),
timeoutSeconds: z
.number()
.int()
.min(1)
.nullable()
.optional()
.describe("Scenario-level timeout in seconds (null to reset to default 600)"),
},
},
async ({ id, name, description, environmentId }) => {
async ({ id, name, description, environmentId, timeoutSeconds }) => {
try {
const scenario = await this.scenarioService.update(id, {
name,
description,
environmentId,
timeoutSeconds,
});
return {
content: [
@@ -580,6 +595,12 @@ export class McpService {
.string()
.optional()
.describe("Playwright JS code to execute (exec steps)"),
timeoutSeconds: z
.number()
.int()
.min(1)
.optional()
.describe("Step-level timeout in seconds (default 60, falls back to scenario timeout)"),
},
},
async ({ scenarioId, ...dto }) => {
@@ -640,6 +661,13 @@ export class McpService {
.describe("New step type"),
title: z.string().optional().describe("New step title"),
execCode: z.string().optional().describe("New exec code"),
timeoutSeconds: z
.number()
.int()
.min(1)
.nullable()
.optional()
.describe("Step-level timeout in seconds (null to reset to default)"),
},
},
async ({ scenarioId, stepId, ...dto }) => {