From caacd59ccacaf5edd60292d28414de8247ace9ad Mon Sep 17 00:00:00 2001 From: Fabian Both Date: Mon, 12 Jan 2026 17:35:10 +0100 Subject: [PATCH 01/15] add edit CLI command --- src/cli.ts | 35 +++++++++----- src/tools/yamlMutations/edit.ts | 84 +++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+), 11 deletions(-) create mode 100644 src/tools/yamlMutations/edit.ts diff --git a/src/cli.ts b/src/cli.ts index 3ffc061..b94e207 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -39,6 +39,7 @@ import { import { init, switchTestTarget } from "./tools/init"; import { update } from "./tools/update"; import { version } from "./version"; +import { edit } from "./tools/yamlMutations/edit"; export const BINARY_NAME = "octomind"; @@ -49,17 +50,17 @@ type WithTestTargetId = { testTargetId: string }; const addTestTargetWrapper = (fn: (options: T) => Promise) => - async ( - options: Omit & Partial>, - ): Promise => { - const resolvedTestTargetId = await resolveTestTargetId( - options.testTargetId, - ); - await fn({ - ...options, - testTargetId: resolvedTestTargetId, - } as T); - }; + async ( + options: Omit & Partial>, + ): Promise => { + const resolvedTestTargetId = await resolveTestTargetId( + options.testTargetId, + ); + await fn({ + ...options, + testTargetId: resolvedTestTargetId, + } as T); + }; const testTargetIdOption = new Option( "-t, --test-target-id [id]", @@ -401,6 +402,18 @@ export const buildCmd = (): CompletableCommand => { .addOption(testTargetIdOption) .action(addTestTargetWrapper(pushTestTarget)); + // noinspection RequiredAttributes + createCommandWithCommonOptions(program, "edit-test-case") + .completer(testTargetIdCompleter) + .description("Edit yaml test case") + .helpGroup("test-cases") + .addOption(testTargetIdOption) + .requiredOption( + "-f, --file-path ", + "The path to the local yaml file you want to edit", + ) + .action(addTestTargetWrapper(edit)); + createCommandWithCommonOptions(program, "list-test-targets") .description("List all test targets") .helpGroup("test-targets") diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts new file mode 100644 index 0000000..09ee3e5 --- /dev/null +++ b/src/tools/yamlMutations/edit.ts @@ -0,0 +1,84 @@ +import fs from "fs"; +import path from "path"; + +import yaml from "yaml"; + +import { client, handleError } from "../client"; +import { checkForConsistency } from "../sync/consistency"; +import { draftPush } from "../sync/push"; +import { SyncTestCase } from "../sync/types"; +import { readTestCasesFromDir } from "../sync/yml"; +import { findOctomindFolder, getAbsoluteFilePathInOctomindRoot } from "../../helpers"; +import { OCTOMIND_FOLDER_NAME } from "../../constants"; + +type EditOptions = { + testTargetId: string; + filePath: string; +}; + + +const getRelevantTestCases = ( + testCasesById: Record, + startTestCase: SyncTestCase, +): SyncTestCase[] => { + let dependencyId = startTestCase.dependencyId; + const result: SyncTestCase[] = [startTestCase]; + + while (dependencyId) { + const currentTestCase = testCasesById[dependencyId]; + + if (!currentTestCase) { + throw new Error( + `Could not find dependency ${dependencyId} for ${startTestCase.id}`, + ); + } + + result.push(currentTestCase); + dependencyId = currentTestCase?.dependencyId; + } + + return result; +}; + +const loadTestCase = (testCasePath: string): SyncTestCase => { + try { + const content = fs.readFileSync(testCasePath, "utf8"); + return yaml.parse(content); + } catch (error) { + throw new Error(`Could not parse ${testCasePath}: ${error}`); + } +}; + +export const edit = async (options: EditOptions): Promise => { + const octomindRoot = await findOctomindFolder(); + if (!octomindRoot) { + throw new Error( + `Could not find ${OCTOMIND_FOLDER_NAME} folder, make sure to pull before trying to edit`, + ); + } + const testCaseFilePath = await getAbsoluteFilePathInOctomindRoot({ octomindRoot, filePath: options.filePath }) + if (!testCaseFilePath) { + throw new Error(`Could not find ${options.filePath} in folder ${octomindRoot}`) + } + + const testCaseToEdit = loadTestCase(testCaseFilePath); + + const testCases = readTestCasesFromDir(octomindRoot); + const testCasesById = Object.fromEntries(testCases.map((tc) => [tc.id, tc])); + const relevantTestCases = getRelevantTestCases(testCasesById, testCaseToEdit); + + checkForConsistency(relevantTestCases); + + const response = await draftPush( + { + testCases: relevantTestCases, + }, + { + testTargetId: options.testTargetId, + client, + onError: handleError, + }, + ); + + console.log(response); +}; From bba3b534073b7fac751b7a598cf0a10a1eca0161 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:02:43 +0100 Subject: [PATCH 02/15] fix linting --- src/cli.ts | 24 ++++++++++++------------ src/tools/yamlMutations/edit.ts | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index b94e207..ed6e970 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -38,8 +38,8 @@ import { } from "./tools"; import { init, switchTestTarget } from "./tools/init"; import { update } from "./tools/update"; -import { version } from "./version"; import { edit } from "./tools/yamlMutations/edit"; +import { version } from "./version"; export const BINARY_NAME = "octomind"; @@ -50,17 +50,17 @@ type WithTestTargetId = { testTargetId: string }; const addTestTargetWrapper = (fn: (options: T) => Promise) => - async ( - options: Omit & Partial>, - ): Promise => { - const resolvedTestTargetId = await resolveTestTargetId( - options.testTargetId, - ); - await fn({ - ...options, - testTargetId: resolvedTestTargetId, - } as T); - }; + async ( + options: Omit & Partial>, + ): Promise => { + const resolvedTestTargetId = await resolveTestTargetId( + options.testTargetId, + ); + await fn({ + ...options, + testTargetId: resolvedTestTargetId, + } as T); + }; const testTargetIdOption = new Option( "-t, --test-target-id [id]", diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index 09ee3e5..689c309 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -3,20 +3,22 @@ import path from "path"; import yaml from "yaml"; +import { OCTOMIND_FOLDER_NAME } from "../../constants"; +import { + findOctomindFolder, + getAbsoluteFilePathInOctomindRoot, +} from "../../helpers"; import { client, handleError } from "../client"; import { checkForConsistency } from "../sync/consistency"; import { draftPush } from "../sync/push"; import { SyncTestCase } from "../sync/types"; import { readTestCasesFromDir } from "../sync/yml"; -import { findOctomindFolder, getAbsoluteFilePathInOctomindRoot } from "../../helpers"; -import { OCTOMIND_FOLDER_NAME } from "../../constants"; type EditOptions = { testTargetId: string; filePath: string; }; - const getRelevantTestCases = ( testCasesById: Record, startTestCase: SyncTestCase, @@ -56,9 +58,14 @@ export const edit = async (options: EditOptions): Promise => { `Could not find ${OCTOMIND_FOLDER_NAME} folder, make sure to pull before trying to edit`, ); } - const testCaseFilePath = await getAbsoluteFilePathInOctomindRoot({ octomindRoot, filePath: options.filePath }) + const testCaseFilePath = await getAbsoluteFilePathInOctomindRoot({ + octomindRoot, + filePath: options.filePath, + }); if (!testCaseFilePath) { - throw new Error(`Could not find ${options.filePath} in folder ${octomindRoot}`) + throw new Error( + `Could not find ${options.filePath} in folder ${octomindRoot}`, + ); } const testCaseToEdit = loadTestCase(testCaseFilePath); From 21b3a4595a895624eb1a3439cbde306a40c36836 Mon Sep 17 00:00:00 2001 From: Fabian Both Date: Tue, 13 Jan 2026 17:58:09 +0100 Subject: [PATCH 03/15] fix test case path --- src/helpers.ts | 13 ++++++------- tests/helpers.spec.ts | 42 ++++-------------------------------------- 2 files changed, 10 insertions(+), 45 deletions(-) diff --git a/src/helpers.ts b/src/helpers.ts index 06fd58e..c6cce4d 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -68,12 +68,11 @@ export const getAbsoluteFilePathInOctomindRoot = async ({ filePath: string; octomindRoot: string; }): Promise => { - try { - const resolvedPath = await fsPromises.realpath( - path.isAbsolute(filePath) ? filePath : path.join(octomindRoot, filePath), - ); - return resolvedPath.startsWith(octomindRoot) ? resolvedPath : null; - } catch { - return null; + let resolvedPath: string + if (path.isAbsolute(filePath)) { + resolvedPath = filePath + } else { + resolvedPath = path.resolve(filePath, path.join(octomindRoot, filePath)) } + return resolvedPath.startsWith(octomindRoot) ? resolvedPath : null; }; diff --git a/tests/helpers.spec.ts b/tests/helpers.spec.ts index b09dff3..4c76cde 100644 --- a/tests/helpers.spec.ts +++ b/tests/helpers.spec.ts @@ -109,34 +109,29 @@ describe("helpers", () => { }); it("should resolve relative path within octomind root", async () => { - const filePath = path.join(octomindRoot, "test-case.yaml"); - await fsPromises.writeFile(filePath, ""); + const expectedPath = path.join(octomindRoot, "test-case.yaml"); const result = await getAbsoluteFilePathInOctomindRoot({ filePath: "test-case.yaml", octomindRoot, }); - expect(result).toBe(filePath); + expect(result).toBe(expectedPath); }); it("should resolve nested relative path within octomind root", async () => { - const subdir = path.join(octomindRoot, "subdir"); - await fsPromises.mkdir(subdir); - const filePath = path.join(subdir, "test-case.yaml"); - await fsPromises.writeFile(filePath, ""); + const expectedPath = path.join(octomindRoot, "subdir", "test-case.yaml"); const result = await getAbsoluteFilePathInOctomindRoot({ filePath: "subdir/test-case.yaml", octomindRoot, }); - expect(result).toBe(filePath); + expect(result).toBe(expectedPath); }); it("should accept absolute path within octomind root", async () => { const filePath = path.join(octomindRoot, "test-case.yaml"); - await fsPromises.writeFile(filePath, ""); const result = await getAbsoluteFilePathInOctomindRoot({ filePath, @@ -148,7 +143,6 @@ describe("helpers", () => { it("should return null for absolute path outside octomind root", async () => { const outsideFile = path.join(tmpDir, "outside.yaml"); - await fsPromises.writeFile(outsideFile, ""); const result = await getAbsoluteFilePathInOctomindRoot({ filePath: outsideFile, @@ -159,9 +153,6 @@ describe("helpers", () => { }); it("should return null for path traversal attempts", async () => { - const outsideFile = path.join(tmpDir, "outside.yaml"); - await fsPromises.writeFile(outsideFile, ""); - const result = await getAbsoluteFilePathInOctomindRoot({ filePath: "../outside.yaml", octomindRoot, @@ -170,30 +161,5 @@ describe("helpers", () => { expect(result).toBeNull(); }); - it("should return null for non-existent file", async () => { - const result = await getAbsoluteFilePathInOctomindRoot({ - filePath: "does-not-exist.yaml", - octomindRoot, - }); - - expect(result).toBeNull(); - }); - - it("should return null for malformed path with nested octomind structure", async () => { - // e.g. /some/folder/.octomind/some/folder/.octomind/a.yaml - const malformedPath = path.join( - octomindRoot, - tmpDir, - OCTOMIND_FOLDER_NAME, - "a.yaml", - ); - - const result = await getAbsoluteFilePathInOctomindRoot({ - filePath: malformedPath, - octomindRoot, - }); - - expect(result).toBeNull(); - }); }); }); From 2526bb2b3dfe652158b3345844628cec6d35c58d Mon Sep 17 00:00:00 2001 From: Fabian Both Date: Tue, 13 Jan 2026 18:17:20 +0100 Subject: [PATCH 04/15] absolute files in octomind root --- src/helpers.ts | 31 ++++++++++++++++++++++++++----- tests/helpers.spec.ts | 22 +++++++++++++++++----- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/helpers.ts b/src/helpers.ts index c6cce4d..a3e11d3 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -68,11 +68,32 @@ export const getAbsoluteFilePathInOctomindRoot = async ({ filePath: string; octomindRoot: string; }): Promise => { - let resolvedPath: string + const isWithinOctomindRoot = (p: string) => p.startsWith(octomindRoot); + + const isFile = async (p: string): Promise => { + try { + const stats = await fsPromises.stat(p); + return stats.isFile(); + } catch { + return false; + } + }; + if (path.isAbsolute(filePath)) { - resolvedPath = filePath - } else { - resolvedPath = path.resolve(filePath, path.join(octomindRoot, filePath)) + return isWithinOctomindRoot(filePath) ? filePath : null; } - return resolvedPath.startsWith(octomindRoot) ? resolvedPath : null; + + // For relative paths, try resolving from cwd first, then from octomindRoot + const candidates = [ + path.resolve(filePath), + path.resolve(octomindRoot, filePath), + ]; + + for (const candidate of candidates) { + if (isWithinOctomindRoot(candidate) && (await isFile(candidate))) { + return candidate; + } + } + + return null; }; diff --git a/tests/helpers.spec.ts b/tests/helpers.spec.ts index 4c76cde..cd1c92a 100644 --- a/tests/helpers.spec.ts +++ b/tests/helpers.spec.ts @@ -109,25 +109,38 @@ describe("helpers", () => { }); it("should resolve relative path within octomind root", async () => { - const expectedPath = path.join(octomindRoot, "test-case.yaml"); + const filePath = path.join(octomindRoot, "test-case.yaml"); + await fsPromises.writeFile(filePath, ""); const result = await getAbsoluteFilePathInOctomindRoot({ filePath: "test-case.yaml", octomindRoot, }); - expect(result).toBe(expectedPath); + expect(result).toBe(filePath); }); it("should resolve nested relative path within octomind root", async () => { - const expectedPath = path.join(octomindRoot, "subdir", "test-case.yaml"); + const subdir = path.join(octomindRoot, "subdir"); + await fsPromises.mkdir(subdir); + const filePath = path.join(subdir, "test-case.yaml"); + await fsPromises.writeFile(filePath, ""); const result = await getAbsoluteFilePathInOctomindRoot({ filePath: "subdir/test-case.yaml", octomindRoot, }); - expect(result).toBe(expectedPath); + expect(result).toBe(filePath); + }); + + it("should return null for non-existent relative path", async () => { + const result = await getAbsoluteFilePathInOctomindRoot({ + filePath: "does-not-exist.yaml", + octomindRoot, + }); + + expect(result).toBeNull(); }); it("should accept absolute path within octomind root", async () => { @@ -160,6 +173,5 @@ describe("helpers", () => { expect(result).toBeNull(); }); - }); }); From 8ef982774150a94c4427f6d85053b2982f5c7346 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:02:58 +0100 Subject: [PATCH 05/15] add open dependency, finish editing implementation --- README.md | 14 ++++++ package.json | 1 + src/helpers.ts | 3 ++ src/tools/sync/push.ts | 9 +++- src/tools/sync/yml.ts | 20 +++++++-- src/tools/test-targets.ts | 2 +- src/tools/yamlMutations/edit.ts | 76 ++++++++++++++++++++++++++++++--- 7 files changed, 115 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 64dc2e2..15ff7a8 100644 --- a/README.md +++ b/README.md @@ -445,6 +445,20 @@ Push local YAML test cases to the test target | `-j, --json` | Output raw JSON response | No | | | `-t, --test-target-id [id]` | Test target ID, if not provided will use the test target id from the config | No | | +## edit-test-case + +Edit yaml test case + +**Usage:** `edit-test-case [options]` + +### Options + +| Option | Description | Required | Default | +|:-------|:----------|:---------|:--------| +| `-j, --json` | Output raw JSON response | No | | +| `-t, --test-target-id [id]` | Test target ID, if not provided will use the test target id from the config | No | | +| `-f, --file-path ` | The path to the local yaml file you want to edit | Yes | | + ## Test Reports ## test-report diff --git a/package.json b/package.json index a773845..c18568a 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@playwright/test": "1.57.0", "@types/shell-quote": "1.7.5", "commander": "14.0.2", + "open": "11.0.0", "openapi-fetch": "0.15.0", "otplib": "13.1.0", "shell-quote": "1.8.3", diff --git a/src/helpers.ts b/src/helpers.ts index a3e11d3..11b7b80 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -97,3 +97,6 @@ export const getAbsoluteFilePathInOctomindRoot = async ({ return null; }; + +export const sleep = (ms: number): Promise => + new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/src/tools/sync/push.ts b/src/tools/sync/push.ts index 173f548..fe8d689 100644 --- a/src/tools/sync/push.ts +++ b/src/tools/sync/push.ts @@ -68,7 +68,14 @@ const defaultPush = async ( export const draftPush = async ( body: TestTargetSyncData, options: Omit & ListOptions, -): Promise<{ success: boolean; versionIds: string[] } | undefined> => { +): Promise< + | { + success: boolean; + versionIds: string[]; + versionIdByStableId: Record; + } + | undefined +> => { const { data, error } = await options.client.POST( "/apiKey/beta/test-targets/{testTargetId}/draft/push", { diff --git a/src/tools/sync/yml.ts b/src/tools/sync/yml.ts index f0aa73e..e0d28db 100644 --- a/src/tools/sync/yml.ts +++ b/src/tools/sync/yml.ts @@ -1,4 +1,5 @@ import fs from "fs"; +import fsPromises from "fs/promises"; import path from "path"; import yaml from "yaml"; @@ -40,7 +41,20 @@ const toFileSystemCompatibleCamelCase = (description: string): string => { return camelCased; }; -export const writeYaml = (data: TestTargetSyncData, destination?: string) => { +export const writeSingleTestCaseYaml = async ( + filePath: string, + testCase: SyncTestCase, +): Promise => { + return fsPromises.writeFile( + filePath, + `# yaml-language-server: $schema=https://app.octomind.dev/schemas/SyncTestCaseSchema.json\n${yaml.stringify(testCase)}`, + ); +}; + +export const writeYaml = async ( + data: TestTargetSyncData, + destination?: string, +): Promise => { cleanupFilesystem({ newTestCases: data.testCases, destination, @@ -50,9 +64,9 @@ export const writeYaml = (data: TestTargetSyncData, destination?: string) => { const folderName = buildFolderName(testCase, data.testCases, destination); const testCaseFilename = buildFilename(testCase, folderName); fs.mkdirSync(folderName, { recursive: true }); - fs.writeFileSync( + await writeSingleTestCaseYaml( path.join(folderName, testCaseFilename), - `# yaml-language-server: $schema=https://app.octomind.dev/schemas/SyncTestCaseSchema.json\n${yaml.stringify(testCase)}`, + testCase, ); } }; diff --git a/src/tools/test-targets.ts b/src/tools/test-targets.ts index 77b185f..ada58cb 100644 --- a/src/tools/test-targets.ts +++ b/src/tools/test-targets.ts @@ -73,7 +73,7 @@ export const pullTestTarget = async ( const destination = (await findOctomindFolder()) ?? path.join(process.cwd(), OCTOMIND_FOLDER_NAME); - writeYaml(data, destination); + await writeYaml(data, destination); console.log("Test Target pulled successfully"); }; diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index 689c309..7963cbf 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -1,18 +1,20 @@ -import fs from "fs"; +import fs, { writeFileSync } from "fs"; import path from "path"; +import open from "open"; import yaml from "yaml"; import { OCTOMIND_FOLDER_NAME } from "../../constants"; import { findOctomindFolder, getAbsoluteFilePathInOctomindRoot, + sleep, } from "../../helpers"; -import { client, handleError } from "../client"; +import { BASE_URL, client, handleError } from "../client"; import { checkForConsistency } from "../sync/consistency"; import { draftPush } from "../sync/push"; import { SyncTestCase } from "../sync/types"; -import { readTestCasesFromDir } from "../sync/yml"; +import { readTestCasesFromDir, writeSingleTestCaseYaml } from "../sync/yml"; type EditOptions = { testTargetId: string; @@ -51,6 +53,25 @@ const loadTestCase = (testCasePath: string): SyncTestCase => { } }; +const POLLING_INTERVAL = 1000; +const getTestCaseToEdit = async ( + versionId: string, + testCaseToEdit: SyncTestCase, + options: EditOptions, +) => { + return await client.GET( + "/apiKey/beta/test-targets/{testTargetId}/test-cases/{testCaseId}/versions/{versionId}", + { + params: { + path: { + versionId, + testCaseId: testCaseToEdit.id, + testTargetId: options.testTargetId, + }, + }, + }, + ); +}; export const edit = async (options: EditOptions): Promise => { const octomindRoot = await findOctomindFolder(); if (!octomindRoot) { @@ -58,17 +79,24 @@ export const edit = async (options: EditOptions): Promise => { `Could not find ${OCTOMIND_FOLDER_NAME} folder, make sure to pull before trying to edit`, ); } + + console.log({ octomindRoot }); const testCaseFilePath = await getAbsoluteFilePathInOctomindRoot({ octomindRoot, filePath: options.filePath, }); + console.log({ testCaseFilePath }); + if (!testCaseFilePath) { throw new Error( `Could not find ${options.filePath} in folder ${octomindRoot}`, ); } - const testCaseToEdit = loadTestCase(testCaseFilePath); + const testCaseToEdit = { + ...loadTestCase(testCaseFilePath), + localEditingStatus: "IN_PROGRESS", + }; const testCases = readTestCasesFromDir(octomindRoot); const testCasesById = Object.fromEntries(testCases.map((tc) => [tc.id, tc])); @@ -87,5 +115,43 @@ export const edit = async (options: EditOptions): Promise => { }, ); - console.log(response); + if (!response) { + throw new Error(`Could not edit test case with id '${testCaseToEdit.id}'`); + } + + const versionId = response?.versionIdByStableId[testCaseToEdit.id]; + + if (!versionId) { + throw new Error(`Could not edit test case with id '${testCaseToEdit.id}'`); + } + + const parsedBaseUrl = URL.parse(BASE_URL); + const localEditingUrl = `${parsedBaseUrl?.protocol}//${parsedBaseUrl?.host}/testtargets/${options.testTargetId}/testcases/${versionId}/localEdit?detailsPanelRail=steps&testTargetId=${options.testTargetId}&testCaseId=${versionId}`; + await open(localEditingUrl); + + console.log( + `Navigating to local editing url, open it manually if a browser didn't open already: ${localEditingUrl}`, + ); + + let localTestCase = await getTestCaseToEdit( + versionId, + testCaseToEdit, + options, + ); + + while (localTestCase.data?.localEditingStatus === "IN_PROGRESS") { + await sleep(POLLING_INTERVAL); + console.log("Waiting for local editing to finish..."); + + localTestCase = await getTestCaseToEdit(versionId, testCaseToEdit, options); + } + + await writeSingleTestCaseYaml(testCaseFilePath, { + ...localTestCase.data, + id: testCaseToEdit.id, + localEditingStatus: undefined, + versionId: undefined, + }); + + console.log("Edited test case successfully!"); }; From aadd2739caec5dcfb9d5273161f0b3b09847d845 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:03:07 +0100 Subject: [PATCH 06/15] working version --- openapi.yaml | 4735 +++++++++++++++++++++++++++++++ package.json | 3 +- src/tools/yamlMutations/edit.ts | 49 +- 3 files changed, 4773 insertions(+), 14 deletions(-) create mode 100644 openapi.yaml diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..e3774b0 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,4735 @@ +openapi: 3.1.0 +info: + title: Octomind external API + description: Octomind API that allows you to execute test cases, fetch reports and register private location workers by providing a URL and an ID. + version: 1.0.0 + contact: + name: API Support + url: https://octomind.dev/docs + email: support@octomind.dev +servers: + - url: https://app.octomind.dev/api + description: Main API Endpoint +tags: + - name: Test targets + description: Operations for managing test targets + - name: Execute + description: Operations for executing tests + - name: Environments + description: Operations for managing test environments + - name: Reports + description: Operations for retrieving test reports + - name: Notifications + description: Operations for retrieving notifications + - name: Private locations + description: Operations for managing private locations + - name: Test Cases + description: Operations for retrieving test cases + - name: Discoveries + description: Operations for creating test discoveries +externalDocs: + description: Find out more + url: https://octomind.dev/docs/ +paths: + /apiKey/v3/test-targets: + get: + summary: Retrieve all test targets + description: Gets a list of test targets. + operationId: getTestTargets + tags: + - Test targets + security: + - ApiKeyAuth: [] + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetsResponse' + '401': + description: Invalid or missing API key + '500': + description: Internal server error + post: + summary: Create a new test target + description: Creates a new test target. + operationId: createTestTarget + tags: + - Test targets + security: + - ApiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateTestTargetBody' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Invalid or missing API key + '500': + description: Internal server error + /apiKey/v3/test-targets/{testTargetId}: + get: + summary: Retrieve a test target + description: Gets a test target by ID. + operationId: getTestTarget + tags: + - Test targets + security: + - ApiKeyAuth: [] + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target to fetch + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Invalid or missing API key + patch: + summary: Update a test target + description: Updates a test target by ID. + operationId: updateTestTarget + tags: + - Test targets + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target to update + security: + - ApiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetUpdateRequest' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Invalid or missing API key + '500': + description: Internal server error + delete: + summary: Delete a test target + description: Deletes a test target by ID. + operationId: deleteTestTarget + tags: + - Test targets + security: + - ApiKeyAuth: [] + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target to delete + responses: + '204': + description: OK + '401': + description: Invalid or missing API key + '404': + description: Test target not found + '500': + description: Internal server error + /apiKey/v3/execute: + post: + summary: Execute tests of the given test target + description: | + This endpoint triggers a test execution by sending an test target id, an URL and optionally tags, an environment and variables. + operationId: executeTests + tags: + - Execute + security: + - ApiKeyAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetExecutionRequest' + responses: + '200': + description: Test executed successfully + content: + application/json: + schema: + $ref: '#/components/schemas/TestExecutionResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Invalid or missing API key + '500': + description: Internal server error + /apiKey/v3/test-targets/{testTargetId}/batch-generations: + post: + summary: Create a batch generation + description: Creates a batch generation for the given test target. + operationId: createBatchGeneration + tags: + - Discoveries + security: + - ApiKeyAuth: [] + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: ID of the test target + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExternalBatchGenerationBody' + responses: + '200': + description: Batch generation created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/BatchGenerationResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Invalid or missing API key + '500': + description: Internal server error + /apiKey/v3/test-targets/{testTargetId}/config: + get: + summary: Retrieve test target configuration + description: Get the test target configuration for a specific environment + operationId: getTestTargetConfig + security: + - ApiKeyAuth: [] + tags: + - Test targets + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + - name: url + in: query + required: true + schema: + type: string + format: uri + description: The execution URL for the test target + - name: outputDir + in: query + required: true + schema: + type: string + description: The directory where test output will be stored + - name: headless + in: query + required: false + schema: + type: string + description: Whether to run tests in headless mode (true/false) + - name: environmentId + in: query + required: false + schema: + type: string + format: uuid + description: Optional ID of the environment to use (defaults to the test target's default environment if not provided) + responses: + '200': + description: Test target configuration retrieved successfully + content: + text/plain: + schema: + type: string + description: The test target configuration as plain text + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Environment not found + '405': + description: Method not allowed + /apiKey/v3/test-targets/{testTargetId}/environments: + post: + summary: Create an environment + description: Create a custom environment. + operationId: createEnvironment + security: + - ApiKeyAuth: [] + tags: + - Environments + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target to which the environment belongs to + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + discoveryUrl: + type: string + format: url + testAccount: + type: object + properties: + username: + type: string + password: + type: string + otpInitializerKey: + type: string + nullable: true + nullable: true + basicAuth: + type: object + properties: + username: + type: string + password: + type: string + nullable: true + privateLocationName: + type: string + description: name of the private location + additionalHeaderFields: + type: object + additionalProperties: + type: string + nullable: true + responses: + '201': + description: environment created + content: + application/json: + schema: + $ref: '#/components/schemas/EnvironmentResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Invalid or missing API key + get: + summary: Retrieve environments + description: get a list of all defined environments. + operationId: getEnvironments + security: + - ApiKeyAuth: [] + tags: + - Environments + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target to which the test report belongs to + responses: + '200': + description: environments + content: + application/json: + schema: + $ref: '#/components/schemas/EnvironmentsResponse' + /apiKey/v3/test-targets/{testTargetId}/environments/{environmentId}: + patch: + summary: Update an environment + description: Updates an enviroment, all properties can be set separately + operationId: updateEnvironment + security: + - ApiKeyAuth: [] + tags: + - Environments + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target to which the environment belongs to + - in: path + name: environmentId + required: true + schema: + type: string + format: uuid + description: ID of the environment to update + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + name: + type: string + nullable: true + discoveryUrl: + type: string + format: url + nullable: true + testAccount: + type: object + properties: + username: + type: string + password: + type: string + otpInitializerKey: + type: string + nullable: true + nullable: true + basicAuth: + type: object + properties: + username: + type: string + password: + type: string + nullable: true + privateLocationName: + type: string + nullable: true + description: name of the private location + additionalHeaderFields: + type: object + additionalProperties: + type: string + nullable: true + responses: + '200': + description: Environment updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/EnvironmentResponse' + delete: + summary: Delete an environment + operationId: deleteEnvironment + description: deletes an enviroment. this operation is not reversable. + security: + - ApiKeyAuth: [] + tags: + - Environments + responses: + '200': + description: Environment deleted successfully + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target to which the test report belongs to + - in: path + name: environmentId + required: true + schema: + type: string + format: uuid + description: ID of the environment to update + /apiKey/v3/test-targets/{testTargetId}/test-reports/{testReportId}: + get: + summary: Retrieve information about a test report + description: Poll from within a CI-pipeline to wait for the completion of a report. + operationId: getTestReport + tags: + - Reports + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target to which the test report belongs to + - in: path + name: testReportId + required: true + schema: + type: string + format: uuid + description: ID of the test report to fetch + security: + - ApiKeyAuth: [] + responses: + '200': + description: Test Report information + content: + application/json: + schema: + $ref: '#/components/schemas/TestReport' + example: + id: 826c15af-644b-4b28-89b4-f50ff34e46b7 + testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a + createdAt: '2024-09-06T13:01:51.686Z' + updatedAt: '2024-09-06T13:05:23.412Z' + executionUrl: https://en.wikipedia.org/ + status: FAILED + context: + source: github + issueNumber: 123 + ref: refs/heads/main + sha: abc123def456 + repo: my-repo + owner: repo-owner + triggeredBy: + type: USER + userId: 3435918b-3d29-4ebd-8c68-9a540532f45a + nodeId: node-123 + testResults: + - id: 9876fedc-ba98-7654-3210-fedcba987654 + testCaseVersionId: 9876fedc-ba98-7654-3210-fedcba987654 + testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a + testReportId: 826c15af-644b-4b28-89b4-f50ff34e46b7 + createdAt: '2024-09-06T13:01:51.686Z' + updatedAt: '2024-09-06T13:03:12.345Z' + status: PASSED + errorMessage: null + traceUrl: https://storage.googleapis.com/automagically-traces/7a1b2c3d-4e5f-6g7h-8i9j-0k1l2m3n4o5p-trace.zip + - id: 3435918b-3d29-4ebd-8c68-9a540532f45a + testCaseVersionId: 5432fedc-ba98-7654-3210-fedcba543210 + testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a + testReportId: 826c15af-644b-4b28-89b4-f50ff34e46b7 + createdAt: '2024-09-06T13:01:51.686Z' + updatedAt: '2024-09-06T13:04:45.678Z' + status: FAILED + errorMessage: 'TimeoutError: locator.click: Timeout 30000ms exceeded.' + traceUrl: https://storage.googleapis.com/automagically-traces/2a3b4c5d-6e7f-8g9h-0i1j-2k3l4m5n6o7p-trace.zip + - id: 3435918b-3d29-4ebd-8c68-9a540532f45a + testCaseVersionId: 1234abcd-ef56-7890-abcd-ef1234567890 + testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a + testReportId: 826c15af-644b-4b28-89b4-f50ff34e46b7 + createdAt: '2024-09-06T13:01:51.686Z' + updatedAt: '2024-09-06T13:05:23.412Z' + status: WAITING + errorMessage: null + traceUrl: null + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Invalid or missing API key + '500': + description: Internal server error + /apiKey/v3/test-targets/{testTargetId}/test-reports: + get: + summary: Retrieve paginated information about test reports + description: Allow fetching the history of test reports for your test target. + operationId: getTestReports + tags: + - Reports + parameters: + - in: path + name: testTargetId + required: true + schema: + type: string + format: uuid + description: ID of the test target for which to fetch the history for + - in: query + name: key + required: false + schema: + type: object + properties: + createdAt: + type: string + format: date-time + description: The timestamp of the key of the next page to fetch - See [Keyset Pagination](https://use-the-index-luke.com/no-offset) + example: '2024-09-06T13:01:51.686Z' + - in: query + name: filter + required: false + schema: + type: array + items: + type: object + properties: + key: + type: string + description: The name of the property to filter for, e.g. an environmentId + example: environmentId + operator: + type: string + enum: + - EQUALS + description: How to compare the property in question, only EQUALS is supported so far. + value: + type: string + format: uuid + description: The value to compare with to find matches. + example: 3435918b-3d29-4ebd-8c68-9a540532f45a + security: + - ApiKeyAuth: [] + responses: + '200': + description: Test Reports information + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/TestReport' + key: + type: object + properties: + createdAt: + type: string + format: date-time + description: The timestamp of the key of the next page to fetch - use this in the query when fetching the next page of reports - See [Keyset Pagination](https://use-the-index-luke.com/no-offset) + example: '2024-09-06T13:01:51.686Z' + hasNextPage: + type: boolean + description: If the query in question has another page to retrieve + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Invalid or missing API key + '500': + description: Internal server error + /apiKey/v3/test-targets/{testTargetId}/notifications: + get: + summary: Retrieve notifications + description: Get a list of notifications for a specific test target. + operationId: getNotifications + security: + - ApiKeyAuth: [] + tags: + - Notifications + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + responses: + '200': + description: List of notifications + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Notification' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target not found + /apiKey/v1/private-location: + get: + security: + - ApiKeyAuth: [] + summary: Retrieve all private locations + description: gets a list of private location workers + operationId: getPrivateLocations + tags: + - Private locations + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PrivateLocationInfo' + /apiKey/v1/private-location/register: + put: + security: + - ApiKeyAuth: [] + summary: Register a private location + description: registers a private location worker + operationId: registerPrivateLocation + tags: + - Private locations + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RegisterRequest' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '404': + description: private location of that name not found + '500': + description: Internal server error + /apiKey/v1/private-location/unregister: + put: + security: + - ApiKeyAuth: [] + summary: Unregister a private location + description: Unregisters a private location worker. + operationId: unregisterPrivateLocation + tags: + - Private locations + externalDocs: + url: https://octomind.dev/docs/proxy/private-location + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UnregisterRequest' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '404': + description: private location of that name not found + '500': + description: Internal server error + /apiKey/v3/test-targets/{testTargetId}/test-cases: + get: + summary: List test cases + description: Get a list of test cases for a specific test target with optional filtering + operationId: getTestCases + security: + - ApiKeyAuth: [] + tags: + - Test Cases + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + - name: filter + in: query + required: false + schema: + type: string + description: | + JSON string containing filter criteria for test cases. The filter supports the following fields: + - testTargetId: Filter by test target ID + - description: Filter by test case description + - status: Filter by test case status (ENABLED, DISABLED, DRAFT, OUTDATED, DELETED, PROVISIONAL) + - runStatus: Filter by run status (ON, OFF) + - folderId: Filter by folder ID + - externalId: Filter by external ID + - AND: Logical AND operator for combining multiple conditions + - OR: Logical OR operator for combining multiple conditions + - NOT: Logical NOT operator for negating conditions + example: '{"status":"ENABLED","folderId":"some-folder-id","OR":[{"description":"Login Test"},{"externalId":"TEST-123"}]}' + responses: + '200': + description: List of test cases + content: + application/json: + schema: + $ref: '#/components/schemas/TestCasesResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target not found + /apiKey/v3/test-targets/{testTargetId}/test-cases/{testCaseId}: + get: + summary: Retrieve a test case + description: Get detailed information about a specific test case + operationId: getTestCase + security: + - ApiKeyAuth: [] + tags: + - Test Cases + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + - name: testCaseId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test case + responses: + '200': + description: Test case details + content: + application/json: + schema: + $ref: '#/components/schemas/TestCaseResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target or test case not found + patch: + summary: Update a test case + description: Update specific properties of a test case + operationId: patchTestCase + security: + - ApiKeyAuth: [] + tags: + - Test Cases + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + - name: testCaseId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test case to update + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + elements: + type: array + items: + $ref: '#/components/schemas/TestCaseElement' + description: + type: string + entryPointUrlPath: + type: string + nullable: true + status: + type: string + enum: + - ENABLED + - DISABLED + - DRAFT + - OUTDATED + - PROVISIONAL + runStatus: + type: string + enum: + - 'ON' + - 'OFF' + folderName: + type: string + nullable: true + interactionStatus: + type: string + enum: + - NEW + - EDITED + - APPROVED + - REJECTED + createBackendDiscoveryPrompt: + type: string + assignedTagNames: + type: array + items: + type: string + externalId: + type: string + nullable: true + responses: + '200': + description: Updated test case + content: + application/json: + schema: + type: object + properties: + id: + type: string + format: uuid + testTargetId: + type: string + format: uuid + description: + type: string + status: + type: string + enum: + - ENABLED + - DISABLED + - DRAFT + - OUTDATED + - PROVISIONAL + runStatus: + type: string + enum: + - 'ON' + - 'OFF' + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + entryPointUrlPath: + type: string + nullable: true + elements: + type: array + items: + type: object + folderId: + type: string + nullable: true + externalId: + type: string + nullable: true + tags: + type: array + items: + type: string + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test case, folder or tag not found + delete: + summary: Delete a test case + description: Delete a specific test case + operationId: deleteTestCase + security: + - ApiKeyAuth: [] + tags: + - Test Cases + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + - name: testCaseId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test case + responses: + '200': + description: Test case deleted successfully + content: + application/json: + schema: + type: object + properties: + status: + type: string + enum: + - deleted + description: Status of the deletion operation + required: + - status + '400': + description: Bad request + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/ZodResponse' + - type: object + properties: + status: + type: string + enum: + - has dependencies + description: Indicates the test case has dependencies + dependencyIds: + type: array + items: + type: string + format: uuid + description: List of test case IDs that depend on this test case + required: + - status + - dependencyIds + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test case not found + '500': + description: Internal server error + content: + application/json: + schema: + type: object + properties: + status: + type: string + enum: + - error + description: Indicates an error occurred + error: + type: string + description: Error message + required: + - status + - error + /apiKey/v3/test-targets/{testTargetId}/test-cases/{testCaseId}/elements/{elementId}: + patch: + summary: Update a test case element + description: Update a the locator line of a specific test case element + operationId: updateTestCaseElement + security: + - ApiKeyAuth: [] + tags: + - Test Cases + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + - name: testCaseId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test case + - name: elementId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test case element + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + locatorLine: + description: The locator line of the test case element + type: string + required: + - locatorLine + responses: + '200': + description: Test case element updated successfully + content: + application/json: + schema: + $ref: '#/components/schemas/TestCaseElement' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target, test case or test case element not found + '500': + description: Internal server error + /apiKey/v3/test-targets/{testTargetId}/test-cases/{testCaseId}/code: + get: + summary: Retrieve code for a test case + description: Get the code representation of a specific test case + operationId: getTestCaseCode + security: + - ApiKeyAuth: [] + tags: + - Test Cases + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + - name: testCaseId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test case + - name: executionUrl + in: query + required: true + schema: + type: string + format: url + description: URL of the app to test + - name: environmentId + in: query + required: false + schema: + type: string + format: uuid + description: Optional ID of the environment to use + responses: + '200': + description: Test case code retrieved successfully + content: + application/json: + schema: + type: object + properties: + testCode: + type: string + description: The code representation of the test case + required: + - testCode + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target, test case, or test code not found + /apiKey/beta/test-targets/{testTargetId}/pull: + get: + summary: Pull all test case from a test target to use it locally as json or yaml and work with the files directly. There is also a "opposite" endpoint to push the files back to the test target. + description: Get the pull data for a specific test target + operationId: getTestTargetPullData + security: + - ApiKeyAuth: [] + tags: + - Test targets + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + responses: + '200': + description: Test target pull data retrieved successfully + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetSyncSchema' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target not found + /apiKey/beta/test-targets/{testTargetId}/code: + post: + summary: Get TestSuite code + description: Retrieve the typescript code in a zip file for a set of yaml based test cases. This code can then be executed by playwright. + operationId: getTestTargetCode + security: + - ApiKeyAuth: [] + tags: + - Test targets + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetCodeSchema' + responses: + '200': + description: Test target code retrieved successfully + content: + application/zip: + schema: + type: string + format: binary + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target not found + /apiKey/beta/test-targets/{testTargetId}/push: + post: + summary: Push test target + description: Pushes all test cases with the specified schema to the test target. There is also a "opposite" endpoint to pull the files back to the local machine. + operationId: pushTestTarget + security: + - ApiKeyAuth: [] + tags: + - Test targets + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetSyncSchema' + responses: + '200': + description: Test target pushed successfully + content: + application/json: + schema: + type: object + required: + - success + - versionIds + properties: + success: + type: boolean + versionIds: + type: array + items: + type: string + format: uuid + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target not found + /apiKey/beta/test-targets/{testTargetId}/draft/push: + post: + summary: Push draft test target + description: Push all test cases from a local representation to a test target as a draft. + operationId: pushTestTargetDraft + security: + - ApiKeyAuth: [] + tags: + - Test targets + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TestTargetSyncSchema' + responses: + '200': + description: Test target pushed successfully + content: + application/json: + schema: + type: object + required: + - success + - versionIds + - versionIdByStableId + properties: + success: + type: boolean + versionIds: + type: array + items: + type: string + format: uuid + description: List of test case IDs that were pushed to the test target + versionIdByStableId: + type: object + additionalProperties: + type: string + format: uuid + example: + 5afe4190-5900-47d0-8cfd-bbb7dce2460e: 48c9e7d0-67e3-4806-b255-3b9f79fa9639 + description: Version IDs per stable id that were pushed to the test target + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target not found + /apiKey/beta/test-targets/{testTargetId}/test-cases/{testCaseId}/versions/{versionId}: + get: + summary: Retrieve a specific test case version + description: Get detailed information about a specific version of a test case, including its local editing status. + operationId: getTestCaseVersion + security: + - ApiKeyAuth: [] + tags: + - Test Cases + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + - name: testCaseId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test case + - name: versionId + in: path + required: true + schema: + type: string + format: uuid + description: The version ID of the test case + responses: + '200': + description: Test case version details + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/items' + - type: object + required: + - versionId + - localEditingStatus + properties: + versionId: + type: string + format: uuid + description: The version ID of this test case + localEditingStatus: + type: string + enum: + - IN_PROGRESS + - DONE + - CANCELLED + nullable: true + description: The local editing status of this test case version + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test case not found + /apiKey/v3/test-targets/{testTargetId}/discoveries: + post: + summary: Create a discovery + description: Create a new test case discovery with a given name and prompt + operationId: createDiscovery + security: + - ApiKeyAuth: [] + tags: + - Discoveries + parameters: + - name: testTargetId + in: path + required: true + schema: + type: string + format: uuid + description: The ID of the test target + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ExternalDiscoveryBody' + responses: + '200': + description: Discovery created successfully + content: + application/json: + schema: + $ref: '#/components/schemas/DiscoveryResponse' + '400': + description: Invalid request parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ZodResponse' + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target not found + '500': + description: Internal server error +components: + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: X-API-Key + schemas: + Breakpoint: + type: string + enum: + - MOBILE + - TABLET + - DESKTOP + description: The breakpoint to run the test cases against. + example: DESKTOP + default: DESKTOP + Browser: + type: string + enum: + - CHROMIUM + - FIREFOX + - SAFARI + description: The browser to run the test cases against. + example: CHROMIUM + default: CHROMIUM + TestTargetExecutionRequest: + type: object + properties: + testTargetId: + type: string + format: uuid + description: Unique identifier for the testTarget. + example: 2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc + url: + type: string + format: uri + description: The URL of the test target for this run. + example: https://example.com + context: + $ref: '#/components/schemas/ExecutionContext' + environmentName: + type: string + format: environment name + description: the environment name you want to run your test against + default: default + variablesToOverwrite: + $ref: '#/components/schemas/Variables' + tags: + type: array + items: + type: string + example: + - tag1 + - tag2 + default: [] + description: The tags to filter the test cases by. + breakpoint: + $ref: '#/components/schemas/Breakpoint' + browser: + $ref: '#/components/schemas/Browser' + testCaseVersionIds: + type: array + items: + type: string + format: uuid + required: + - testTargetId + - url + - context + TestResult: + type: object + example: + id: 333d3f57-00cf-4ce9-8d34-89093a08681a + testCaseVersionId: 9876fedc-ba98-7654-3210-fedcba987654 + testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a + testReportId: 826c15af-644b-4b28-89b4-f50ff34e46b7 + createdAt: '2024-09-06T13:01:51.686Z' + updatedAt: '2024-09-06T13:03:12.345Z' + status: PASSED + errorMessage: null + traceUrl: https://storage.googleapis.com/automagically-traces/7a1b2c3d-4e5f-6g7h-8i9j-0k1l2m3n4o5p-trace.zip + properties: + id: + type: string + format: uuid + description: Unique identifier for the test result. + example: 826c15af-644b-4b28-89b4-f50ff34e46b7 + testTargetId: + type: string + format: uuid + description: Unique identifier of the test report this result belongs to. + example: 3435918b-3d29-4ebd-8c68-9a540532f45a + testCaseVersionId: + type: string + format: uuid + description: Unique identifier of the test case version this result belongs to. + example: 5b844cf1-d597-4048-9e74-7c0f9ce3e2ee + createdAt: + type: string + format: date-time + description: The timestamp when the test result was created. + example: '2024-09-06T13:01:51.686Z' + updatedAt: + type: string + format: date-time + description: The timestamp when the test result was last updated. + example: '2024-09-06T13:01:51.686Z' + status: + type: string + enum: + - WAITING + - PASSED + - FAILED + - ERROR + description: The status of the specific test result, will be WAITING as long as the result is running, FAILED if the execution failed, PASSED if it succeeded, and ERROR if an internal error occurred. + errorMessage: + type: string + nullable: true + description: The error that has occurred during execution - only set if the status is FAILED or ERROR. + example: 'TimeoutError: locator.click: Timeout 30000ms exceeded.' + traceUrl: + type: string + nullable: true + description: Link to the playwright trace of the test execution - only set once the test result is finished (PASSED or FAILED). + example: https://storage.googleapis.com/automagically-traces/826c15af-644b-4b28-89b4-f50ff34e46b7-trace.zip + breakpoint: + $ref: '#/components/schemas/Breakpoint' + browser: + $ref: '#/components/schemas/Browser' + TestReport: + type: object + required: + - id + - testTargetId + - createdAt + - updatedAt + - executionUrl + - status + - context + properties: + id: + type: string + format: uuid + description: Unique identifier for the test report. + example: 826c15af-644b-4b28-89b4-f50ff34e46b7 + testTargetId: + type: string + format: uuid + description: The unique identifier of the test target. + example: 3435918b-3d29-4ebd-8c68-9a540532f45a + createdAt: + type: string + format: date-time + description: The timestamp when the test report was created. + example: '2024-09-06T13:01:51.686Z' + updatedAt: + type: string + format: date-time + description: The timestamp when the test report was last updated. + example: '2024-09-06T13:01:51.686Z' + executionUrl: + type: string + format: uri + description: The URL where the test execution was performed. + example: https://en.wikipedia.org/ + status: + type: string + enum: + - WAITING + - PASSED + - FAILED + description: The status of the test report, will be WAITING as long as any result is running, FAILED if the report is done but has any failed result and PASSED if all test results are done and successful + context: + $ref: '#/components/schemas/ExecutionContext' + breakpoint: + $ref: '#/components/schemas/Breakpoint' + browser: + $ref: '#/components/schemas/Browser' + testResults: + type: array + items: + $ref: '#/components/schemas/TestResult' + PrivateLocationInfo: + type: array + items: + type: object + properties: + status: + type: string + enum: + - OFFLINE + - ONLINE + address: + type: string + format: uri + example: https://example.com:3128 + name: + type: string + example: my-private-location + required: + - status + - address + - name + TestExecutionResponse: + type: object + required: + - testReportUrl + - testReport + properties: + testReportUrl: + type: string + format: uri + description: The URL where the test report can be accessed. + example: https://app.octomind.dev/testreports/826c15af-644b-4b28-89b4-f50ff34e46b7 + testReport: + $ref: '#/components/schemas/TestReport' + TestCasesResponse: + type: array + items: + $ref: '#/components/schemas/TestCaseResponse' + TestCaseResponse: + type: object + properties: + version: + type: string + enum: + - '1' + description: The version of the test case response. + id: + type: string + format: uuid + description: The ID of the test case. + testTargetId: + type: string + format: uuid + type: + type: string + nullable: true + elements: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + index: + type: integer + interaction: + type: object + nullable: true + properties: + id: + type: string + format: uuid + action: + type: string + enum: + - EXTRACT + - ENTER_TEXT + - CLICK + - SELECT_OPTION + - TYPE_TEXT + - KEY_PRESS + - HOVER + - UPLOAD + - GO_TO + - DRAG_AND_DROP + - CLOSE_PAGE + - OPEN_EMAIL + calledWith: + type: string + nullable: true + testCaseElementId: + type: string + format: uuid + assertion: + type: object + nullable: true + properties: + id: + type: string + format: uuid + expectation: + type: string + enum: + - VISIBLE + - NOT_VISIBLE + - TO_BE_CHECKED + - NOT_TO_BE_CHECKED + - TO_HAVE_VALUE + - TO_CONTAIN_TEXT + - TO_HAVE_STYLE + calledWith: + type: string + nullable: true + testCaseElementId: + type: string + format: uuid + scrollState: + type: object + nullable: true + selectors: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + index: + type: integer + selector: + type: string + selectorType: + type: string + enum: + - TEXT + - LABEL + - PLACEHOLDER + - ROLE + options: + type: object + nullable: true + properties: + name: + type: string + testCaseElementId: + type: string + format: uuid + scrollStateId: + type: string + nullable: true + testCaseId: + type: string + format: uuid + ignoreFailure: + type: boolean + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + description: + type: string + status: + type: string + enum: + - ENABLED + - DRAFT + externalId: + type: string + nullable: true + entryPointUrlPath: + type: string + nullable: true + tags: + type: array + items: + type: string + createdBy: + type: string + enum: + - EDIT + runStatus: + type: string + enum: + - 'ON' + - 'OFF' + prerequisiteId: + type: string + nullable: true + proposalRunId: + type: string + nullable: true + folderId: + type: string + nullable: true + teardownTestCaseId: + type: string + nullable: true + discovery: + type: object + nullable: true + properties: + updatedAt: + type: string + format: date-time + freePrompt: + type: string + traceUrl: + type: string + nullable: true + status: + type: string + enum: + - CREATED + - IN_PROGRESS + - ERROR + - SUCCESS + - FAILED + - INCOMPLETE + - QUEUED + - STOPPED + - OUTDATED + - PAUSED + abortCause: + type: string + nullable: true + message: + type: string + nullable: true + required: + - id + - testTargetId + SuccessResponse: + type: object + properties: + success: + type: boolean + description: Indicates whether the operation was successful. + example: true + UnregisterRequest: + type: object + properties: + name: + type: string + RegisterRequest: + type: object + properties: + name: + type: string + registrationData: + type: object + properties: + proxypass: + type: string + example: secret22 + proxyuser: + type: string + example: user + address: + type: string + description: the address of the remote endpoint. IP and port + example: 34.45.23.22:23455 + EnvironmentsResponse: + type: array + items: + $ref: '#/components/schemas/EnvironmentResponse' + EnvironmentSimpleResponse: + type: object + properties: + id: + type: string + format: uuid + type: + type: string + enum: + - DEFAULT + - ADDITIONAL + example: DEFAULT + discoveryUrl: + type: string + format: url + example: https://example.com + email: + type: string + example: user@example.com + description: The 2FA email of the environment to test email flows. + EnvironmentResponse: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + enum: + - DEFAULT + - ADDITIONAL + example: DEFAULT + testTargetId: + type: string + format: uuid + updatedAt: + type: string + format: date-time + type: + type: string + enum: + - DEFAULT + - ADDITIONAL + example: DEFAULT + discoveryUrl: + type: string + format: url + additionalHeaderFields: + type: object + additionalProperties: + type: string + nullable: true + testAccount: + type: object + properties: + username: + type: string + password: + type: string + otpInitializerKey: + type: string + nullable: true + updatedAt: + type: string + format: date-time + nullable: true + basicAuth: + type: object + properties: + username: + type: string + password: + type: string + updatedAt: + type: string + format: date-time + nullable: true + privateLocation: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + status: + type: string + type: + type: string + required: + - id + - name + - testTargetId + - type + CreateTestTargetBody: + type: object + properties: + testTarget: + type: object + properties: + app: + type: string + description: The app name or project name of the test target + discoveryUrl: + type: string + format: uri + description: The discovery URL of the test target. This is the URL that a discovery tool can use to discover the test target. + required: + - app + - discoveryUrl + TestTargetsResponse: + type: array + items: + $ref: '#/components/schemas/TestTargetResponse' + TestTargetResponse: + type: object + properties: + id: + type: string + format: uuid + app: + type: string + description: The app name or project name of the test target + tags: + type: array + items: + type: string + nullable: true + environments: + type: array + items: + $ref: '#/components/schemas/EnvironmentSimpleResponse' + description: The environments of the test target + required: + - id + - app + TestTargetUpdateRequest: + type: object + properties: + app: + type: string + nullable: true + description: The app name or project name of the test target + testIdAttribute: + type: string + nullable: true + description: The attribute name of the test ID + example: test-automation-id + testRailIntegration: + type: object + properties: + domain: + type: string + description: The domain of the TestRail instance + example: https://mycompany.testrail.io + username: + type: string + description: The username for the TestRail instance + example: user + projectId: + type: string + description: The project ID for the TestRail instance + example: '123' + apiKey: + type: string + description: The TestRail API key for the TestRail instance + example: '123123123' + nullable: true + timeoutPerStep: + type: number + format: int32 + minimum: 5000 + maximum: 30000 + description: The timeout per step in milliseconds + ZodResponse: + type: array + items: + type: object + properties: + code: + type: string + example: invalid_type + description: What error code happened while parsing the request + expected: + type: string + description: What the expected type was + example: object + received: + type: string + description: What the actual passed type was + example: string + path: + type: array + items: + type: string + description: The json path to the wrong parameter + example: key + message: + type: string + description: Human-readable message of the error that occurred while parsing. + example: Expected object, received string + ExternalBatchGenerationBody: + type: object + properties: + prompt: + type: string + description: Prompt to generate the test cases in this batch generation + imageUrls: + type: array + items: + type: string + description: Image URLs to generate the test cases in this batch generation + entryPointUrlPath: + type: string + nullable: true + description: Entry point URL path, where the batch generation will start + environmentId: + type: string + nullable: true + description: Environment ID, where the batch generation will be executed + prerequisiteId: + type: string + nullable: true + description: Prerequisite ID, which will be executed before the batch generation + baseUrl: + type: string + nullable: true + description: Base URL, where the batch generation will be executed + context: + $ref: '#/components/schemas/ExecutionContext' + BatchGenerationResponse: + type: object + properties: + batchGenerationId: + type: string + format: uuid + description: Unique identifier for the batch generation + example: 826c15af-644b-4b28-89b4-f50ff34e46b7 + Notification: + type: object + properties: + id: + type: string + format: uuid + description: Unique identifier for the event. + example: 826c15af-644b-4b28-89b4-f50ff34e46b7 + testTargetId: + type: string + format: uuid + description: The unique identifier of the test target this event belongs to. + example: 3435918b-3d29-4ebd-8c68-9a540532f45a + createdAt: + type: string + format: date-time + description: The timestamp when the event was created. + example: '2024-09-06T13:01:51.686Z' + updatedAt: + type: string + format: date-time + description: The timestamp when the event was last updated. + example: '2024-09-06T13:01:51.686Z' + payload: + type: object + description: JSON payload containing event-specific data. + example: + testCaseId: 5deeef76-f37a-418b-8101-7d69529fa561 + type: + type: string + enum: + - VALIDATION_PASSED + - VALIDATION_FAILED + - DISCOVERY_FINISHED + - PROPOSAL_SUCCESS + - PROPOSAL_FAILED + - REPORT_EXECUTION_FINISHED + description: The type of event that occurred. + example: VALIDATION_PASSED + ack: + type: string + enum: + - IN_WEB_APP + description: Optional acknowledgment status of the event. + example: IN_WEB_APP + nullable: true + required: + - id + - testTargetId + - createdAt + - updatedAt + - payload + - type + ExternalDiscoveryBody: + type: object + properties: + name: + type: string + description: Name of the discovered test case + example: Login Form Validation Test + entryPointUrlPath: + type: string + description: Entry point URL path of the discovered test case + example: /login + prerequisiteName: + type: string + description: Prerequisite test case name + example: Cookie Banner Acceptance + externalId: + type: string + description: External ID of the discovered test case + example: ext-test-001 + tagNames: + type: array + items: + type: string + description: Tags to assign to the discovered test case + example: + - authentication + - forms + - validation + prompt: + type: string + description: Prompt to generate the discovered test case + example: Test the login form with valid and invalid credentials + folderName: + type: string + description: Folder name of the discovered test case + example: Authentication Tests + type: + type: string + enum: + - LOGIN + - COOKIE_BANNER + description: Type of the discovered test case + example: LOGIN + required: + - name + - prompt + DiscoveryResponse: + type: object + required: + - discoveryId + - testCaseId + properties: + discoveryId: + type: string + format: uuid + description: The ID of the created discovery + testCaseId: + type: string + format: uuid + description: The ID of the associated test case + ExecutionContext: + oneOf: + - type: object + properties: + source: + type: string + enum: + - github + example: github + issueNumber: + type: integer + nullable: true + example: 123 + ref: + type: string + nullable: true + example: refs/heads/main + sha: + type: string + nullable: true + example: abc123def456 + repo: + type: string + example: my-repo + owner: + type: string + example: repo-owner + triggeredBy: + type: object + nullable: true + properties: + type: + type: string + enum: + - USER + example: USER + userId: + type: string + example: user123 + nodeId: + type: string + nullable: true + example: node-123 + - type: object + properties: + source: + type: string + enum: + - azureDevOps + example: azureDevOps + accessToken: + type: string + example: token123 + organization: + type: string + example: my-org + project: + type: string + example: my-project + repositoryId: + type: string + example: repo-123 + sha: + type: string + nullable: true + example: abc123def456 + ref: + type: string + nullable: true + example: refs/heads/main + pullRequestId: + type: integer + nullable: true + example: 101 + triggeredBy: + type: object + nullable: true + properties: + type: + type: string + enum: + - USER + example: USER + userId: + type: string + example: user123 + threadId: + type: string + nullable: true + example: thread-123 + - type: object + properties: + source: + type: string + enum: + - discovery + example: discovery + description: + type: string + example: A discovery test + triggeredBy: + oneOf: + - type: object + properties: + type: + type: string + enum: + - INITIAL + example: INITIAL + - type: object + properties: + type: + type: string + enum: + - USER + example: USER + userId: + type: string + example: user123 + - type: object + properties: + source: + type: string + enum: + - manual + example: manual + description: + type: string + example: A manual trigger + triggeredBy: + type: object + properties: + type: + type: string + enum: + - USER + example: USER + userId: + type: string + example: user123 + - type: object + properties: + source: + type: string + enum: + - scheduled + example: scheduled + triggeredBy: + type: object + nullable: true + properties: + type: + type: string + enum: + - USER + example: USER + userId: + type: string + example: user123 + - type: object + properties: + source: + type: string + enum: + - proposal + example: proposal + description: + type: string + example: A proposal trigger + triggeredBy: + oneOf: + - type: object + properties: + type: + type: string + enum: + - INITIAL + example: INITIAL + - type: object + properties: + type: + type: string + enum: + - USER + example: USER + userId: + type: string + example: user123 + Variables: + type: object + additionalProperties: + type: array + items: + type: string + description: The variables to overwrite exclusively for this test run. + example: + SPACE_ID: + - 64ee32b4-7365-47a6-b5b0-2903b6ad849d + TestCaseElement: + type: object + properties: + id: + type: string + format: uuid + index: + type: integer + interaction: + type: object + nullable: true + properties: + id: + type: string + format: uuid + action: + type: string + enum: + - EXTRACT + - ENTER_TEXT + - CLICK + - SELECT_OPTION + - TYPE_TEXT + - KEY_PRESS + - HOVER + - UPLOAD + - GO_TO + - DRAG_AND_DROP + - CLOSE_PAGE + - OPEN_EMAIL + calledWith: + type: string + nullable: true + testCaseElementId: + type: string + format: uuid + assertion: + type: object + nullable: true + properties: + id: + type: string + format: uuid + expectation: + type: string + enum: + - VISIBLE + - NOT_VISIBLE + - TO_BE_CHECKED + - NOT_TO_BE_CHECKED + - TO_HAVE_VALUE + - TO_CONTAIN_TEXT + - TO_HAVE_STYLE + calledWith: + type: string + nullable: true + testCaseElementId: + type: string + format: uuid + selectors: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + index: + type: integer + selector: + type: string + selectorType: + type: string + enum: + - TEXT + - LABEL + - PLACEHOLDER + - ROLE + options: + type: object + nullable: true + testCaseElementId: + type: string + format: uuid + testCaseId: + type: string + format: uuid + ignoreFailure: + type: boolean + TestTargetSyncSchema: + title: TestTargetSyncSchema + description: schema for import and export of test cases + type: object + properties: + testCases: + type: array + items: + type: object + properties: + version: + type: string + enum: + - '1' + id: + type: string + format: uuid + type: + type: string + enum: + - LOGIN + - COOKIE_BANNER + - LINK + - TEARDOWN + tagNames: + type: array + items: + type: string + excludedEnvironmentNames: + type: array + items: + type: string + runStatus: + type: string + enum: + - 'OFF' + - 'ON' + dependencyId: + type: string + format: uuid + teardownId: + type: string + format: uuid + elements: + type: array + items: + type: object + properties: + interaction: + anyOf: + - type: object + properties: + action: + type: string + enum: + - CLICK + calledWith: + type: object + properties: + button: + type: string + enum: + - right + - left + - middle + double: + type: boolean + force: + type: boolean + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - ENTER_TEXT + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - SELECT_OPTION + calledWith: + anyOf: + - anyOf: + - anyOf: + - type: string + - type: array + items: + type: string + - type: object + properties: + value: + type: string + label: + type: string + index: + type: number + additionalProperties: false + - type: array + items: + type: object + properties: + value: + type: string + label: + type: string + index: + type: number + additionalProperties: false + nullable: true + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - GO_TO + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - KEY_PRESS + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - HOVER + calledWith: + not: {} + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - UPLOAD + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - DOWNLOAD + calledWith: + anyOf: + - type: string + - {} + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - DRAG_AND_DROP + calledWith: + type: array + minItems: 2 + maxItems: 2 + prefixItems: + - type: string + - anyOf: + - type: string + - {} + items: {} + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - TYPE_TEXT + calledWith: + type: object + properties: + text: + type: string + delay: + type: number + required: + - text + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - EXTRACT + calledWith: + anyOf: + - type: object + properties: + variableName: + type: string + type: + type: string + enum: + - TEXT + required: + - variableName + - type + additionalProperties: false + - type: object + properties: + variableName: + type: string + type: + type: string + enum: + - ATTRIBUTE + attributeName: + type: string + required: + - variableName + - type + - attributeName + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - JAVASCRIPT + calledWith: + type: object + properties: + code: + type: string + execType: + type: string + enum: + - browser + - sandbox + default: sandbox + required: + - code + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - OPEN_EMAIL + calledWith: + type: object + properties: + subjectContaining: + type: string + nullable: true + subAddress: + type: string + pattern: ^[^ @]*$ + nullable: true + required: + - subjectContaining + - subAddress + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - CLOSE_PAGE + calledWith: + enum: + - 'null' + nullable: true + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - WAIT_FOR + calledWith: + anyOf: + - type: object + properties: + type: + type: string + enum: + - load + - domContentLoaded + - networkIdle + - nuxtHydration + - nuxtDelayHydration + - webComponentsHydration + - preactHydration + - qwikHydration + required: + - type + additionalProperties: false + - type: object + properties: + type: + type: string + enum: + - fixedTime + timeMilliseconds: + type: number + required: + - type + additionalProperties: false + - type: object + properties: + type: + type: string + enum: + - code + code: + type: string + required: + - type + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - SCROLL + calledWith: + type: object + properties: + x: + type: number + 'y': + type: number + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + assertion: + anyOf: + - type: object + properties: + expectation: + type: string + enum: + - VISIBLE + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - NOT_VISIBLE + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - RESPONSE_OK + calledWith: + type: string + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - DISABLED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_HAVE_VALUE + calledWith: + anyOf: + - type: string + - {} + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_BE_CHECKED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - NOT_TO_BE_CHECKED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_CONTAIN_TEXT + calledWith: + anyOf: + - type: string + - {} + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_HAVE_STYLE + calledWith: + type: array + minItems: 2 + maxItems: 2 + prefixItems: + - type: string + - anyOf: + - type: string + - {} + items: {} + required: + - expectation + - calledWith + additionalProperties: false + ignoreFailure: + type: boolean + selectors: + type: array + items: + type: object + properties: + selectorType: + type: string + enum: + - FRAME + - CSS + - TEXT + - ROLE + - ALT_TEXT + - LABEL + - TEST_ID + - TITLE + - PLACEHOLDER + - FILTER + - FIRST + - LAST + - NTH + selector: + anyOf: + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - type: string + enum: + - alert + - alertdialog + - application + - article + - banner + - blockquote + - button + - caption + - cell + - checkbox + - code + - columnheader + - combobox + - complementary + - contentinfo + - definition + - deletion + - dialog + - directory + - document + - emphasis + - feed + - figure + - form + - generic + - grid + - gridcell + - group + - heading + - img + - insertion + - link + - list + - listbox + - listitem + - log + - main + - marquee + - math + - meter + - menu + - menubar + - menuitem + - menuitemcheckbox + - menuitemradio + - navigation + - none + - note + - option + - paragraph + - presentation + - progressbar + - radio + - radiogroup + - region + - row + - rowgroup + - rowheader + - scrollbar + - search + - searchbox + - separator + - slider + - spinbutton + - status + - strong + - subscript + - superscript + - switch + - tab + - table + - tablist + - tabpanel + - term + - textbox + - time + - timer + - toolbar + - tooltip + - tree + - treegrid + - treeitem + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - type: string + - type: string + - type: string + nullable: true + options: + type: object + properties: + name: + anyOf: + - type: string + - {} + exact: + type: boolean + checked: + type: boolean + disabled: + type: boolean + expanded: + type: boolean + includeHidden: + type: boolean + level: + type: number + pressed: + type: boolean + selected: + type: boolean + hasText: + anyOf: + - type: string + - {} + hasNotText: + anyOf: + - type: string + - {} + additionalProperties: false + nullable: true + required: + - selectorType + additionalProperties: false + required: + - selectors + additionalProperties: false + description: + type: string + entryPointUrlPath: + type: string + folderName: + type: string + externalId: + type: string + prompt: + type: string + localEditingStatus: + type: string + enum: + - IN_PROGRESS + - DONE + - CANCELLED + required: + - version + - id + - runStatus + - elements + - description + - prompt + additionalProperties: false + required: + - testCases + additionalProperties: false + TestTargetCodeSchema: + title: TestTargetCodeSchema + description: schema for export of test cases as code + type: object + properties: + executionUrl: + type: string + format: uri + environmentId: + type: string + format: uuid + testCases: + type: array + items: + type: object + properties: + version: + type: string + enum: + - '1' + id: + type: string + format: uuid + type: + type: string + enum: + - LOGIN + - COOKIE_BANNER + - LINK + - TEARDOWN + tagNames: + type: array + items: + type: string + excludedEnvironmentNames: + type: array + items: + type: string + runStatus: + type: string + enum: + - 'OFF' + - 'ON' + dependencyId: + type: string + format: uuid + teardownId: + type: string + format: uuid + elements: + type: array + items: + type: object + properties: + interaction: + anyOf: + - type: object + properties: + action: + type: string + enum: + - CLICK + calledWith: + type: object + properties: + button: + type: string + enum: + - right + - left + - middle + double: + type: boolean + force: + type: boolean + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - ENTER_TEXT + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - SELECT_OPTION + calledWith: + anyOf: + - anyOf: + - anyOf: + - type: string + - type: array + items: + type: string + - type: object + properties: + value: + type: string + label: + type: string + index: + type: number + additionalProperties: false + - type: array + items: + type: object + properties: + value: + type: string + label: + type: string + index: + type: number + additionalProperties: false + nullable: true + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - GO_TO + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - KEY_PRESS + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - HOVER + calledWith: + not: {} + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - UPLOAD + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - DOWNLOAD + calledWith: + anyOf: + - type: string + - {} + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - DRAG_AND_DROP + calledWith: + type: array + minItems: 2 + maxItems: 2 + prefixItems: + - type: string + - anyOf: + - type: string + - {} + items: {} + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - TYPE_TEXT + calledWith: + type: object + properties: + text: + type: string + delay: + type: number + required: + - text + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - EXTRACT + calledWith: + anyOf: + - type: object + properties: + variableName: + type: string + type: + type: string + enum: + - TEXT + required: + - variableName + - type + additionalProperties: false + - type: object + properties: + variableName: + type: string + type: + type: string + enum: + - ATTRIBUTE + attributeName: + type: string + required: + - variableName + - type + - attributeName + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - JAVASCRIPT + calledWith: + type: object + properties: + code: + type: string + execType: + type: string + enum: + - browser + - sandbox + default: sandbox + required: + - code + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - OPEN_EMAIL + calledWith: + type: object + properties: + subjectContaining: + type: string + nullable: true + subAddress: + type: string + pattern: ^[^ @]*$ + nullable: true + required: + - subjectContaining + - subAddress + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - CLOSE_PAGE + calledWith: + enum: + - 'null' + nullable: true + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - WAIT_FOR + calledWith: + anyOf: + - type: object + properties: + type: + type: string + enum: + - load + - domContentLoaded + - networkIdle + - nuxtHydration + - nuxtDelayHydration + - webComponentsHydration + - preactHydration + - qwikHydration + required: + - type + additionalProperties: false + - type: object + properties: + type: + type: string + enum: + - fixedTime + timeMilliseconds: + type: number + required: + - type + additionalProperties: false + - type: object + properties: + type: + type: string + enum: + - code + code: + type: string + required: + - type + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - SCROLL + calledWith: + type: object + properties: + x: + type: number + 'y': + type: number + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + assertion: + anyOf: + - type: object + properties: + expectation: + type: string + enum: + - VISIBLE + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - NOT_VISIBLE + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - RESPONSE_OK + calledWith: + type: string + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - DISABLED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_HAVE_VALUE + calledWith: + anyOf: + - type: string + - {} + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_BE_CHECKED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - NOT_TO_BE_CHECKED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_CONTAIN_TEXT + calledWith: + anyOf: + - type: string + - {} + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_HAVE_STYLE + calledWith: + type: array + minItems: 2 + maxItems: 2 + prefixItems: + - type: string + - anyOf: + - type: string + - {} + items: {} + required: + - expectation + - calledWith + additionalProperties: false + ignoreFailure: + type: boolean + selectors: + type: array + items: + type: object + properties: + selectorType: + type: string + enum: + - FRAME + - CSS + - TEXT + - ROLE + - ALT_TEXT + - LABEL + - TEST_ID + - TITLE + - PLACEHOLDER + - FILTER + - FIRST + - LAST + - NTH + selector: + anyOf: + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - type: string + enum: + - alert + - alertdialog + - application + - article + - banner + - blockquote + - button + - caption + - cell + - checkbox + - code + - columnheader + - combobox + - complementary + - contentinfo + - definition + - deletion + - dialog + - directory + - document + - emphasis + - feed + - figure + - form + - generic + - grid + - gridcell + - group + - heading + - img + - insertion + - link + - list + - listbox + - listitem + - log + - main + - marquee + - math + - meter + - menu + - menubar + - menuitem + - menuitemcheckbox + - menuitemradio + - navigation + - none + - note + - option + - paragraph + - presentation + - progressbar + - radio + - radiogroup + - region + - row + - rowgroup + - rowheader + - scrollbar + - search + - searchbox + - separator + - slider + - spinbutton + - status + - strong + - subscript + - superscript + - switch + - tab + - table + - tablist + - tabpanel + - term + - textbox + - time + - timer + - toolbar + - tooltip + - tree + - treegrid + - treeitem + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - type: string + - type: string + - type: string + nullable: true + options: + type: object + properties: + name: + anyOf: + - type: string + - {} + exact: + type: boolean + checked: + type: boolean + disabled: + type: boolean + expanded: + type: boolean + includeHidden: + type: boolean + level: + type: number + pressed: + type: boolean + selected: + type: boolean + hasText: + anyOf: + - type: string + - {} + hasNotText: + anyOf: + - type: string + - {} + additionalProperties: false + nullable: true + required: + - selectorType + additionalProperties: false + required: + - selectors + additionalProperties: false + description: + type: string + entryPointUrlPath: + type: string + folderName: + type: string + externalId: + type: string + prompt: + type: string + localEditingStatus: + type: string + enum: + - IN_PROGRESS + - DONE + - CANCELLED + required: + - version + - id + - runStatus + - elements + - description + - prompt + additionalProperties: false + required: + - executionUrl + - testCases + additionalProperties: false + items: + type: object + properties: + version: + type: string + enum: + - '1' + id: + type: string + format: uuid + type: + type: string + enum: + - LOGIN + - COOKIE_BANNER + - LINK + - TEARDOWN + tagNames: + type: array + items: + type: string + excludedEnvironmentNames: + type: array + items: + type: string + runStatus: + type: string + enum: + - 'OFF' + - 'ON' + dependencyId: + type: string + format: uuid + teardownId: + type: string + format: uuid + elements: + type: array + items: + type: object + properties: + interaction: + anyOf: + - type: object + properties: + action: + type: string + enum: + - CLICK + calledWith: + type: object + properties: + button: + type: string + enum: + - right + - left + - middle + double: + type: boolean + force: + type: boolean + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - ENTER_TEXT + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - SELECT_OPTION + calledWith: + anyOf: + - anyOf: + - anyOf: + - type: string + - type: array + items: + type: string + - type: object + properties: + value: + type: string + label: + type: string + index: + type: number + additionalProperties: false + - type: array + items: + type: object + properties: + value: + type: string + label: + type: string + index: + type: number + additionalProperties: false + nullable: true + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - GO_TO + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - KEY_PRESS + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - HOVER + calledWith: + not: {} + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - UPLOAD + calledWith: + type: string + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - DOWNLOAD + calledWith: + anyOf: + - type: string + - {} + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - DRAG_AND_DROP + calledWith: + type: array + minItems: 2 + maxItems: 2 + prefixItems: + - type: string + - anyOf: + - type: string + - {} + items: {} + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - TYPE_TEXT + calledWith: + type: object + properties: + text: + type: string + delay: + type: number + required: + - text + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - EXTRACT + calledWith: + anyOf: + - type: object + properties: + variableName: + type: string + type: + type: string + enum: + - TEXT + required: + - variableName + - type + additionalProperties: false + - type: object + properties: + variableName: + type: string + type: + type: string + enum: + - ATTRIBUTE + attributeName: + type: string + required: + - variableName + - type + - attributeName + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - JAVASCRIPT + calledWith: + type: object + properties: + code: + type: string + execType: + type: string + enum: + - browser + - sandbox + default: sandbox + required: + - code + additionalProperties: false + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - OPEN_EMAIL + calledWith: + type: object + properties: + subjectContaining: + type: string + nullable: true + subAddress: + type: string + pattern: ^[^ @]*$ + nullable: true + required: + - subjectContaining + - subAddress + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - CLOSE_PAGE + calledWith: + enum: + - 'null' + nullable: true + required: + - action + - calledWith + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - WAIT_FOR + calledWith: + anyOf: + - type: object + properties: + type: + type: string + enum: + - load + - domContentLoaded + - networkIdle + - nuxtHydration + - nuxtDelayHydration + - webComponentsHydration + - preactHydration + - qwikHydration + required: + - type + additionalProperties: false + - type: object + properties: + type: + type: string + enum: + - fixedTime + timeMilliseconds: + type: number + required: + - type + additionalProperties: false + - type: object + properties: + type: + type: string + enum: + - code + code: + type: string + required: + - type + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + - type: object + properties: + action: + type: string + enum: + - SCROLL + calledWith: + type: object + properties: + x: + type: number + 'y': + type: number + additionalProperties: false + nullable: true + required: + - action + additionalProperties: false + assertion: + anyOf: + - type: object + properties: + expectation: + type: string + enum: + - VISIBLE + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - NOT_VISIBLE + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - RESPONSE_OK + calledWith: + type: string + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - DISABLED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_HAVE_VALUE + calledWith: + anyOf: + - type: string + - {} + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_BE_CHECKED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - NOT_TO_BE_CHECKED + calledWith: + not: {} + nullable: true + required: + - expectation + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_CONTAIN_TEXT + calledWith: + anyOf: + - type: string + - {} + required: + - expectation + - calledWith + additionalProperties: false + - type: object + properties: + expectation: + type: string + enum: + - TO_HAVE_STYLE + calledWith: + type: array + minItems: 2 + maxItems: 2 + prefixItems: + - type: string + - anyOf: + - type: string + - {} + items: {} + required: + - expectation + - calledWith + additionalProperties: false + ignoreFailure: + type: boolean + selectors: + type: array + items: + type: object + properties: + selectorType: + type: string + enum: + - FRAME + - CSS + - TEXT + - ROLE + - ALT_TEXT + - LABEL + - TEST_ID + - TITLE + - PLACEHOLDER + - FILTER + - FIRST + - LAST + - NTH + selector: + anyOf: + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - type: string + enum: + - alert + - alertdialog + - application + - article + - banner + - blockquote + - button + - caption + - cell + - checkbox + - code + - columnheader + - combobox + - complementary + - contentinfo + - definition + - deletion + - dialog + - directory + - document + - emphasis + - feed + - figure + - form + - generic + - grid + - gridcell + - group + - heading + - img + - insertion + - link + - list + - listbox + - listitem + - log + - main + - marquee + - math + - meter + - menu + - menubar + - menuitem + - menuitemcheckbox + - menuitemradio + - navigation + - none + - note + - option + - paragraph + - presentation + - progressbar + - radio + - radiogroup + - region + - row + - rowgroup + - rowheader + - scrollbar + - search + - searchbox + - separator + - slider + - spinbutton + - status + - strong + - subscript + - superscript + - switch + - tab + - table + - tablist + - tabpanel + - term + - textbox + - time + - timer + - toolbar + - tooltip + - tree + - treegrid + - treeitem + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - anyOf: + - type: string + - {} + - type: string + - type: string + - type: string + nullable: true + options: + type: object + properties: + name: + anyOf: + - type: string + - {} + exact: + type: boolean + checked: + type: boolean + disabled: + type: boolean + expanded: + type: boolean + includeHidden: + type: boolean + level: + type: number + pressed: + type: boolean + selected: + type: boolean + hasText: + anyOf: + - type: string + - {} + hasNotText: + anyOf: + - type: string + - {} + additionalProperties: false + nullable: true + required: + - selectorType + additionalProperties: false + required: + - selectors + additionalProperties: false + description: + type: string + entryPointUrlPath: + type: string + folderName: + type: string + externalId: + type: string + prompt: + type: string + localEditingStatus: + type: string + enum: + - IN_PROGRESS + - DONE + - CANCELLED + required: + - version + - id + - runStatus + - elements + - description + - prompt + additionalProperties: false diff --git a/package.json b/package.json index c18568a..44a26a8 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "dev:local": "pnpm apigen && OCTOMIND_CONFIG_FILE=octomind.dev.local.json OCTOMIND_API_URL=http://localhost:3000/api tsx src/index.ts", "dev:staging": "pnpm apigen && OCTOMIND_CONFIG_FILE=octomind.dev.staging.json OCTOMIND_API_URL=https://preview.octomind.dev/api tsx src/index.ts", "dev:prod": "pnpm apigen && OCTOMIND_CONFIG_FILE=octomind.dev.prod.json OCTOMIND_API_URL=https://app.octomind.dev/api tsx src/index.ts", - "apigen": "openapi-typescript https://preview.octomind.dev/openapi.yaml --output src/api.ts && orval", + "apigen": "openapi-typescript openapi.yaml --output src/api.ts && orval", "build": "pnpm apigen && npx genversion -des src/version.ts && pnpm gendoc && tsc --project tsconfig.build.json", "octomind": "pnpm apigen && tsx src/index.ts", "test": "pnpm apigen && npx genversion -des src/version.ts && vitest", @@ -41,6 +41,7 @@ "@playwright/test": "1.57.0", "@types/shell-quote": "1.7.5", "commander": "14.0.2", + "diff": "8.0.3", "open": "11.0.0", "openapi-fetch": "0.15.0", "otplib": "13.1.0", diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index 7963cbf..5c90c61 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -1,6 +1,6 @@ -import fs, { writeFileSync } from "fs"; -import path from "path"; +import fs from "fs"; +import { createTwoFilesPatch } from "diff"; import open from "open"; import yaml from "yaml"; @@ -72,6 +72,7 @@ const getTestCaseToEdit = async ( }, ); }; + export const edit = async (options: EditOptions): Promise => { const octomindRoot = await findOctomindFolder(); if (!octomindRoot) { @@ -80,12 +81,10 @@ export const edit = async (options: EditOptions): Promise => { ); } - console.log({ octomindRoot }); const testCaseFilePath = await getAbsoluteFilePathInOctomindRoot({ octomindRoot, filePath: options.filePath, }); - console.log({ testCaseFilePath }); if (!testCaseFilePath) { throw new Error( @@ -93,9 +92,10 @@ export const edit = async (options: EditOptions): Promise => { ); } + const originalTestCase = loadTestCase(testCaseFilePath); const testCaseToEdit = { - ...loadTestCase(testCaseFilePath), - localEditingStatus: "IN_PROGRESS", + ...originalTestCase, + localEditingStatus: "IN_PROGRESS" as const, }; const testCases = readTestCasesFromDir(octomindRoot); @@ -119,12 +119,10 @@ export const edit = async (options: EditOptions): Promise => { throw new Error(`Could not edit test case with id '${testCaseToEdit.id}'`); } - const versionId = response?.versionIdByStableId[testCaseToEdit.id]; - + const versionId = response.versionIdByStableId[testCaseToEdit.id]; if (!versionId) { throw new Error(`Could not edit test case with id '${testCaseToEdit.id}'`); } - const parsedBaseUrl = URL.parse(BASE_URL); const localEditingUrl = `${parsedBaseUrl?.protocol}//${parsedBaseUrl?.host}/testtargets/${options.testTargetId}/testcases/${versionId}/localEdit?detailsPanelRail=steps&testTargetId=${options.testTargetId}&testCaseId=${versionId}`; await open(localEditingUrl); @@ -139,19 +137,44 @@ export const edit = async (options: EditOptions): Promise => { options, ); - while (localTestCase.data?.localEditingStatus === "IN_PROGRESS") { + if (!localTestCase.data) { + throw new Error( + `Could not get local editing status for test case ${testCaseToEdit.id}`, + ); + } + + while (localTestCase.data.localEditingStatus === "IN_PROGRESS") { await sleep(POLLING_INTERVAL); console.log("Waiting for local editing to finish..."); localTestCase = await getTestCaseToEdit(versionId, testCaseToEdit, options); + if (!localTestCase.data) { + throw new Error( + `Could not get local editing status for test case ${testCaseToEdit.id}`, + ); + } } - await writeSingleTestCaseYaml(testCaseFilePath, { + const syncTestCaseWithoutExtraProperties: SyncTestCase & { + versionId: undefined; + } = { ...localTestCase.data, id: testCaseToEdit.id, localEditingStatus: undefined, versionId: undefined, - }); + }; - console.log("Edited test case successfully!"); + await writeSingleTestCaseYaml( + testCaseFilePath, + syncTestCaseWithoutExtraProperties, + ); + + const diff = createTwoFilesPatch( + "old.yaml", + "new.yaml", + yaml.stringify(originalTestCase), + yaml.stringify(syncTestCaseWithoutExtraProperties), + ); + console.log(`Edited test case successfully`); + console.log(diff); }; From 51c1b9c46c1e07b6dbde454f34d3345fdb93f247 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:03:35 +0100 Subject: [PATCH 07/15] throbber! --- package.json | 9 +++- src/tools/yamlMutations/edit.ts | 94 ++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 39 deletions(-) diff --git a/package.json b/package.json index 44a26a8..24bece3 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,13 @@ "description": "a command line client for octomind apis", "main": "./dist/index.js", "packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402", - "files": ["dist", "src", "README.md", "LICENSE", "package.json"], + "files": [ + "dist", + "src", + "README.md", + "LICENSE", + "package.json" + ], "engines": { "node": ">=22.0.0" }, @@ -44,6 +50,7 @@ "diff": "8.0.3", "open": "11.0.0", "openapi-fetch": "0.15.0", + "ora": "9.0.0", "otplib": "13.1.0", "shell-quote": "1.8.3", "simple-git": "3.30.0", diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index 5c90c61..b2b1d89 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -1,7 +1,8 @@ import fs from "fs"; -import { createTwoFilesPatch } from "diff"; +import { createTwoFilesPatch, parsePatch } from "diff"; import open from "open"; +import ora from "ora"; import yaml from "yaml"; import { OCTOMIND_FOLDER_NAME } from "../../constants"; @@ -54,9 +55,9 @@ const loadTestCase = (testCasePath: string): SyncTestCase => { }; const POLLING_INTERVAL = 1000; -const getTestCaseToEdit = async ( +const getTestCaseVersion = async ( versionId: string, - testCaseToEdit: SyncTestCase, + testCase: SyncTestCase, options: EditOptions, ) => { return await client.GET( @@ -65,7 +66,7 @@ const getTestCaseToEdit = async ( params: { path: { versionId, - testCaseId: testCaseToEdit.id, + testCaseId: testCase.id, testTargetId: options.testTargetId, }, }, @@ -73,6 +74,53 @@ const getTestCaseToEdit = async ( ); }; +const waitForLocalEditingToBeFinished = async ( + versionId: string, + testCaseToEdit: SyncTestCase, + options: EditOptions, +): Promise => { + let localTestCase = await getTestCaseVersion( + versionId, + testCaseToEdit, + options, + ); + + if (!localTestCase.data) { + throw new Error( + `Could not get local editing status for test case ${testCaseToEdit.id}`, + ); + } + + const throbber = ora("Waiting for local editing to finish..").start(); + while (localTestCase.data.localEditingStatus === "IN_PROGRESS") { + await sleep(POLLING_INTERVAL); + + localTestCase = await getTestCaseVersion( + versionId, + testCaseToEdit, + options, + ); + if (!localTestCase.data) { + throw new Error( + `Could not get local editing status for test case ${testCaseToEdit.id}`, + ); + } + } + + throbber.succeed(); + + const syncTestCaseWithoutExtraProperties: SyncTestCase & { + versionId: undefined; + } = { + ...localTestCase.data, + id: testCaseToEdit.id, + localEditingStatus: undefined, + versionId: undefined, + }; + + return syncTestCaseWithoutExtraProperties; +}; + export const edit = async (options: EditOptions): Promise => { const octomindRoot = await findOctomindFolder(); if (!octomindRoot) { @@ -101,7 +149,6 @@ export const edit = async (options: EditOptions): Promise => { const testCases = readTestCasesFromDir(octomindRoot); const testCasesById = Object.fromEntries(testCases.map((tc) => [tc.id, tc])); const relevantTestCases = getRelevantTestCases(testCasesById, testCaseToEdit); - checkForConsistency(relevantTestCases); const response = await draftPush( @@ -131,50 +178,21 @@ export const edit = async (options: EditOptions): Promise => { `Navigating to local editing url, open it manually if a browser didn't open already: ${localEditingUrl}`, ); - let localTestCase = await getTestCaseToEdit( + const editResult = await waitForLocalEditingToBeFinished( versionId, testCaseToEdit, options, ); - if (!localTestCase.data) { - throw new Error( - `Could not get local editing status for test case ${testCaseToEdit.id}`, - ); - } - - while (localTestCase.data.localEditingStatus === "IN_PROGRESS") { - await sleep(POLLING_INTERVAL); - console.log("Waiting for local editing to finish..."); - - localTestCase = await getTestCaseToEdit(versionId, testCaseToEdit, options); - if (!localTestCase.data) { - throw new Error( - `Could not get local editing status for test case ${testCaseToEdit.id}`, - ); - } - } - - const syncTestCaseWithoutExtraProperties: SyncTestCase & { - versionId: undefined; - } = { - ...localTestCase.data, - id: testCaseToEdit.id, - localEditingStatus: undefined, - versionId: undefined, - }; - - await writeSingleTestCaseYaml( - testCaseFilePath, - syncTestCaseWithoutExtraProperties, - ); + await writeSingleTestCaseYaml(testCaseFilePath, editResult); const diff = createTwoFilesPatch( "old.yaml", "new.yaml", yaml.stringify(originalTestCase), - yaml.stringify(syncTestCaseWithoutExtraProperties), + yaml.stringify(editResult), ); + console.log(`Edited test case successfully`); console.log(diff); }; From b3e59985ff32c8cc06b42c4c62f210edfe7ed01a Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Tue, 13 Jan 2026 19:52:04 +0100 Subject: [PATCH 08/15] add cancellation, better throbber exiting --- src/tools/yamlMutations/edit.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index b2b1d89..8525844 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -78,7 +78,7 @@ const waitForLocalEditingToBeFinished = async ( versionId: string, testCaseToEdit: SyncTestCase, options: EditOptions, -): Promise => { +): Promise => { let localTestCase = await getTestCaseVersion( versionId, testCaseToEdit, @@ -91,7 +91,7 @@ const waitForLocalEditingToBeFinished = async ( ); } - const throbber = ora("Waiting for local editing to finish..").start(); + const throbber = ora("Waiting for editing to finish in UI").start(); while (localTestCase.data.localEditingStatus === "IN_PROGRESS") { await sleep(POLLING_INTERVAL); @@ -105,9 +105,14 @@ const waitForLocalEditingToBeFinished = async ( `Could not get local editing status for test case ${testCaseToEdit.id}`, ); } + + if (localTestCase.data.localEditingStatus === "CANCELLED") { + throbber.fail("cancelled by user"); + return "cancelled"; + } } - throbber.succeed(); + throbber.succeed("Finished editing in UI"); const syncTestCaseWithoutExtraProperties: SyncTestCase & { versionId: undefined; @@ -184,6 +189,11 @@ export const edit = async (options: EditOptions): Promise => { options, ); + if (editResult === "cancelled") { + console.log("Cancelled editing test case, exiting"); + return; + } + await writeSingleTestCaseYaml(testCaseFilePath, editResult); const diff = createTwoFilesPatch( From 28ce0026f8de894c0030552b9c0e8c2d85831cf7 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 10:38:52 +0100 Subject: [PATCH 09/15] remove import --- src/tools/yamlMutations/edit.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index 8525844..042dae5 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -1,6 +1,6 @@ import fs from "fs"; -import { createTwoFilesPatch, parsePatch } from "diff"; +import { createTwoFilesPatch } from "diff"; import open from "open"; import ora from "ora"; import yaml from "yaml"; From d8814ab823fd61d28e3e18ca6b9f44b827ecfcf1 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:03:56 +0100 Subject: [PATCH 10/15] -debugging stuff --- openapi.yaml | 4735 -------------------------------------------------- package.json | 10 +- 2 files changed, 2 insertions(+), 4743 deletions(-) delete mode 100644 openapi.yaml diff --git a/openapi.yaml b/openapi.yaml deleted file mode 100644 index e3774b0..0000000 --- a/openapi.yaml +++ /dev/null @@ -1,4735 +0,0 @@ -openapi: 3.1.0 -info: - title: Octomind external API - description: Octomind API that allows you to execute test cases, fetch reports and register private location workers by providing a URL and an ID. - version: 1.0.0 - contact: - name: API Support - url: https://octomind.dev/docs - email: support@octomind.dev -servers: - - url: https://app.octomind.dev/api - description: Main API Endpoint -tags: - - name: Test targets - description: Operations for managing test targets - - name: Execute - description: Operations for executing tests - - name: Environments - description: Operations for managing test environments - - name: Reports - description: Operations for retrieving test reports - - name: Notifications - description: Operations for retrieving notifications - - name: Private locations - description: Operations for managing private locations - - name: Test Cases - description: Operations for retrieving test cases - - name: Discoveries - description: Operations for creating test discoveries -externalDocs: - description: Find out more - url: https://octomind.dev/docs/ -paths: - /apiKey/v3/test-targets: - get: - summary: Retrieve all test targets - description: Gets a list of test targets. - operationId: getTestTargets - tags: - - Test targets - security: - - ApiKeyAuth: [] - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetsResponse' - '401': - description: Invalid or missing API key - '500': - description: Internal server error - post: - summary: Create a new test target - description: Creates a new test target. - operationId: createTestTarget - tags: - - Test targets - security: - - ApiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/CreateTestTargetBody' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Invalid or missing API key - '500': - description: Internal server error - /apiKey/v3/test-targets/{testTargetId}: - get: - summary: Retrieve a test target - description: Gets a test target by ID. - operationId: getTestTarget - tags: - - Test targets - security: - - ApiKeyAuth: [] - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target to fetch - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Invalid or missing API key - patch: - summary: Update a test target - description: Updates a test target by ID. - operationId: updateTestTarget - tags: - - Test targets - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target to update - security: - - ApiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetUpdateRequest' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Invalid or missing API key - '500': - description: Internal server error - delete: - summary: Delete a test target - description: Deletes a test target by ID. - operationId: deleteTestTarget - tags: - - Test targets - security: - - ApiKeyAuth: [] - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target to delete - responses: - '204': - description: OK - '401': - description: Invalid or missing API key - '404': - description: Test target not found - '500': - description: Internal server error - /apiKey/v3/execute: - post: - summary: Execute tests of the given test target - description: | - This endpoint triggers a test execution by sending an test target id, an URL and optionally tags, an environment and variables. - operationId: executeTests - tags: - - Execute - security: - - ApiKeyAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetExecutionRequest' - responses: - '200': - description: Test executed successfully - content: - application/json: - schema: - $ref: '#/components/schemas/TestExecutionResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Invalid or missing API key - '500': - description: Internal server error - /apiKey/v3/test-targets/{testTargetId}/batch-generations: - post: - summary: Create a batch generation - description: Creates a batch generation for the given test target. - operationId: createBatchGeneration - tags: - - Discoveries - security: - - ApiKeyAuth: [] - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: ID of the test target - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ExternalBatchGenerationBody' - responses: - '200': - description: Batch generation created successfully - content: - application/json: - schema: - $ref: '#/components/schemas/BatchGenerationResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Invalid or missing API key - '500': - description: Internal server error - /apiKey/v3/test-targets/{testTargetId}/config: - get: - summary: Retrieve test target configuration - description: Get the test target configuration for a specific environment - operationId: getTestTargetConfig - security: - - ApiKeyAuth: [] - tags: - - Test targets - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - - name: url - in: query - required: true - schema: - type: string - format: uri - description: The execution URL for the test target - - name: outputDir - in: query - required: true - schema: - type: string - description: The directory where test output will be stored - - name: headless - in: query - required: false - schema: - type: string - description: Whether to run tests in headless mode (true/false) - - name: environmentId - in: query - required: false - schema: - type: string - format: uuid - description: Optional ID of the environment to use (defaults to the test target's default environment if not provided) - responses: - '200': - description: Test target configuration retrieved successfully - content: - text/plain: - schema: - type: string - description: The test target configuration as plain text - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Environment not found - '405': - description: Method not allowed - /apiKey/v3/test-targets/{testTargetId}/environments: - post: - summary: Create an environment - description: Create a custom environment. - operationId: createEnvironment - security: - - ApiKeyAuth: [] - tags: - - Environments - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target to which the environment belongs to - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - type: string - discoveryUrl: - type: string - format: url - testAccount: - type: object - properties: - username: - type: string - password: - type: string - otpInitializerKey: - type: string - nullable: true - nullable: true - basicAuth: - type: object - properties: - username: - type: string - password: - type: string - nullable: true - privateLocationName: - type: string - description: name of the private location - additionalHeaderFields: - type: object - additionalProperties: - type: string - nullable: true - responses: - '201': - description: environment created - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Invalid or missing API key - get: - summary: Retrieve environments - description: get a list of all defined environments. - operationId: getEnvironments - security: - - ApiKeyAuth: [] - tags: - - Environments - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target to which the test report belongs to - responses: - '200': - description: environments - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentsResponse' - /apiKey/v3/test-targets/{testTargetId}/environments/{environmentId}: - patch: - summary: Update an environment - description: Updates an enviroment, all properties can be set separately - operationId: updateEnvironment - security: - - ApiKeyAuth: [] - tags: - - Environments - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target to which the environment belongs to - - in: path - name: environmentId - required: true - schema: - type: string - format: uuid - description: ID of the environment to update - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - type: string - nullable: true - discoveryUrl: - type: string - format: url - nullable: true - testAccount: - type: object - properties: - username: - type: string - password: - type: string - otpInitializerKey: - type: string - nullable: true - nullable: true - basicAuth: - type: object - properties: - username: - type: string - password: - type: string - nullable: true - privateLocationName: - type: string - nullable: true - description: name of the private location - additionalHeaderFields: - type: object - additionalProperties: - type: string - nullable: true - responses: - '200': - description: Environment updated successfully - content: - application/json: - schema: - $ref: '#/components/schemas/EnvironmentResponse' - delete: - summary: Delete an environment - operationId: deleteEnvironment - description: deletes an enviroment. this operation is not reversable. - security: - - ApiKeyAuth: [] - tags: - - Environments - responses: - '200': - description: Environment deleted successfully - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target to which the test report belongs to - - in: path - name: environmentId - required: true - schema: - type: string - format: uuid - description: ID of the environment to update - /apiKey/v3/test-targets/{testTargetId}/test-reports/{testReportId}: - get: - summary: Retrieve information about a test report - description: Poll from within a CI-pipeline to wait for the completion of a report. - operationId: getTestReport - tags: - - Reports - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target to which the test report belongs to - - in: path - name: testReportId - required: true - schema: - type: string - format: uuid - description: ID of the test report to fetch - security: - - ApiKeyAuth: [] - responses: - '200': - description: Test Report information - content: - application/json: - schema: - $ref: '#/components/schemas/TestReport' - example: - id: 826c15af-644b-4b28-89b4-f50ff34e46b7 - testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a - createdAt: '2024-09-06T13:01:51.686Z' - updatedAt: '2024-09-06T13:05:23.412Z' - executionUrl: https://en.wikipedia.org/ - status: FAILED - context: - source: github - issueNumber: 123 - ref: refs/heads/main - sha: abc123def456 - repo: my-repo - owner: repo-owner - triggeredBy: - type: USER - userId: 3435918b-3d29-4ebd-8c68-9a540532f45a - nodeId: node-123 - testResults: - - id: 9876fedc-ba98-7654-3210-fedcba987654 - testCaseVersionId: 9876fedc-ba98-7654-3210-fedcba987654 - testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a - testReportId: 826c15af-644b-4b28-89b4-f50ff34e46b7 - createdAt: '2024-09-06T13:01:51.686Z' - updatedAt: '2024-09-06T13:03:12.345Z' - status: PASSED - errorMessage: null - traceUrl: https://storage.googleapis.com/automagically-traces/7a1b2c3d-4e5f-6g7h-8i9j-0k1l2m3n4o5p-trace.zip - - id: 3435918b-3d29-4ebd-8c68-9a540532f45a - testCaseVersionId: 5432fedc-ba98-7654-3210-fedcba543210 - testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a - testReportId: 826c15af-644b-4b28-89b4-f50ff34e46b7 - createdAt: '2024-09-06T13:01:51.686Z' - updatedAt: '2024-09-06T13:04:45.678Z' - status: FAILED - errorMessage: 'TimeoutError: locator.click: Timeout 30000ms exceeded.' - traceUrl: https://storage.googleapis.com/automagically-traces/2a3b4c5d-6e7f-8g9h-0i1j-2k3l4m5n6o7p-trace.zip - - id: 3435918b-3d29-4ebd-8c68-9a540532f45a - testCaseVersionId: 1234abcd-ef56-7890-abcd-ef1234567890 - testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a - testReportId: 826c15af-644b-4b28-89b4-f50ff34e46b7 - createdAt: '2024-09-06T13:01:51.686Z' - updatedAt: '2024-09-06T13:05:23.412Z' - status: WAITING - errorMessage: null - traceUrl: null - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Invalid or missing API key - '500': - description: Internal server error - /apiKey/v3/test-targets/{testTargetId}/test-reports: - get: - summary: Retrieve paginated information about test reports - description: Allow fetching the history of test reports for your test target. - operationId: getTestReports - tags: - - Reports - parameters: - - in: path - name: testTargetId - required: true - schema: - type: string - format: uuid - description: ID of the test target for which to fetch the history for - - in: query - name: key - required: false - schema: - type: object - properties: - createdAt: - type: string - format: date-time - description: The timestamp of the key of the next page to fetch - See [Keyset Pagination](https://use-the-index-luke.com/no-offset) - example: '2024-09-06T13:01:51.686Z' - - in: query - name: filter - required: false - schema: - type: array - items: - type: object - properties: - key: - type: string - description: The name of the property to filter for, e.g. an environmentId - example: environmentId - operator: - type: string - enum: - - EQUALS - description: How to compare the property in question, only EQUALS is supported so far. - value: - type: string - format: uuid - description: The value to compare with to find matches. - example: 3435918b-3d29-4ebd-8c68-9a540532f45a - security: - - ApiKeyAuth: [] - responses: - '200': - description: Test Reports information - content: - application/json: - schema: - type: object - properties: - data: - type: array - items: - $ref: '#/components/schemas/TestReport' - key: - type: object - properties: - createdAt: - type: string - format: date-time - description: The timestamp of the key of the next page to fetch - use this in the query when fetching the next page of reports - See [Keyset Pagination](https://use-the-index-luke.com/no-offset) - example: '2024-09-06T13:01:51.686Z' - hasNextPage: - type: boolean - description: If the query in question has another page to retrieve - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Invalid or missing API key - '500': - description: Internal server error - /apiKey/v3/test-targets/{testTargetId}/notifications: - get: - summary: Retrieve notifications - description: Get a list of notifications for a specific test target. - operationId: getNotifications - security: - - ApiKeyAuth: [] - tags: - - Notifications - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - responses: - '200': - description: List of notifications - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Notification' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target not found - /apiKey/v1/private-location: - get: - security: - - ApiKeyAuth: [] - summary: Retrieve all private locations - description: gets a list of private location workers - operationId: getPrivateLocations - tags: - - Private locations - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/PrivateLocationInfo' - /apiKey/v1/private-location/register: - put: - security: - - ApiKeyAuth: [] - summary: Register a private location - description: registers a private location worker - operationId: registerPrivateLocation - tags: - - Private locations - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/RegisterRequest' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/SuccessResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '404': - description: private location of that name not found - '500': - description: Internal server error - /apiKey/v1/private-location/unregister: - put: - security: - - ApiKeyAuth: [] - summary: Unregister a private location - description: Unregisters a private location worker. - operationId: unregisterPrivateLocation - tags: - - Private locations - externalDocs: - url: https://octomind.dev/docs/proxy/private-location - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UnregisterRequest' - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/SuccessResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '404': - description: private location of that name not found - '500': - description: Internal server error - /apiKey/v3/test-targets/{testTargetId}/test-cases: - get: - summary: List test cases - description: Get a list of test cases for a specific test target with optional filtering - operationId: getTestCases - security: - - ApiKeyAuth: [] - tags: - - Test Cases - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - - name: filter - in: query - required: false - schema: - type: string - description: | - JSON string containing filter criteria for test cases. The filter supports the following fields: - - testTargetId: Filter by test target ID - - description: Filter by test case description - - status: Filter by test case status (ENABLED, DISABLED, DRAFT, OUTDATED, DELETED, PROVISIONAL) - - runStatus: Filter by run status (ON, OFF) - - folderId: Filter by folder ID - - externalId: Filter by external ID - - AND: Logical AND operator for combining multiple conditions - - OR: Logical OR operator for combining multiple conditions - - NOT: Logical NOT operator for negating conditions - example: '{"status":"ENABLED","folderId":"some-folder-id","OR":[{"description":"Login Test"},{"externalId":"TEST-123"}]}' - responses: - '200': - description: List of test cases - content: - application/json: - schema: - $ref: '#/components/schemas/TestCasesResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target not found - /apiKey/v3/test-targets/{testTargetId}/test-cases/{testCaseId}: - get: - summary: Retrieve a test case - description: Get detailed information about a specific test case - operationId: getTestCase - security: - - ApiKeyAuth: [] - tags: - - Test Cases - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - - name: testCaseId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test case - responses: - '200': - description: Test case details - content: - application/json: - schema: - $ref: '#/components/schemas/TestCaseResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target or test case not found - patch: - summary: Update a test case - description: Update specific properties of a test case - operationId: patchTestCase - security: - - ApiKeyAuth: [] - tags: - - Test Cases - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - - name: testCaseId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test case to update - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - elements: - type: array - items: - $ref: '#/components/schemas/TestCaseElement' - description: - type: string - entryPointUrlPath: - type: string - nullable: true - status: - type: string - enum: - - ENABLED - - DISABLED - - DRAFT - - OUTDATED - - PROVISIONAL - runStatus: - type: string - enum: - - 'ON' - - 'OFF' - folderName: - type: string - nullable: true - interactionStatus: - type: string - enum: - - NEW - - EDITED - - APPROVED - - REJECTED - createBackendDiscoveryPrompt: - type: string - assignedTagNames: - type: array - items: - type: string - externalId: - type: string - nullable: true - responses: - '200': - description: Updated test case - content: - application/json: - schema: - type: object - properties: - id: - type: string - format: uuid - testTargetId: - type: string - format: uuid - description: - type: string - status: - type: string - enum: - - ENABLED - - DISABLED - - DRAFT - - OUTDATED - - PROVISIONAL - runStatus: - type: string - enum: - - 'ON' - - 'OFF' - createdAt: - type: string - format: date-time - updatedAt: - type: string - format: date-time - entryPointUrlPath: - type: string - nullable: true - elements: - type: array - items: - type: object - folderId: - type: string - nullable: true - externalId: - type: string - nullable: true - tags: - type: array - items: - type: string - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test case, folder or tag not found - delete: - summary: Delete a test case - description: Delete a specific test case - operationId: deleteTestCase - security: - - ApiKeyAuth: [] - tags: - - Test Cases - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - - name: testCaseId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test case - responses: - '200': - description: Test case deleted successfully - content: - application/json: - schema: - type: object - properties: - status: - type: string - enum: - - deleted - description: Status of the deletion operation - required: - - status - '400': - description: Bad request - content: - application/json: - schema: - oneOf: - - $ref: '#/components/schemas/ZodResponse' - - type: object - properties: - status: - type: string - enum: - - has dependencies - description: Indicates the test case has dependencies - dependencyIds: - type: array - items: - type: string - format: uuid - description: List of test case IDs that depend on this test case - required: - - status - - dependencyIds - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test case not found - '500': - description: Internal server error - content: - application/json: - schema: - type: object - properties: - status: - type: string - enum: - - error - description: Indicates an error occurred - error: - type: string - description: Error message - required: - - status - - error - /apiKey/v3/test-targets/{testTargetId}/test-cases/{testCaseId}/elements/{elementId}: - patch: - summary: Update a test case element - description: Update a the locator line of a specific test case element - operationId: updateTestCaseElement - security: - - ApiKeyAuth: [] - tags: - - Test Cases - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - - name: testCaseId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test case - - name: elementId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test case element - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - locatorLine: - description: The locator line of the test case element - type: string - required: - - locatorLine - responses: - '200': - description: Test case element updated successfully - content: - application/json: - schema: - $ref: '#/components/schemas/TestCaseElement' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target, test case or test case element not found - '500': - description: Internal server error - /apiKey/v3/test-targets/{testTargetId}/test-cases/{testCaseId}/code: - get: - summary: Retrieve code for a test case - description: Get the code representation of a specific test case - operationId: getTestCaseCode - security: - - ApiKeyAuth: [] - tags: - - Test Cases - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - - name: testCaseId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test case - - name: executionUrl - in: query - required: true - schema: - type: string - format: url - description: URL of the app to test - - name: environmentId - in: query - required: false - schema: - type: string - format: uuid - description: Optional ID of the environment to use - responses: - '200': - description: Test case code retrieved successfully - content: - application/json: - schema: - type: object - properties: - testCode: - type: string - description: The code representation of the test case - required: - - testCode - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target, test case, or test code not found - /apiKey/beta/test-targets/{testTargetId}/pull: - get: - summary: Pull all test case from a test target to use it locally as json or yaml and work with the files directly. There is also a "opposite" endpoint to push the files back to the test target. - description: Get the pull data for a specific test target - operationId: getTestTargetPullData - security: - - ApiKeyAuth: [] - tags: - - Test targets - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - responses: - '200': - description: Test target pull data retrieved successfully - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetSyncSchema' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target not found - /apiKey/beta/test-targets/{testTargetId}/code: - post: - summary: Get TestSuite code - description: Retrieve the typescript code in a zip file for a set of yaml based test cases. This code can then be executed by playwright. - operationId: getTestTargetCode - security: - - ApiKeyAuth: [] - tags: - - Test targets - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetCodeSchema' - responses: - '200': - description: Test target code retrieved successfully - content: - application/zip: - schema: - type: string - format: binary - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target not found - /apiKey/beta/test-targets/{testTargetId}/push: - post: - summary: Push test target - description: Pushes all test cases with the specified schema to the test target. There is also a "opposite" endpoint to pull the files back to the local machine. - operationId: pushTestTarget - security: - - ApiKeyAuth: [] - tags: - - Test targets - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetSyncSchema' - responses: - '200': - description: Test target pushed successfully - content: - application/json: - schema: - type: object - required: - - success - - versionIds - properties: - success: - type: boolean - versionIds: - type: array - items: - type: string - format: uuid - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target not found - /apiKey/beta/test-targets/{testTargetId}/draft/push: - post: - summary: Push draft test target - description: Push all test cases from a local representation to a test target as a draft. - operationId: pushTestTargetDraft - security: - - ApiKeyAuth: [] - tags: - - Test targets - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TestTargetSyncSchema' - responses: - '200': - description: Test target pushed successfully - content: - application/json: - schema: - type: object - required: - - success - - versionIds - - versionIdByStableId - properties: - success: - type: boolean - versionIds: - type: array - items: - type: string - format: uuid - description: List of test case IDs that were pushed to the test target - versionIdByStableId: - type: object - additionalProperties: - type: string - format: uuid - example: - 5afe4190-5900-47d0-8cfd-bbb7dce2460e: 48c9e7d0-67e3-4806-b255-3b9f79fa9639 - description: Version IDs per stable id that were pushed to the test target - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target not found - /apiKey/beta/test-targets/{testTargetId}/test-cases/{testCaseId}/versions/{versionId}: - get: - summary: Retrieve a specific test case version - description: Get detailed information about a specific version of a test case, including its local editing status. - operationId: getTestCaseVersion - security: - - ApiKeyAuth: [] - tags: - - Test Cases - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - - name: testCaseId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test case - - name: versionId - in: path - required: true - schema: - type: string - format: uuid - description: The version ID of the test case - responses: - '200': - description: Test case version details - content: - application/json: - schema: - allOf: - - $ref: '#/components/schemas/items' - - type: object - required: - - versionId - - localEditingStatus - properties: - versionId: - type: string - format: uuid - description: The version ID of this test case - localEditingStatus: - type: string - enum: - - IN_PROGRESS - - DONE - - CANCELLED - nullable: true - description: The local editing status of this test case version - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test case not found - /apiKey/v3/test-targets/{testTargetId}/discoveries: - post: - summary: Create a discovery - description: Create a new test case discovery with a given name and prompt - operationId: createDiscovery - security: - - ApiKeyAuth: [] - tags: - - Discoveries - parameters: - - name: testTargetId - in: path - required: true - schema: - type: string - format: uuid - description: The ID of the test target - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ExternalDiscoveryBody' - responses: - '200': - description: Discovery created successfully - content: - application/json: - schema: - $ref: '#/components/schemas/DiscoveryResponse' - '400': - description: Invalid request parameters - content: - application/json: - schema: - $ref: '#/components/schemas/ZodResponse' - '401': - description: Unauthorized - Invalid or missing API key - '404': - description: Test target not found - '500': - description: Internal server error -components: - securitySchemes: - ApiKeyAuth: - type: apiKey - in: header - name: X-API-Key - schemas: - Breakpoint: - type: string - enum: - - MOBILE - - TABLET - - DESKTOP - description: The breakpoint to run the test cases against. - example: DESKTOP - default: DESKTOP - Browser: - type: string - enum: - - CHROMIUM - - FIREFOX - - SAFARI - description: The browser to run the test cases against. - example: CHROMIUM - default: CHROMIUM - TestTargetExecutionRequest: - type: object - properties: - testTargetId: - type: string - format: uuid - description: Unique identifier for the testTarget. - example: 2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc - url: - type: string - format: uri - description: The URL of the test target for this run. - example: https://example.com - context: - $ref: '#/components/schemas/ExecutionContext' - environmentName: - type: string - format: environment name - description: the environment name you want to run your test against - default: default - variablesToOverwrite: - $ref: '#/components/schemas/Variables' - tags: - type: array - items: - type: string - example: - - tag1 - - tag2 - default: [] - description: The tags to filter the test cases by. - breakpoint: - $ref: '#/components/schemas/Breakpoint' - browser: - $ref: '#/components/schemas/Browser' - testCaseVersionIds: - type: array - items: - type: string - format: uuid - required: - - testTargetId - - url - - context - TestResult: - type: object - example: - id: 333d3f57-00cf-4ce9-8d34-89093a08681a - testCaseVersionId: 9876fedc-ba98-7654-3210-fedcba987654 - testTargetId: 3435918b-3d29-4ebd-8c68-9a540532f45a - testReportId: 826c15af-644b-4b28-89b4-f50ff34e46b7 - createdAt: '2024-09-06T13:01:51.686Z' - updatedAt: '2024-09-06T13:03:12.345Z' - status: PASSED - errorMessage: null - traceUrl: https://storage.googleapis.com/automagically-traces/7a1b2c3d-4e5f-6g7h-8i9j-0k1l2m3n4o5p-trace.zip - properties: - id: - type: string - format: uuid - description: Unique identifier for the test result. - example: 826c15af-644b-4b28-89b4-f50ff34e46b7 - testTargetId: - type: string - format: uuid - description: Unique identifier of the test report this result belongs to. - example: 3435918b-3d29-4ebd-8c68-9a540532f45a - testCaseVersionId: - type: string - format: uuid - description: Unique identifier of the test case version this result belongs to. - example: 5b844cf1-d597-4048-9e74-7c0f9ce3e2ee - createdAt: - type: string - format: date-time - description: The timestamp when the test result was created. - example: '2024-09-06T13:01:51.686Z' - updatedAt: - type: string - format: date-time - description: The timestamp when the test result was last updated. - example: '2024-09-06T13:01:51.686Z' - status: - type: string - enum: - - WAITING - - PASSED - - FAILED - - ERROR - description: The status of the specific test result, will be WAITING as long as the result is running, FAILED if the execution failed, PASSED if it succeeded, and ERROR if an internal error occurred. - errorMessage: - type: string - nullable: true - description: The error that has occurred during execution - only set if the status is FAILED or ERROR. - example: 'TimeoutError: locator.click: Timeout 30000ms exceeded.' - traceUrl: - type: string - nullable: true - description: Link to the playwright trace of the test execution - only set once the test result is finished (PASSED or FAILED). - example: https://storage.googleapis.com/automagically-traces/826c15af-644b-4b28-89b4-f50ff34e46b7-trace.zip - breakpoint: - $ref: '#/components/schemas/Breakpoint' - browser: - $ref: '#/components/schemas/Browser' - TestReport: - type: object - required: - - id - - testTargetId - - createdAt - - updatedAt - - executionUrl - - status - - context - properties: - id: - type: string - format: uuid - description: Unique identifier for the test report. - example: 826c15af-644b-4b28-89b4-f50ff34e46b7 - testTargetId: - type: string - format: uuid - description: The unique identifier of the test target. - example: 3435918b-3d29-4ebd-8c68-9a540532f45a - createdAt: - type: string - format: date-time - description: The timestamp when the test report was created. - example: '2024-09-06T13:01:51.686Z' - updatedAt: - type: string - format: date-time - description: The timestamp when the test report was last updated. - example: '2024-09-06T13:01:51.686Z' - executionUrl: - type: string - format: uri - description: The URL where the test execution was performed. - example: https://en.wikipedia.org/ - status: - type: string - enum: - - WAITING - - PASSED - - FAILED - description: The status of the test report, will be WAITING as long as any result is running, FAILED if the report is done but has any failed result and PASSED if all test results are done and successful - context: - $ref: '#/components/schemas/ExecutionContext' - breakpoint: - $ref: '#/components/schemas/Breakpoint' - browser: - $ref: '#/components/schemas/Browser' - testResults: - type: array - items: - $ref: '#/components/schemas/TestResult' - PrivateLocationInfo: - type: array - items: - type: object - properties: - status: - type: string - enum: - - OFFLINE - - ONLINE - address: - type: string - format: uri - example: https://example.com:3128 - name: - type: string - example: my-private-location - required: - - status - - address - - name - TestExecutionResponse: - type: object - required: - - testReportUrl - - testReport - properties: - testReportUrl: - type: string - format: uri - description: The URL where the test report can be accessed. - example: https://app.octomind.dev/testreports/826c15af-644b-4b28-89b4-f50ff34e46b7 - testReport: - $ref: '#/components/schemas/TestReport' - TestCasesResponse: - type: array - items: - $ref: '#/components/schemas/TestCaseResponse' - TestCaseResponse: - type: object - properties: - version: - type: string - enum: - - '1' - description: The version of the test case response. - id: - type: string - format: uuid - description: The ID of the test case. - testTargetId: - type: string - format: uuid - type: - type: string - nullable: true - elements: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - index: - type: integer - interaction: - type: object - nullable: true - properties: - id: - type: string - format: uuid - action: - type: string - enum: - - EXTRACT - - ENTER_TEXT - - CLICK - - SELECT_OPTION - - TYPE_TEXT - - KEY_PRESS - - HOVER - - UPLOAD - - GO_TO - - DRAG_AND_DROP - - CLOSE_PAGE - - OPEN_EMAIL - calledWith: - type: string - nullable: true - testCaseElementId: - type: string - format: uuid - assertion: - type: object - nullable: true - properties: - id: - type: string - format: uuid - expectation: - type: string - enum: - - VISIBLE - - NOT_VISIBLE - - TO_BE_CHECKED - - NOT_TO_BE_CHECKED - - TO_HAVE_VALUE - - TO_CONTAIN_TEXT - - TO_HAVE_STYLE - calledWith: - type: string - nullable: true - testCaseElementId: - type: string - format: uuid - scrollState: - type: object - nullable: true - selectors: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - index: - type: integer - selector: - type: string - selectorType: - type: string - enum: - - TEXT - - LABEL - - PLACEHOLDER - - ROLE - options: - type: object - nullable: true - properties: - name: - type: string - testCaseElementId: - type: string - format: uuid - scrollStateId: - type: string - nullable: true - testCaseId: - type: string - format: uuid - ignoreFailure: - type: boolean - createdAt: - type: string - format: date-time - updatedAt: - type: string - format: date-time - description: - type: string - status: - type: string - enum: - - ENABLED - - DRAFT - externalId: - type: string - nullable: true - entryPointUrlPath: - type: string - nullable: true - tags: - type: array - items: - type: string - createdBy: - type: string - enum: - - EDIT - runStatus: - type: string - enum: - - 'ON' - - 'OFF' - prerequisiteId: - type: string - nullable: true - proposalRunId: - type: string - nullable: true - folderId: - type: string - nullable: true - teardownTestCaseId: - type: string - nullable: true - discovery: - type: object - nullable: true - properties: - updatedAt: - type: string - format: date-time - freePrompt: - type: string - traceUrl: - type: string - nullable: true - status: - type: string - enum: - - CREATED - - IN_PROGRESS - - ERROR - - SUCCESS - - FAILED - - INCOMPLETE - - QUEUED - - STOPPED - - OUTDATED - - PAUSED - abortCause: - type: string - nullable: true - message: - type: string - nullable: true - required: - - id - - testTargetId - SuccessResponse: - type: object - properties: - success: - type: boolean - description: Indicates whether the operation was successful. - example: true - UnregisterRequest: - type: object - properties: - name: - type: string - RegisterRequest: - type: object - properties: - name: - type: string - registrationData: - type: object - properties: - proxypass: - type: string - example: secret22 - proxyuser: - type: string - example: user - address: - type: string - description: the address of the remote endpoint. IP and port - example: 34.45.23.22:23455 - EnvironmentsResponse: - type: array - items: - $ref: '#/components/schemas/EnvironmentResponse' - EnvironmentSimpleResponse: - type: object - properties: - id: - type: string - format: uuid - type: - type: string - enum: - - DEFAULT - - ADDITIONAL - example: DEFAULT - discoveryUrl: - type: string - format: url - example: https://example.com - email: - type: string - example: user@example.com - description: The 2FA email of the environment to test email flows. - EnvironmentResponse: - type: object - properties: - id: - type: string - format: uuid - name: - type: string - enum: - - DEFAULT - - ADDITIONAL - example: DEFAULT - testTargetId: - type: string - format: uuid - updatedAt: - type: string - format: date-time - type: - type: string - enum: - - DEFAULT - - ADDITIONAL - example: DEFAULT - discoveryUrl: - type: string - format: url - additionalHeaderFields: - type: object - additionalProperties: - type: string - nullable: true - testAccount: - type: object - properties: - username: - type: string - password: - type: string - otpInitializerKey: - type: string - nullable: true - updatedAt: - type: string - format: date-time - nullable: true - basicAuth: - type: object - properties: - username: - type: string - password: - type: string - updatedAt: - type: string - format: date-time - nullable: true - privateLocation: - type: object - properties: - id: - type: string - format: uuid - name: - type: string - status: - type: string - type: - type: string - required: - - id - - name - - testTargetId - - type - CreateTestTargetBody: - type: object - properties: - testTarget: - type: object - properties: - app: - type: string - description: The app name or project name of the test target - discoveryUrl: - type: string - format: uri - description: The discovery URL of the test target. This is the URL that a discovery tool can use to discover the test target. - required: - - app - - discoveryUrl - TestTargetsResponse: - type: array - items: - $ref: '#/components/schemas/TestTargetResponse' - TestTargetResponse: - type: object - properties: - id: - type: string - format: uuid - app: - type: string - description: The app name or project name of the test target - tags: - type: array - items: - type: string - nullable: true - environments: - type: array - items: - $ref: '#/components/schemas/EnvironmentSimpleResponse' - description: The environments of the test target - required: - - id - - app - TestTargetUpdateRequest: - type: object - properties: - app: - type: string - nullable: true - description: The app name or project name of the test target - testIdAttribute: - type: string - nullable: true - description: The attribute name of the test ID - example: test-automation-id - testRailIntegration: - type: object - properties: - domain: - type: string - description: The domain of the TestRail instance - example: https://mycompany.testrail.io - username: - type: string - description: The username for the TestRail instance - example: user - projectId: - type: string - description: The project ID for the TestRail instance - example: '123' - apiKey: - type: string - description: The TestRail API key for the TestRail instance - example: '123123123' - nullable: true - timeoutPerStep: - type: number - format: int32 - minimum: 5000 - maximum: 30000 - description: The timeout per step in milliseconds - ZodResponse: - type: array - items: - type: object - properties: - code: - type: string - example: invalid_type - description: What error code happened while parsing the request - expected: - type: string - description: What the expected type was - example: object - received: - type: string - description: What the actual passed type was - example: string - path: - type: array - items: - type: string - description: The json path to the wrong parameter - example: key - message: - type: string - description: Human-readable message of the error that occurred while parsing. - example: Expected object, received string - ExternalBatchGenerationBody: - type: object - properties: - prompt: - type: string - description: Prompt to generate the test cases in this batch generation - imageUrls: - type: array - items: - type: string - description: Image URLs to generate the test cases in this batch generation - entryPointUrlPath: - type: string - nullable: true - description: Entry point URL path, where the batch generation will start - environmentId: - type: string - nullable: true - description: Environment ID, where the batch generation will be executed - prerequisiteId: - type: string - nullable: true - description: Prerequisite ID, which will be executed before the batch generation - baseUrl: - type: string - nullable: true - description: Base URL, where the batch generation will be executed - context: - $ref: '#/components/schemas/ExecutionContext' - BatchGenerationResponse: - type: object - properties: - batchGenerationId: - type: string - format: uuid - description: Unique identifier for the batch generation - example: 826c15af-644b-4b28-89b4-f50ff34e46b7 - Notification: - type: object - properties: - id: - type: string - format: uuid - description: Unique identifier for the event. - example: 826c15af-644b-4b28-89b4-f50ff34e46b7 - testTargetId: - type: string - format: uuid - description: The unique identifier of the test target this event belongs to. - example: 3435918b-3d29-4ebd-8c68-9a540532f45a - createdAt: - type: string - format: date-time - description: The timestamp when the event was created. - example: '2024-09-06T13:01:51.686Z' - updatedAt: - type: string - format: date-time - description: The timestamp when the event was last updated. - example: '2024-09-06T13:01:51.686Z' - payload: - type: object - description: JSON payload containing event-specific data. - example: - testCaseId: 5deeef76-f37a-418b-8101-7d69529fa561 - type: - type: string - enum: - - VALIDATION_PASSED - - VALIDATION_FAILED - - DISCOVERY_FINISHED - - PROPOSAL_SUCCESS - - PROPOSAL_FAILED - - REPORT_EXECUTION_FINISHED - description: The type of event that occurred. - example: VALIDATION_PASSED - ack: - type: string - enum: - - IN_WEB_APP - description: Optional acknowledgment status of the event. - example: IN_WEB_APP - nullable: true - required: - - id - - testTargetId - - createdAt - - updatedAt - - payload - - type - ExternalDiscoveryBody: - type: object - properties: - name: - type: string - description: Name of the discovered test case - example: Login Form Validation Test - entryPointUrlPath: - type: string - description: Entry point URL path of the discovered test case - example: /login - prerequisiteName: - type: string - description: Prerequisite test case name - example: Cookie Banner Acceptance - externalId: - type: string - description: External ID of the discovered test case - example: ext-test-001 - tagNames: - type: array - items: - type: string - description: Tags to assign to the discovered test case - example: - - authentication - - forms - - validation - prompt: - type: string - description: Prompt to generate the discovered test case - example: Test the login form with valid and invalid credentials - folderName: - type: string - description: Folder name of the discovered test case - example: Authentication Tests - type: - type: string - enum: - - LOGIN - - COOKIE_BANNER - description: Type of the discovered test case - example: LOGIN - required: - - name - - prompt - DiscoveryResponse: - type: object - required: - - discoveryId - - testCaseId - properties: - discoveryId: - type: string - format: uuid - description: The ID of the created discovery - testCaseId: - type: string - format: uuid - description: The ID of the associated test case - ExecutionContext: - oneOf: - - type: object - properties: - source: - type: string - enum: - - github - example: github - issueNumber: - type: integer - nullable: true - example: 123 - ref: - type: string - nullable: true - example: refs/heads/main - sha: - type: string - nullable: true - example: abc123def456 - repo: - type: string - example: my-repo - owner: - type: string - example: repo-owner - triggeredBy: - type: object - nullable: true - properties: - type: - type: string - enum: - - USER - example: USER - userId: - type: string - example: user123 - nodeId: - type: string - nullable: true - example: node-123 - - type: object - properties: - source: - type: string - enum: - - azureDevOps - example: azureDevOps - accessToken: - type: string - example: token123 - organization: - type: string - example: my-org - project: - type: string - example: my-project - repositoryId: - type: string - example: repo-123 - sha: - type: string - nullable: true - example: abc123def456 - ref: - type: string - nullable: true - example: refs/heads/main - pullRequestId: - type: integer - nullable: true - example: 101 - triggeredBy: - type: object - nullable: true - properties: - type: - type: string - enum: - - USER - example: USER - userId: - type: string - example: user123 - threadId: - type: string - nullable: true - example: thread-123 - - type: object - properties: - source: - type: string - enum: - - discovery - example: discovery - description: - type: string - example: A discovery test - triggeredBy: - oneOf: - - type: object - properties: - type: - type: string - enum: - - INITIAL - example: INITIAL - - type: object - properties: - type: - type: string - enum: - - USER - example: USER - userId: - type: string - example: user123 - - type: object - properties: - source: - type: string - enum: - - manual - example: manual - description: - type: string - example: A manual trigger - triggeredBy: - type: object - properties: - type: - type: string - enum: - - USER - example: USER - userId: - type: string - example: user123 - - type: object - properties: - source: - type: string - enum: - - scheduled - example: scheduled - triggeredBy: - type: object - nullable: true - properties: - type: - type: string - enum: - - USER - example: USER - userId: - type: string - example: user123 - - type: object - properties: - source: - type: string - enum: - - proposal - example: proposal - description: - type: string - example: A proposal trigger - triggeredBy: - oneOf: - - type: object - properties: - type: - type: string - enum: - - INITIAL - example: INITIAL - - type: object - properties: - type: - type: string - enum: - - USER - example: USER - userId: - type: string - example: user123 - Variables: - type: object - additionalProperties: - type: array - items: - type: string - description: The variables to overwrite exclusively for this test run. - example: - SPACE_ID: - - 64ee32b4-7365-47a6-b5b0-2903b6ad849d - TestCaseElement: - type: object - properties: - id: - type: string - format: uuid - index: - type: integer - interaction: - type: object - nullable: true - properties: - id: - type: string - format: uuid - action: - type: string - enum: - - EXTRACT - - ENTER_TEXT - - CLICK - - SELECT_OPTION - - TYPE_TEXT - - KEY_PRESS - - HOVER - - UPLOAD - - GO_TO - - DRAG_AND_DROP - - CLOSE_PAGE - - OPEN_EMAIL - calledWith: - type: string - nullable: true - testCaseElementId: - type: string - format: uuid - assertion: - type: object - nullable: true - properties: - id: - type: string - format: uuid - expectation: - type: string - enum: - - VISIBLE - - NOT_VISIBLE - - TO_BE_CHECKED - - NOT_TO_BE_CHECKED - - TO_HAVE_VALUE - - TO_CONTAIN_TEXT - - TO_HAVE_STYLE - calledWith: - type: string - nullable: true - testCaseElementId: - type: string - format: uuid - selectors: - type: array - items: - type: object - properties: - id: - type: string - format: uuid - index: - type: integer - selector: - type: string - selectorType: - type: string - enum: - - TEXT - - LABEL - - PLACEHOLDER - - ROLE - options: - type: object - nullable: true - testCaseElementId: - type: string - format: uuid - testCaseId: - type: string - format: uuid - ignoreFailure: - type: boolean - TestTargetSyncSchema: - title: TestTargetSyncSchema - description: schema for import and export of test cases - type: object - properties: - testCases: - type: array - items: - type: object - properties: - version: - type: string - enum: - - '1' - id: - type: string - format: uuid - type: - type: string - enum: - - LOGIN - - COOKIE_BANNER - - LINK - - TEARDOWN - tagNames: - type: array - items: - type: string - excludedEnvironmentNames: - type: array - items: - type: string - runStatus: - type: string - enum: - - 'OFF' - - 'ON' - dependencyId: - type: string - format: uuid - teardownId: - type: string - format: uuid - elements: - type: array - items: - type: object - properties: - interaction: - anyOf: - - type: object - properties: - action: - type: string - enum: - - CLICK - calledWith: - type: object - properties: - button: - type: string - enum: - - right - - left - - middle - double: - type: boolean - force: - type: boolean - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - ENTER_TEXT - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - SELECT_OPTION - calledWith: - anyOf: - - anyOf: - - anyOf: - - type: string - - type: array - items: - type: string - - type: object - properties: - value: - type: string - label: - type: string - index: - type: number - additionalProperties: false - - type: array - items: - type: object - properties: - value: - type: string - label: - type: string - index: - type: number - additionalProperties: false - nullable: true - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - GO_TO - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - KEY_PRESS - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - HOVER - calledWith: - not: {} - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - UPLOAD - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - DOWNLOAD - calledWith: - anyOf: - - type: string - - {} - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - DRAG_AND_DROP - calledWith: - type: array - minItems: 2 - maxItems: 2 - prefixItems: - - type: string - - anyOf: - - type: string - - {} - items: {} - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - TYPE_TEXT - calledWith: - type: object - properties: - text: - type: string - delay: - type: number - required: - - text - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - EXTRACT - calledWith: - anyOf: - - type: object - properties: - variableName: - type: string - type: - type: string - enum: - - TEXT - required: - - variableName - - type - additionalProperties: false - - type: object - properties: - variableName: - type: string - type: - type: string - enum: - - ATTRIBUTE - attributeName: - type: string - required: - - variableName - - type - - attributeName - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - JAVASCRIPT - calledWith: - type: object - properties: - code: - type: string - execType: - type: string - enum: - - browser - - sandbox - default: sandbox - required: - - code - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - OPEN_EMAIL - calledWith: - type: object - properties: - subjectContaining: - type: string - nullable: true - subAddress: - type: string - pattern: ^[^ @]*$ - nullable: true - required: - - subjectContaining - - subAddress - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - CLOSE_PAGE - calledWith: - enum: - - 'null' - nullable: true - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - WAIT_FOR - calledWith: - anyOf: - - type: object - properties: - type: - type: string - enum: - - load - - domContentLoaded - - networkIdle - - nuxtHydration - - nuxtDelayHydration - - webComponentsHydration - - preactHydration - - qwikHydration - required: - - type - additionalProperties: false - - type: object - properties: - type: - type: string - enum: - - fixedTime - timeMilliseconds: - type: number - required: - - type - additionalProperties: false - - type: object - properties: - type: - type: string - enum: - - code - code: - type: string - required: - - type - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - SCROLL - calledWith: - type: object - properties: - x: - type: number - 'y': - type: number - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - assertion: - anyOf: - - type: object - properties: - expectation: - type: string - enum: - - VISIBLE - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - NOT_VISIBLE - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - RESPONSE_OK - calledWith: - type: string - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - DISABLED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_HAVE_VALUE - calledWith: - anyOf: - - type: string - - {} - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_BE_CHECKED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - NOT_TO_BE_CHECKED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_CONTAIN_TEXT - calledWith: - anyOf: - - type: string - - {} - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_HAVE_STYLE - calledWith: - type: array - minItems: 2 - maxItems: 2 - prefixItems: - - type: string - - anyOf: - - type: string - - {} - items: {} - required: - - expectation - - calledWith - additionalProperties: false - ignoreFailure: - type: boolean - selectors: - type: array - items: - type: object - properties: - selectorType: - type: string - enum: - - FRAME - - CSS - - TEXT - - ROLE - - ALT_TEXT - - LABEL - - TEST_ID - - TITLE - - PLACEHOLDER - - FILTER - - FIRST - - LAST - - NTH - selector: - anyOf: - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - type: string - enum: - - alert - - alertdialog - - application - - article - - banner - - blockquote - - button - - caption - - cell - - checkbox - - code - - columnheader - - combobox - - complementary - - contentinfo - - definition - - deletion - - dialog - - directory - - document - - emphasis - - feed - - figure - - form - - generic - - grid - - gridcell - - group - - heading - - img - - insertion - - link - - list - - listbox - - listitem - - log - - main - - marquee - - math - - meter - - menu - - menubar - - menuitem - - menuitemcheckbox - - menuitemradio - - navigation - - none - - note - - option - - paragraph - - presentation - - progressbar - - radio - - radiogroup - - region - - row - - rowgroup - - rowheader - - scrollbar - - search - - searchbox - - separator - - slider - - spinbutton - - status - - strong - - subscript - - superscript - - switch - - tab - - table - - tablist - - tabpanel - - term - - textbox - - time - - timer - - toolbar - - tooltip - - tree - - treegrid - - treeitem - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - type: string - - type: string - - type: string - nullable: true - options: - type: object - properties: - name: - anyOf: - - type: string - - {} - exact: - type: boolean - checked: - type: boolean - disabled: - type: boolean - expanded: - type: boolean - includeHidden: - type: boolean - level: - type: number - pressed: - type: boolean - selected: - type: boolean - hasText: - anyOf: - - type: string - - {} - hasNotText: - anyOf: - - type: string - - {} - additionalProperties: false - nullable: true - required: - - selectorType - additionalProperties: false - required: - - selectors - additionalProperties: false - description: - type: string - entryPointUrlPath: - type: string - folderName: - type: string - externalId: - type: string - prompt: - type: string - localEditingStatus: - type: string - enum: - - IN_PROGRESS - - DONE - - CANCELLED - required: - - version - - id - - runStatus - - elements - - description - - prompt - additionalProperties: false - required: - - testCases - additionalProperties: false - TestTargetCodeSchema: - title: TestTargetCodeSchema - description: schema for export of test cases as code - type: object - properties: - executionUrl: - type: string - format: uri - environmentId: - type: string - format: uuid - testCases: - type: array - items: - type: object - properties: - version: - type: string - enum: - - '1' - id: - type: string - format: uuid - type: - type: string - enum: - - LOGIN - - COOKIE_BANNER - - LINK - - TEARDOWN - tagNames: - type: array - items: - type: string - excludedEnvironmentNames: - type: array - items: - type: string - runStatus: - type: string - enum: - - 'OFF' - - 'ON' - dependencyId: - type: string - format: uuid - teardownId: - type: string - format: uuid - elements: - type: array - items: - type: object - properties: - interaction: - anyOf: - - type: object - properties: - action: - type: string - enum: - - CLICK - calledWith: - type: object - properties: - button: - type: string - enum: - - right - - left - - middle - double: - type: boolean - force: - type: boolean - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - ENTER_TEXT - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - SELECT_OPTION - calledWith: - anyOf: - - anyOf: - - anyOf: - - type: string - - type: array - items: - type: string - - type: object - properties: - value: - type: string - label: - type: string - index: - type: number - additionalProperties: false - - type: array - items: - type: object - properties: - value: - type: string - label: - type: string - index: - type: number - additionalProperties: false - nullable: true - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - GO_TO - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - KEY_PRESS - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - HOVER - calledWith: - not: {} - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - UPLOAD - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - DOWNLOAD - calledWith: - anyOf: - - type: string - - {} - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - DRAG_AND_DROP - calledWith: - type: array - minItems: 2 - maxItems: 2 - prefixItems: - - type: string - - anyOf: - - type: string - - {} - items: {} - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - TYPE_TEXT - calledWith: - type: object - properties: - text: - type: string - delay: - type: number - required: - - text - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - EXTRACT - calledWith: - anyOf: - - type: object - properties: - variableName: - type: string - type: - type: string - enum: - - TEXT - required: - - variableName - - type - additionalProperties: false - - type: object - properties: - variableName: - type: string - type: - type: string - enum: - - ATTRIBUTE - attributeName: - type: string - required: - - variableName - - type - - attributeName - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - JAVASCRIPT - calledWith: - type: object - properties: - code: - type: string - execType: - type: string - enum: - - browser - - sandbox - default: sandbox - required: - - code - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - OPEN_EMAIL - calledWith: - type: object - properties: - subjectContaining: - type: string - nullable: true - subAddress: - type: string - pattern: ^[^ @]*$ - nullable: true - required: - - subjectContaining - - subAddress - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - CLOSE_PAGE - calledWith: - enum: - - 'null' - nullable: true - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - WAIT_FOR - calledWith: - anyOf: - - type: object - properties: - type: - type: string - enum: - - load - - domContentLoaded - - networkIdle - - nuxtHydration - - nuxtDelayHydration - - webComponentsHydration - - preactHydration - - qwikHydration - required: - - type - additionalProperties: false - - type: object - properties: - type: - type: string - enum: - - fixedTime - timeMilliseconds: - type: number - required: - - type - additionalProperties: false - - type: object - properties: - type: - type: string - enum: - - code - code: - type: string - required: - - type - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - SCROLL - calledWith: - type: object - properties: - x: - type: number - 'y': - type: number - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - assertion: - anyOf: - - type: object - properties: - expectation: - type: string - enum: - - VISIBLE - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - NOT_VISIBLE - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - RESPONSE_OK - calledWith: - type: string - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - DISABLED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_HAVE_VALUE - calledWith: - anyOf: - - type: string - - {} - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_BE_CHECKED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - NOT_TO_BE_CHECKED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_CONTAIN_TEXT - calledWith: - anyOf: - - type: string - - {} - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_HAVE_STYLE - calledWith: - type: array - minItems: 2 - maxItems: 2 - prefixItems: - - type: string - - anyOf: - - type: string - - {} - items: {} - required: - - expectation - - calledWith - additionalProperties: false - ignoreFailure: - type: boolean - selectors: - type: array - items: - type: object - properties: - selectorType: - type: string - enum: - - FRAME - - CSS - - TEXT - - ROLE - - ALT_TEXT - - LABEL - - TEST_ID - - TITLE - - PLACEHOLDER - - FILTER - - FIRST - - LAST - - NTH - selector: - anyOf: - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - type: string - enum: - - alert - - alertdialog - - application - - article - - banner - - blockquote - - button - - caption - - cell - - checkbox - - code - - columnheader - - combobox - - complementary - - contentinfo - - definition - - deletion - - dialog - - directory - - document - - emphasis - - feed - - figure - - form - - generic - - grid - - gridcell - - group - - heading - - img - - insertion - - link - - list - - listbox - - listitem - - log - - main - - marquee - - math - - meter - - menu - - menubar - - menuitem - - menuitemcheckbox - - menuitemradio - - navigation - - none - - note - - option - - paragraph - - presentation - - progressbar - - radio - - radiogroup - - region - - row - - rowgroup - - rowheader - - scrollbar - - search - - searchbox - - separator - - slider - - spinbutton - - status - - strong - - subscript - - superscript - - switch - - tab - - table - - tablist - - tabpanel - - term - - textbox - - time - - timer - - toolbar - - tooltip - - tree - - treegrid - - treeitem - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - type: string - - type: string - - type: string - nullable: true - options: - type: object - properties: - name: - anyOf: - - type: string - - {} - exact: - type: boolean - checked: - type: boolean - disabled: - type: boolean - expanded: - type: boolean - includeHidden: - type: boolean - level: - type: number - pressed: - type: boolean - selected: - type: boolean - hasText: - anyOf: - - type: string - - {} - hasNotText: - anyOf: - - type: string - - {} - additionalProperties: false - nullable: true - required: - - selectorType - additionalProperties: false - required: - - selectors - additionalProperties: false - description: - type: string - entryPointUrlPath: - type: string - folderName: - type: string - externalId: - type: string - prompt: - type: string - localEditingStatus: - type: string - enum: - - IN_PROGRESS - - DONE - - CANCELLED - required: - - version - - id - - runStatus - - elements - - description - - prompt - additionalProperties: false - required: - - executionUrl - - testCases - additionalProperties: false - items: - type: object - properties: - version: - type: string - enum: - - '1' - id: - type: string - format: uuid - type: - type: string - enum: - - LOGIN - - COOKIE_BANNER - - LINK - - TEARDOWN - tagNames: - type: array - items: - type: string - excludedEnvironmentNames: - type: array - items: - type: string - runStatus: - type: string - enum: - - 'OFF' - - 'ON' - dependencyId: - type: string - format: uuid - teardownId: - type: string - format: uuid - elements: - type: array - items: - type: object - properties: - interaction: - anyOf: - - type: object - properties: - action: - type: string - enum: - - CLICK - calledWith: - type: object - properties: - button: - type: string - enum: - - right - - left - - middle - double: - type: boolean - force: - type: boolean - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - ENTER_TEXT - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - SELECT_OPTION - calledWith: - anyOf: - - anyOf: - - anyOf: - - type: string - - type: array - items: - type: string - - type: object - properties: - value: - type: string - label: - type: string - index: - type: number - additionalProperties: false - - type: array - items: - type: object - properties: - value: - type: string - label: - type: string - index: - type: number - additionalProperties: false - nullable: true - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - GO_TO - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - KEY_PRESS - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - HOVER - calledWith: - not: {} - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - UPLOAD - calledWith: - type: string - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - DOWNLOAD - calledWith: - anyOf: - - type: string - - {} - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - DRAG_AND_DROP - calledWith: - type: array - minItems: 2 - maxItems: 2 - prefixItems: - - type: string - - anyOf: - - type: string - - {} - items: {} - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - TYPE_TEXT - calledWith: - type: object - properties: - text: - type: string - delay: - type: number - required: - - text - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - EXTRACT - calledWith: - anyOf: - - type: object - properties: - variableName: - type: string - type: - type: string - enum: - - TEXT - required: - - variableName - - type - additionalProperties: false - - type: object - properties: - variableName: - type: string - type: - type: string - enum: - - ATTRIBUTE - attributeName: - type: string - required: - - variableName - - type - - attributeName - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - JAVASCRIPT - calledWith: - type: object - properties: - code: - type: string - execType: - type: string - enum: - - browser - - sandbox - default: sandbox - required: - - code - additionalProperties: false - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - OPEN_EMAIL - calledWith: - type: object - properties: - subjectContaining: - type: string - nullable: true - subAddress: - type: string - pattern: ^[^ @]*$ - nullable: true - required: - - subjectContaining - - subAddress - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - CLOSE_PAGE - calledWith: - enum: - - 'null' - nullable: true - required: - - action - - calledWith - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - WAIT_FOR - calledWith: - anyOf: - - type: object - properties: - type: - type: string - enum: - - load - - domContentLoaded - - networkIdle - - nuxtHydration - - nuxtDelayHydration - - webComponentsHydration - - preactHydration - - qwikHydration - required: - - type - additionalProperties: false - - type: object - properties: - type: - type: string - enum: - - fixedTime - timeMilliseconds: - type: number - required: - - type - additionalProperties: false - - type: object - properties: - type: - type: string - enum: - - code - code: - type: string - required: - - type - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - - type: object - properties: - action: - type: string - enum: - - SCROLL - calledWith: - type: object - properties: - x: - type: number - 'y': - type: number - additionalProperties: false - nullable: true - required: - - action - additionalProperties: false - assertion: - anyOf: - - type: object - properties: - expectation: - type: string - enum: - - VISIBLE - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - NOT_VISIBLE - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - RESPONSE_OK - calledWith: - type: string - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - DISABLED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_HAVE_VALUE - calledWith: - anyOf: - - type: string - - {} - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_BE_CHECKED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - NOT_TO_BE_CHECKED - calledWith: - not: {} - nullable: true - required: - - expectation - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_CONTAIN_TEXT - calledWith: - anyOf: - - type: string - - {} - required: - - expectation - - calledWith - additionalProperties: false - - type: object - properties: - expectation: - type: string - enum: - - TO_HAVE_STYLE - calledWith: - type: array - minItems: 2 - maxItems: 2 - prefixItems: - - type: string - - anyOf: - - type: string - - {} - items: {} - required: - - expectation - - calledWith - additionalProperties: false - ignoreFailure: - type: boolean - selectors: - type: array - items: - type: object - properties: - selectorType: - type: string - enum: - - FRAME - - CSS - - TEXT - - ROLE - - ALT_TEXT - - LABEL - - TEST_ID - - TITLE - - PLACEHOLDER - - FILTER - - FIRST - - LAST - - NTH - selector: - anyOf: - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - type: string - enum: - - alert - - alertdialog - - application - - article - - banner - - blockquote - - button - - caption - - cell - - checkbox - - code - - columnheader - - combobox - - complementary - - contentinfo - - definition - - deletion - - dialog - - directory - - document - - emphasis - - feed - - figure - - form - - generic - - grid - - gridcell - - group - - heading - - img - - insertion - - link - - list - - listbox - - listitem - - log - - main - - marquee - - math - - meter - - menu - - menubar - - menuitem - - menuitemcheckbox - - menuitemradio - - navigation - - none - - note - - option - - paragraph - - presentation - - progressbar - - radio - - radiogroup - - region - - row - - rowgroup - - rowheader - - scrollbar - - search - - searchbox - - separator - - slider - - spinbutton - - status - - strong - - subscript - - superscript - - switch - - tab - - table - - tablist - - tabpanel - - term - - textbox - - time - - timer - - toolbar - - tooltip - - tree - - treegrid - - treeitem - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - anyOf: - - type: string - - {} - - type: string - - type: string - - type: string - nullable: true - options: - type: object - properties: - name: - anyOf: - - type: string - - {} - exact: - type: boolean - checked: - type: boolean - disabled: - type: boolean - expanded: - type: boolean - includeHidden: - type: boolean - level: - type: number - pressed: - type: boolean - selected: - type: boolean - hasText: - anyOf: - - type: string - - {} - hasNotText: - anyOf: - - type: string - - {} - additionalProperties: false - nullable: true - required: - - selectorType - additionalProperties: false - required: - - selectors - additionalProperties: false - description: - type: string - entryPointUrlPath: - type: string - folderName: - type: string - externalId: - type: string - prompt: - type: string - localEditingStatus: - type: string - enum: - - IN_PROGRESS - - DONE - - CANCELLED - required: - - version - - id - - runStatus - - elements - - description - - prompt - additionalProperties: false diff --git a/package.json b/package.json index 24bece3..0b33e1c 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,7 @@ "description": "a command line client for octomind apis", "main": "./dist/index.js", "packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402", - "files": [ - "dist", - "src", - "README.md", - "LICENSE", - "package.json" - ], + "files": ["dist", "src", "README.md", "LICENSE", "package.json"], "engines": { "node": ">=22.0.0" }, @@ -34,7 +28,7 @@ "dev:local": "pnpm apigen && OCTOMIND_CONFIG_FILE=octomind.dev.local.json OCTOMIND_API_URL=http://localhost:3000/api tsx src/index.ts", "dev:staging": "pnpm apigen && OCTOMIND_CONFIG_FILE=octomind.dev.staging.json OCTOMIND_API_URL=https://preview.octomind.dev/api tsx src/index.ts", "dev:prod": "pnpm apigen && OCTOMIND_CONFIG_FILE=octomind.dev.prod.json OCTOMIND_API_URL=https://app.octomind.dev/api tsx src/index.ts", - "apigen": "openapi-typescript openapi.yaml --output src/api.ts && orval", + "apigen": "openapi-typescript https://preview.octomind.dev/openapi.yaml --output src/api.ts && orval", "build": "pnpm apigen && npx genversion -des src/version.ts && pnpm gendoc && tsc --project tsconfig.build.json", "octomind": "pnpm apigen && tsx src/index.ts", "test": "pnpm apigen && npx genversion -des src/version.ts && vitest", From 8f6671281927fd33933f95003395bad3ec902df4 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:05:30 +0100 Subject: [PATCH 11/15] lockfile --- pnpm-lock.yaml | 235 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1f48cfa..a3600c9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,9 +17,18 @@ importers: commander: specifier: 14.0.2 version: 14.0.2 + diff: + specifier: 8.0.3 + version: 8.0.3 + open: + specifier: 11.0.0 + version: 11.0.0 openapi-fetch: specifier: 0.15.0 version: 0.15.0 + ora: + specifier: 9.0.0 + version: 9.0.0 otplib: specifier: 13.1.0 version: 13.1.0 @@ -948,6 +957,10 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -1006,6 +1019,10 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -1033,6 +1050,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} @@ -1047,6 +1068,14 @@ packages: resolution: {integrity: sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==} engines: {node: '>=4'} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-spinners@3.4.0: + resolution: {integrity: sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==} + engines: {node: '>=18.20'} + cli-width@2.2.1: resolution: {integrity: sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==} @@ -1121,10 +1150,22 @@ packages: supports-color: optional: true + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.4.0: + resolution: {integrity: sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==} + engines: {node: '>=18'} + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -1133,6 +1174,10 @@ packages: resolution: {integrity: sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==} engines: {node: '>= 0.6.0'} + diff@8.0.3: + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} + engines: {node: '>=0.3.1'} + dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -1329,6 +1374,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.4.0: + resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1469,6 +1518,11 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1493,6 +1547,19 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -1537,6 +1604,10 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -1549,6 +1620,10 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -1639,6 +1714,10 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + log-symbols@7.0.1: + resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} + engines: {node: '>=18'} + loglevel-plugin-prefix@0.8.4: resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} @@ -1682,6 +1761,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1781,6 +1864,14 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} + openapi-fetch@0.15.0: resolution: {integrity: sha512-OjQUdi61WO4HYhr9+byCPMj0+bgste/LtSBEcV6FzDdONTs7x0fWn8/ndoYwzqCsKWIxEZwo4FN/TG1c1rI8IQ==} @@ -1799,6 +1890,10 @@ packages: openapi3-ts@4.5.0: resolution: {integrity: sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ==} + ora@9.0.0: + resolution: {integrity: sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A==} + engines: {node: '>=20'} + orval@7.18.0: resolution: {integrity: sha512-mPGSQeAAxhvRoxMKn22vmmtFa5eoJiwTBUSsrwKjKjC+rJdA3eWOLRiU1ICq2lep22S+3qpEy5WizP5FW26+rg==} engines: {node: '>=22.18.0'} @@ -1886,6 +1981,10 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -1929,6 +2028,10 @@ packages: resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} engines: {node: '>=4'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -1938,6 +2041,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -2034,6 +2141,10 @@ packages: signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + simple-eval@1.0.1: resolution: {integrity: sha512-LH7FpTAkeD+y5xQC4fzS+tFtaNlvt3Ib1zKzvhjv/Y+cioV4zIuw4IZr2yhRLu67CWL7FR9/6KXKnjRoZTvGGQ==} engines: {node: '>=12'} @@ -2055,6 +2166,10 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -2071,6 +2186,10 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@8.1.0: + resolution: {integrity: sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==} + engines: {node: '>=20'} + string.prototype.trim@1.2.10: resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} @@ -2098,6 +2217,10 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -2397,6 +2520,10 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -2425,6 +2552,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + zod@4.3.5: resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==} @@ -3275,6 +3406,8 @@ snapshots: ansi-regex@5.0.1: {} + ansi-regex@6.2.2: {} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 @@ -3331,6 +3464,10 @@ snapshots: dependencies: fill-range: 7.1.1 + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -3363,6 +3500,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.6.2: {} + change-case@5.4.4: {} chardet@0.7.0: {} @@ -3375,6 +3514,12 @@ snapshots: dependencies: restore-cursor: 2.0.0 + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-spinners@3.4.0: {} + cli-width@2.2.1: {} cliui@8.0.1: @@ -3441,12 +3586,21 @@ snapshots: optionalDependencies: supports-color: 10.2.2 + default-browser-id@5.0.1: {} + + default-browser@5.4.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.1 es-errors: 1.3.0 gopd: 1.2.0 + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -3455,6 +3609,8 @@ snapshots: dependency-graph@0.11.0: {} + diff@8.0.3: {} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 @@ -3757,6 +3913,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.4.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -3918,6 +4076,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-docker@3.0.0: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -3940,6 +4100,14 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-interactive@2.0.0: {} + is-map@2.0.3: {} is-negative-zero@2.0.3: {} @@ -3981,6 +4149,8 @@ snapshots: dependencies: which-typed-array: 1.1.19 + is-unicode-supported@2.1.0: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -3992,6 +4162,10 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-wsl@3.1.0: + dependencies: + is-inside-container: 1.0.0 + isarray@1.0.0: {} isarray@2.0.5: {} @@ -4062,6 +4236,11 @@ snapshots: lodash@4.17.21: {} + log-symbols@7.0.1: + dependencies: + is-unicode-supported: 2.1.0 + yoctocolors: 2.1.2 + loglevel-plugin-prefix@0.8.4: {} loglevel@1.9.2: {} @@ -4098,6 +4277,8 @@ snapshots: mimic-fn@2.1.0: {} + mimic-function@5.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -4208,6 +4389,19 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + open@11.0.0: + dependencies: + default-browser: 5.4.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 + openapi-fetch@0.15.0: dependencies: openapi-typescript-helpers: 0.0.15 @@ -4230,6 +4424,18 @@ snapshots: dependencies: yaml: 2.8.2 + ora@9.0.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 3.4.0 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 7.0.1 + stdin-discarder: 0.2.2 + string-width: 8.1.0 + strip-ansi: 7.1.2 + orval@7.18.0(openapi-types@12.1.3)(typescript@5.9.3): dependencies: '@apidevtools/swagger-parser': 12.1.0(openapi-types@12.1.3) @@ -4337,6 +4543,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + powershell-utils@0.1.0: {} + process-nextick-args@2.0.1: {} punycode.js@2.3.1: {} @@ -4388,6 +4596,11 @@ snapshots: onetime: 2.0.1 signal-exit: 3.0.7 + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + reusify@1.1.0: {} rollup@4.55.1: @@ -4421,6 +4634,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.55.1 fsevents: 2.3.3 + run-applescript@7.1.0: {} + run-async@2.4.1: {} run-parallel@1.2.0: @@ -4544,6 +4759,8 @@ snapshots: signal-exit@3.0.7: {} + signal-exit@4.1.0: {} + simple-eval@1.0.1: dependencies: jsep: 1.4.0 @@ -4564,6 +4781,8 @@ snapshots: std-env@3.10.0: {} + stdin-discarder@0.2.2: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -4582,6 +4801,11 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@8.1.0: + dependencies: + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 + string.prototype.trim@1.2.10: dependencies: call-bind: 1.0.8 @@ -4621,6 +4845,10 @@ snapshots: dependencies: ansi-regex: 5.0.1 + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + strip-final-newline@2.0.0: {} supports-color@10.2.2: {} @@ -4927,6 +5155,11 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + wsl-utils@0.3.1: + dependencies: + is-wsl: 3.1.0 + powershell-utils: 0.1.0 + y18n@5.0.8: {} yaml-ast-parser@0.0.43: {} @@ -4949,4 +5182,6 @@ snapshots: yocto-queue@0.1.0: {} + yoctocolors@2.1.2: {} + zod@4.3.5: {} From 5ae1afed35365e7e3ee1997c8a3ce08f1e60b904 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:25:48 +0100 Subject: [PATCH 12/15] add edit tests --- .github/workflows/publish.yml | 4 +- .github/workflows/ts.yml | 12 +- src/tools/yamlMutations/edit.ts | 3 + tests/tools/yamlMutations/edit.spec.ts | 232 +++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 tests/tools/yamlMutations/edit.spec.ts diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 5419be8..f30b77b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -14,9 +14,9 @@ jobs: npm i -g corepack@latest corepack enable - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 registry-url: "https://registry.npmjs.org" cache: "pnpm" diff --git a/.github/workflows/ts.yml b/.github/workflows/ts.yml index 7be9bc8..490afef 100644 --- a/.github/workflows/ts.yml +++ b/.github/workflows/ts.yml @@ -22,9 +22,9 @@ jobs: npm i -g corepack@latest corepack enable - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 cache: "pnpm" - run: pnpm i @@ -44,9 +44,9 @@ jobs: corepack enable - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 cache: "pnpm" - run: pnpm i @@ -64,9 +64,9 @@ jobs: npm i -g corepack@latest corepack enable - - uses: actions/setup-node@v5 + - uses: actions/setup-node@v6 with: - node-version: 22 + node-version: 24 cache: "pnpm" - run: pnpm i diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index 042dae5..f81fc35 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -46,8 +46,10 @@ const getRelevantTestCases = ( }; const loadTestCase = (testCasePath: string): SyncTestCase => { + console.log("loadTestCase"); try { const content = fs.readFileSync(testCasePath, "utf8"); + console.log({ content }); return yaml.parse(content); } catch (error) { throw new Error(`Could not parse ${testCasePath}: ${error}`); @@ -127,6 +129,7 @@ const waitForLocalEditingToBeFinished = async ( }; export const edit = async (options: EditOptions): Promise => { + console.log("hello"); const octomindRoot = await findOctomindFolder(); if (!octomindRoot) { throw new Error( diff --git a/tests/tools/yamlMutations/edit.spec.ts b/tests/tools/yamlMutations/edit.spec.ts new file mode 100644 index 0000000..15cee50 --- /dev/null +++ b/tests/tools/yamlMutations/edit.spec.ts @@ -0,0 +1,232 @@ +import fs from "fs"; + +import ora from "ora"; +import { beforeEach, describe, expect, it, MockedObject, vi } from "vitest"; +import { mock } from "vitest-mock-extended"; +import yaml from "yaml"; + +import { + findOctomindFolder, + getAbsoluteFilePathInOctomindRoot, +} from "../../../src/helpers"; +import { client } from "../../../src/tools/client"; +import { draftPush } from "../../../src/tools/sync/push"; +import { readTestCasesFromDir } from "../../../src/tools/sync/yml"; +import { edit } from "../../../src/tools/yamlMutations/edit"; +import { createMockSyncTestCase } from "../../mocks"; + +vi.mock("fs"); +vi.mock("open"); +vi.mock("ora"); +vi.mock("../../../src/helpers"); +vi.mock("../../../src/tools/client"); +vi.mock("../../../src/tools/sync/push"); +vi.mock("../../../src/tools/sync/yml"); +vi.mock("../../../src/tools/sync/consistency"); + +describe("edit", () => { + let mockedClient: MockedObject; + + beforeEach(() => { + console.log = vi.fn(); + + mockedClient = vi.mocked(client); + + vi.mocked(ora).mockReturnValue( + mock>({ + start: vi.fn().mockReturnThis(), + succeed: vi.fn(), + fail: vi.fn(), + }), + ); + + vi.mocked(readTestCasesFromDir).mockReturnValue([]); + }); + + it("throws if octomind folder is not found", async () => { + vi.mocked(findOctomindFolder).mockResolvedValue(null); + + await expect( + edit({ testTargetId: "someId", filePath: "test.yaml" }), + ).rejects.toThrow("Could not find .octomind folder"); + }); + + it("throws if file path is not found", async () => { + vi.mocked(findOctomindFolder).mockResolvedValue("/mock/.octomind"); + vi.mocked(getAbsoluteFilePathInOctomindRoot).mockResolvedValue(null); + + await expect( + edit({ testTargetId: "someId", filePath: "missing.yaml" }), + ).rejects.toThrow("Could not find missing.yaml"); + }); + + it("throws if test case file cannot be parsed", async () => { + vi.mocked(findOctomindFolder).mockResolvedValue("/mock/.octomind"); + vi.mocked(getAbsoluteFilePathInOctomindRoot).mockResolvedValue( + "/mock/.octomind/test.yaml", + ); + vi.mocked(fs.readFileSync).mockReturnValue("this: is: invalid: "); + + await expect( + edit({ testTargetId: "someId", filePath: "test.yaml" }), + ).rejects.toThrow("Could not parse"); + }); + + it("throws if draftPush returns no response", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(findOctomindFolder).mockResolvedValue("/mock/.octomind"); + vi.mocked(getAbsoluteFilePathInOctomindRoot).mockResolvedValue( + "/mock/.octomind/test.yaml", + ); + vi.mocked(fs.readFileSync).mockReturnValue(yaml.stringify(testCase)); + vi.mocked(readTestCasesFromDir).mockReturnValue([testCase]); + vi.mocked(draftPush).mockResolvedValue(undefined); + + await expect( + edit({ testTargetId: "someId", filePath: "test.yaml" }), + ).rejects.toThrow("Could not edit test case with id 'test-id'"); + }); + + it("throws if versionId is not returned for test case", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(findOctomindFolder).mockResolvedValue("/mock/.octomind"); + vi.mocked(getAbsoluteFilePathInOctomindRoot).mockResolvedValue( + "/mock/.octomind/test.yaml", + ); + vi.mocked(fs.readFileSync).mockReturnValue(yaml.stringify(testCase)); + vi.mocked(readTestCasesFromDir).mockReturnValue([testCase]); + vi.mocked(draftPush).mockResolvedValue({ + success: true, + versionIds: [], + versionIdByStableId: {}, + }); + + await expect( + edit({ testTargetId: "someId", filePath: "test.yaml" }), + ).rejects.toThrow("Could not edit test case with id 'test-id'"); + }); + + it("exits gracefully when editing is cancelled", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(findOctomindFolder).mockResolvedValue("/mock/.octomind"); + vi.mocked(getAbsoluteFilePathInOctomindRoot).mockResolvedValue( + "/mock/.octomind/test.yaml", + ); + vi.mocked(fs.readFileSync).mockReturnValue(yaml.stringify(testCase)); + vi.mocked(readTestCasesFromDir).mockReturnValue([testCase]); + vi.mocked(draftPush).mockResolvedValue({ + success: true, + versionIds: [], + versionIdByStableId: { "test-id": "version-123" }, + }); + vi.mocked(mockedClient.GET) + .mockResolvedValueOnce({ + data: { localEditingStatus: "IN_PROGRESS" }, + error: undefined, + response: mock(), + }) + .mockResolvedValueOnce({ + data: { localEditingStatus: "CANCELLED" }, + error: undefined, + response: mock(), + }); + + await edit({ testTargetId: "someId", filePath: "test.yaml" }); + + expect(console.log).toHaveBeenCalledWith( + "Cancelled editing test case, exiting", + ); + }); + + it("includes dependency chain in relevant test cases", async () => { + const parentTestCase = createMockSyncTestCase({ id: "parent-id" }); + const childTestCase = createMockSyncTestCase({ + id: "child-id", + dependencyId: "parent-id", + }); + + vi.mocked(findOctomindFolder).mockResolvedValue("/mock/.octomind"); + vi.mocked(getAbsoluteFilePathInOctomindRoot).mockResolvedValue( + "/mock/.octomind/child.yaml", + ); + vi.mocked(fs.readFileSync).mockReturnValue(yaml.stringify(childTestCase)); + vi.mocked(readTestCasesFromDir).mockReturnValue([ + parentTestCase, + childTestCase, + ]); + vi.mocked(draftPush).mockResolvedValue({ + success: true, + versionIds: [], + versionIdByStableId: { "child-id": "version-123" }, + }); + vi.mocked(mockedClient.GET).mockResolvedValue({ + data: { localEditingStatus: "CANCELLED" }, + error: undefined, + response: mock(), + }); + + await edit({ testTargetId: "someId", filePath: "child.yaml" }); + + expect(draftPush).toHaveBeenCalledWith( + expect.objectContaining({ + testCases: expect.arrayContaining([ + expect.objectContaining({ id: "child-id" }), + expect.objectContaining({ id: "parent-id" }), + ]), + }), + expect.anything(), + ); + }); + + it("throws if dependency is not found", async () => { + const childTestCase = createMockSyncTestCase({ + id: "child-id", + dependencyId: "missing-parent", + }); + + vi.mocked(findOctomindFolder).mockResolvedValue("/mock/.octomind"); + vi.mocked(getAbsoluteFilePathInOctomindRoot).mockResolvedValue( + "/mock/.octomind/child.yaml", + ); + vi.mocked(fs.readFileSync).mockReturnValue(yaml.stringify(childTestCase)); + vi.mocked(readTestCasesFromDir).mockReturnValue([childTestCase]); + + await expect( + edit({ testTargetId: "someId", filePath: "child.yaml" }), + ).rejects.toThrow("Could not find dependency missing-parent"); + }); + + it("exits gracefully when editing is finished", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(findOctomindFolder).mockResolvedValue("/mock/.octomind"); + vi.mocked(getAbsoluteFilePathInOctomindRoot).mockResolvedValue( + "/mock/.octomind/test.yaml", + ); + vi.mocked(fs.readFileSync).mockReturnValue(yaml.stringify(testCase)); + vi.mocked(readTestCasesFromDir).mockReturnValue([testCase]); + vi.mocked(draftPush).mockResolvedValue({ + success: true, + versionIds: [], + versionIdByStableId: { "test-id": "version-123" }, + }); + vi.mocked(mockedClient.GET) + .mockResolvedValueOnce({ + data: { localEditingStatus: "IN_PROGRESS" }, + error: undefined, + response: mock(), + }) + .mockResolvedValueOnce({ + data: { localEditingStatus: "DONE" }, + error: undefined, + response: mock(), + }); + + await edit({ testTargetId: "someId", filePath: "test.yaml" }); + + expect(console.log).toHaveBeenCalledWith("Edited test case successfully"); + }); +}); From ce31c818df448003a2c225d39ea5ae7dd19db429 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:26:37 +0100 Subject: [PATCH 13/15] fix --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 15ff7a8..6c34c49 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ This way even entityIds like environmentIds or testCaseIds will be autocompleted # octomind -Octomind cli tool. Version: 4.0.0. Additional documentation see https://octomind.dev/docs/api-reference/ +Octomind cli tool. Version: 4.1.0. Additional documentation see https://octomind.dev/docs/api-reference/ **Usage:** `octomind [options] [command]` diff --git a/package.json b/package.json index 0b33e1c..8eaea63 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@octomind/octomind", - "version": "4.0.0", + "version": "4.1.0", "description": "a command line client for octomind apis", "main": "./dist/index.js", "packageManager": "pnpm@10.26.0+sha512.3b3f6c725ebe712506c0ab1ad4133cf86b1f4b687effce62a9b38b4d72e3954242e643190fc51fa1642949c735f403debd44f5cb0edd657abe63a8b6a7e1e402", From 1b8db73854a8d362b15fbd8bada89605ee72d8e1 Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:40:18 +0100 Subject: [PATCH 14/15] split and add new tests --- src/tools/yamlMutations/edit.ts | 78 +------- .../yamlMutations/waitForLocalChanges.ts | 77 ++++++++ tests/tools/yamlMutations/edit.spec.ts | 12 +- .../yamlMutations/waitForLocalChanges.spec.ts | 175 ++++++++++++++++++ 4 files changed, 259 insertions(+), 83 deletions(-) create mode 100644 src/tools/yamlMutations/waitForLocalChanges.ts create mode 100644 tests/tools/yamlMutations/waitForLocalChanges.spec.ts diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index f81fc35..a2ef0ef 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -16,6 +16,7 @@ import { checkForConsistency } from "../sync/consistency"; import { draftPush } from "../sync/push"; import { SyncTestCase } from "../sync/types"; import { readTestCasesFromDir, writeSingleTestCaseYaml } from "../sync/yml"; +import { waitForLocalChangesToBeFinished } from "./waitForLocalChanges"; type EditOptions = { testTargetId: string; @@ -46,90 +47,15 @@ const getRelevantTestCases = ( }; const loadTestCase = (testCasePath: string): SyncTestCase => { - console.log("loadTestCase"); try { const content = fs.readFileSync(testCasePath, "utf8"); - console.log({ content }); return yaml.parse(content); } catch (error) { throw new Error(`Could not parse ${testCasePath}: ${error}`); } }; -const POLLING_INTERVAL = 1000; -const getTestCaseVersion = async ( - versionId: string, - testCase: SyncTestCase, - options: EditOptions, -) => { - return await client.GET( - "/apiKey/beta/test-targets/{testTargetId}/test-cases/{testCaseId}/versions/{versionId}", - { - params: { - path: { - versionId, - testCaseId: testCase.id, - testTargetId: options.testTargetId, - }, - }, - }, - ); -}; - -const waitForLocalEditingToBeFinished = async ( - versionId: string, - testCaseToEdit: SyncTestCase, - options: EditOptions, -): Promise => { - let localTestCase = await getTestCaseVersion( - versionId, - testCaseToEdit, - options, - ); - - if (!localTestCase.data) { - throw new Error( - `Could not get local editing status for test case ${testCaseToEdit.id}`, - ); - } - - const throbber = ora("Waiting for editing to finish in UI").start(); - while (localTestCase.data.localEditingStatus === "IN_PROGRESS") { - await sleep(POLLING_INTERVAL); - - localTestCase = await getTestCaseVersion( - versionId, - testCaseToEdit, - options, - ); - if (!localTestCase.data) { - throw new Error( - `Could not get local editing status for test case ${testCaseToEdit.id}`, - ); - } - - if (localTestCase.data.localEditingStatus === "CANCELLED") { - throbber.fail("cancelled by user"); - return "cancelled"; - } - } - - throbber.succeed("Finished editing in UI"); - - const syncTestCaseWithoutExtraProperties: SyncTestCase & { - versionId: undefined; - } = { - ...localTestCase.data, - id: testCaseToEdit.id, - localEditingStatus: undefined, - versionId: undefined, - }; - - return syncTestCaseWithoutExtraProperties; -}; - export const edit = async (options: EditOptions): Promise => { - console.log("hello"); const octomindRoot = await findOctomindFolder(); if (!octomindRoot) { throw new Error( @@ -186,7 +112,7 @@ export const edit = async (options: EditOptions): Promise => { `Navigating to local editing url, open it manually if a browser didn't open already: ${localEditingUrl}`, ); - const editResult = await waitForLocalEditingToBeFinished( + const editResult = await waitForLocalChangesToBeFinished( versionId, testCaseToEdit, options, diff --git a/src/tools/yamlMutations/waitForLocalChanges.ts b/src/tools/yamlMutations/waitForLocalChanges.ts new file mode 100644 index 0000000..c5a5171 --- /dev/null +++ b/src/tools/yamlMutations/waitForLocalChanges.ts @@ -0,0 +1,77 @@ +import ora from "ora"; + +import { sleep } from "../../helpers"; +import { client } from "../client"; +import { SyncTestCase } from "../sync/types"; + +const POLLING_INTERVAL = 1000; +const getTestCaseVersion = async ( + versionId: string, + testCase: SyncTestCase, + options: { testTargetId: string }, +) => { + return await client.GET( + "/apiKey/beta/test-targets/{testTargetId}/test-cases/{testCaseId}/versions/{versionId}", + { + params: { + path: { + versionId, + testCaseId: testCase.id, + testTargetId: options.testTargetId, + }, + }, + }, + ); +}; + +export const waitForLocalChangesToBeFinished = async ( + versionId: string, + testCaseToEdit: SyncTestCase, + options: { testTargetId: string }, +): Promise => { + let localTestCase = await getTestCaseVersion( + versionId, + testCaseToEdit, + options, + ); + + if (!localTestCase.data) { + throw new Error( + `Could not get local editing status for test case ${testCaseToEdit.id}`, + ); + } + + const throbber = ora("Waiting for editing to finish in UI").start(); + while (localTestCase.data.localEditingStatus === "IN_PROGRESS") { + await sleep(POLLING_INTERVAL); + + localTestCase = await getTestCaseVersion( + versionId, + testCaseToEdit, + options, + ); + if (!localTestCase.data) { + throw new Error( + `Could not get local editing status for test case ${testCaseToEdit.id}`, + ); + } + + if (localTestCase.data.localEditingStatus === "CANCELLED") { + throbber.fail("cancelled by user"); + return "cancelled"; + } + } + + throbber.succeed("Finished editing in UI"); + + const syncTestCaseWithoutExtraProperties: SyncTestCase & { + versionId: undefined; + } = { + ...localTestCase.data, + id: testCaseToEdit.id, + localEditingStatus: undefined, + versionId: undefined, + }; + + return syncTestCaseWithoutExtraProperties; +}; diff --git a/tests/tools/yamlMutations/edit.spec.ts b/tests/tools/yamlMutations/edit.spec.ts index 15cee50..48a8b44 100644 --- a/tests/tools/yamlMutations/edit.spec.ts +++ b/tests/tools/yamlMutations/edit.spec.ts @@ -13,16 +13,17 @@ import { client } from "../../../src/tools/client"; import { draftPush } from "../../../src/tools/sync/push"; import { readTestCasesFromDir } from "../../../src/tools/sync/yml"; import { edit } from "../../../src/tools/yamlMutations/edit"; +import { waitForLocalChangesToBeFinished } from "../../../src/tools/yamlMutations/waitForLocalChanges"; import { createMockSyncTestCase } from "../../mocks"; vi.mock("fs"); vi.mock("open"); -vi.mock("ora"); vi.mock("../../../src/helpers"); vi.mock("../../../src/tools/client"); vi.mock("../../../src/tools/sync/push"); vi.mock("../../../src/tools/sync/yml"); vi.mock("../../../src/tools/sync/consistency"); +vi.mock("../../../src/tools/yamlMutations/waitForLocalChanges"); describe("edit", () => { let mockedClient: MockedObject; @@ -32,12 +33,8 @@ describe("edit", () => { mockedClient = vi.mocked(client); - vi.mocked(ora).mockReturnValue( - mock>({ - start: vi.fn().mockReturnThis(), - succeed: vi.fn(), - fail: vi.fn(), - }), + vi.mocked(waitForLocalChangesToBeFinished).mockResolvedValue( + createMockSyncTestCase({ id: "test-id" }), ); vi.mocked(readTestCasesFromDir).mockReturnValue([]); @@ -133,6 +130,7 @@ describe("edit", () => { error: undefined, response: mock(), }); + vi.mocked(waitForLocalChangesToBeFinished).mockResolvedValue("cancelled"); await edit({ testTargetId: "someId", filePath: "test.yaml" }); diff --git a/tests/tools/yamlMutations/waitForLocalChanges.spec.ts b/tests/tools/yamlMutations/waitForLocalChanges.spec.ts new file mode 100644 index 0000000..f5fb69b --- /dev/null +++ b/tests/tools/yamlMutations/waitForLocalChanges.spec.ts @@ -0,0 +1,175 @@ +import { Client } from "openapi-fetch"; +import ora from "ora"; +import { beforeEach, describe, expect, it, MockedObject, vi } from "vitest"; +import { mock } from "vitest-mock-extended"; + +import { sleep } from "../../../src/helpers"; +import { client, paths } from "../../../src/tools/client"; +import { SyncTestCase } from "../../../src/tools/sync/types"; +import { waitForLocalChangesToBeFinished } from "../../../src/tools/yamlMutations/waitForLocalChanges"; +import { createMockSyncTestCase } from "../../mocks"; + +vi.mock("ora"); +vi.mock("../../../src/helpers"); +vi.mock("../../../src/tools/client"); + +describe("waitForLocalChangesToBeFinished", () => { + let mockedClient: MockedObject>; + let mockedOraInstance: MockedObject>; + + beforeEach(() => { + mockedClient = vi.mocked(client); + + mockedOraInstance = mock>({ + start: vi.fn().mockReturnThis(), + succeed: vi.fn(), + fail: vi.fn(), + }); + vi.mocked(ora).mockReturnValue(mockedOraInstance); + + vi.mocked(sleep).mockResolvedValue(); + }); + + it("throws if initial GET returns no data", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(mockedClient.GET).mockResolvedValueOnce({ + data: undefined, + error: { message: "error" }, + response: mock(), + }); + + await expect( + waitForLocalChangesToBeFinished("version-123", testCase, { + testTargetId: "someId", + }), + ).rejects.toThrow( + "Could not get local editing status for test case test-id", + ); + }); + + it("throws if GET returns no data during polling", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(mockedClient.GET) + .mockResolvedValueOnce({ + data: { localEditingStatus: "IN_PROGRESS" }, + error: undefined, + response: mock(), + }) + .mockResolvedValueOnce({ + data: undefined, + error: { message: "error" }, + response: mock(), + }); + + await expect( + waitForLocalChangesToBeFinished("version-123", testCase, { + testTargetId: "someId", + }), + ).rejects.toThrow( + "Could not get local editing status for test case test-id", + ); + }); + + it("returns 'cancelled' when localEditingStatus is CANCELLED", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(mockedClient.GET) + .mockResolvedValueOnce({ + data: { localEditingStatus: "IN_PROGRESS" }, + error: undefined, + response: mock(), + }) + .mockResolvedValueOnce({ + data: { localEditingStatus: "CANCELLED" }, + error: undefined, + response: mock(), + }); + + const result = await waitForLocalChangesToBeFinished( + "version-123", + testCase, + { + testTargetId: "someId", + }, + ); + + expect(result).toBe("cancelled"); + expect(mockedOraInstance.fail).toHaveBeenCalledWith("cancelled by user"); + }); + + it("returns updated test case when editing is finished", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(mockedClient.GET).mockResolvedValueOnce({ + data: { + localEditingStatus: "DONE", + description: "updated description", + elements: [], + version: "1", + prompt: "updated prompt", + runStatus: "ON", + }, + error: undefined, + response: mock(), + }); + + const result = await waitForLocalChangesToBeFinished( + "version-123", + testCase, + { + testTargetId: "someId", + }, + ); + + expect(result).toHaveProperty("versionId", undefined); + expect(result).toHaveProperty("localEditingStatus", undefined); + expect(result).toEqual({ + id: "test-id", + description: "updated description", + elements: [], + version: "1", + prompt: "updated prompt", + runStatus: "ON", + }); + expect(mockedOraInstance.succeed).toHaveBeenCalledWith( + "Finished editing in UI", + ); + }); + + it("polls until editing is finished", async () => { + const testCase = createMockSyncTestCase({ id: "test-id" }); + + vi.mocked(mockedClient.GET) + .mockResolvedValueOnce({ + data: { localEditingStatus: "IN_PROGRESS" }, + error: undefined, + response: mock(), + }) + .mockResolvedValueOnce({ + data: { localEditingStatus: "IN_PROGRESS" }, + error: undefined, + response: mock(), + }) + .mockResolvedValueOnce({ + data: { + localEditingStatus: "DONE", + description: "done", + elements: [], + version: "1", + prompt: "prompt", + runStatus: "ON", + }, + error: undefined, + response: mock(), + }); + + await waitForLocalChangesToBeFinished("version-123", testCase, { + testTargetId: "someId", + }); + + expect(sleep).toHaveBeenCalledTimes(2); + expect(mockedClient.GET).toHaveBeenCalledTimes(3); + }); +}); From 016779609622b17ba2223acde3722ae951fcd64d Mon Sep 17 00:00:00 2001 From: Daniel Draper Date: Wed, 14 Jan 2026 16:51:43 +0100 Subject: [PATCH 15/15] yml -> yaml --- src/debugtopus/index.ts | 2 +- src/tools/sync/push.ts | 2 +- src/tools/sync/{yml.ts => yaml.ts} | 22 ++++++++++++---------- src/tools/test-cases.ts | 2 +- src/tools/test-targets.ts | 2 +- src/tools/yamlMutations/edit.ts | 2 +- tests/debugtopus/index.spec.ts | 4 ++-- tests/tools/sync/push.spec.ts | 4 ++-- tests/tools/sync/yaml.spec.ts | 9 +++++---- tests/tools/test-cases.spec.ts | 4 ++-- tests/tools/test-targets.spec.ts | 4 ++-- tests/tools/yamlMutations/edit.spec.ts | 4 ++-- 12 files changed, 32 insertions(+), 29 deletions(-) rename src/tools/sync/{yml.ts => yaml.ts} (95%) diff --git a/src/debugtopus/index.ts b/src/debugtopus/index.ts index e72f141..4de0b5e 100644 --- a/src/debugtopus/index.ts +++ b/src/debugtopus/index.ts @@ -19,7 +19,7 @@ import { getTestCases, } from "../tools"; import { client, handleError } from "../tools/client"; -import { readTestCasesFromDir } from "../tools/sync/yml"; +import { readTestCasesFromDir } from "../tools/sync/yaml"; import { ensureChromiumIsInstalled } from "./installation"; export type DebugtopusOptions = { diff --git a/src/tools/sync/push.ts b/src/tools/sync/push.ts index fe8d689..ea034cf 100644 --- a/src/tools/sync/push.ts +++ b/src/tools/sync/push.ts @@ -5,7 +5,7 @@ import { ListOptions } from "../client"; import { checkForConsistency } from "./consistency"; import { getGitContext } from "./git"; import { TestTargetSyncData } from "./types"; -import { readTestCasesFromDir } from "./yml"; +import { readTestCasesFromDir } from "./yaml"; type ErrorResponse = | components["schemas"]["ZodResponse"] diff --git a/src/tools/sync/yml.ts b/src/tools/sync/yaml.ts similarity index 95% rename from src/tools/sync/yml.ts rename to src/tools/sync/yaml.ts index e0d28db..f7e89cb 100644 --- a/src/tools/sync/yml.ts +++ b/src/tools/sync/yaml.ts @@ -7,6 +7,8 @@ import yaml from "yaml"; import { pushTestTargetBody } from "../../schemas/octomindExternalAPI"; import { SyncTestCase, TestTargetSyncData } from "./types"; +const syncTestCaseSchema = pushTestTargetBody.shape.testCases.element; + const removeDiacritics = (str: string): string => { // diacritics lead to issues in the file system afterward, cf. https://www.reddit.com/r/MacOS/comments/jhjv41/psa_beware_of_umlauts_and_other_accented/ return str.normalize("NFKD").replace(/[\u0300-\u036f]/g, ""); @@ -181,21 +183,21 @@ export const readTestCasesFromDir = (startDir: string): SyncTestCase[] => { for (const file of yamlFiles) { try { const content = fs.readFileSync(file, "utf8"); - const parsed = yaml.parse(content); - testCases.push(parsed); + const raw = yaml.parse(content); + const result = syncTestCaseSchema.safeParse(raw); + + if (result.success) { + testCases.push(result.data); + } else { + console.warn( + `Failed to read test case from ${file}: ${result.error.message}`, + ); + } } catch { console.error(`Failed to read test case from ${file}`); } } - const result = pushTestTargetBody.safeParse({ testCases }); - - if (!result.success) { - throw new Error( - `Failed to parse test cases from ${startDir}: ${result.error.message}`, - ); - } - return testCases; }; diff --git a/src/tools/test-cases.ts b/src/tools/test-cases.ts index c831fe0..742fb06 100644 --- a/src/tools/test-cases.ts +++ b/src/tools/test-cases.ts @@ -6,7 +6,7 @@ import { findOctomindFolder } from "../helpers"; import { getUrl } from "../url"; import { client, handleError, ListOptions, logJson } from "./client"; import { getEnvironments } from "./environments"; -import { buildFilename, readTestCasesFromDir } from "./sync/yml"; +import { buildFilename, readTestCasesFromDir } from "./sync/yaml"; export type TestCaseResponse = components["schemas"]["TestCaseResponse"]; export type TestCasesResponse = components["schemas"]["TestCasesResponse"]; diff --git a/src/tools/test-targets.ts b/src/tools/test-targets.ts index ada58cb..62733d4 100644 --- a/src/tools/test-targets.ts +++ b/src/tools/test-targets.ts @@ -5,7 +5,7 @@ import { findOctomindFolder } from "../helpers"; import { getUrl } from "../url"; import { client, handleError, ListOptions, logJson } from "./client"; import { push } from "./sync/push"; -import { writeYaml } from "./sync/yml"; +import { writeYaml } from "./sync/yaml"; export const getTestTargets = async () => { const { data, error } = await client.GET("/apiKey/v3/test-targets"); diff --git a/src/tools/yamlMutations/edit.ts b/src/tools/yamlMutations/edit.ts index a2ef0ef..9d2cf4f 100644 --- a/src/tools/yamlMutations/edit.ts +++ b/src/tools/yamlMutations/edit.ts @@ -15,7 +15,7 @@ import { BASE_URL, client, handleError } from "../client"; import { checkForConsistency } from "../sync/consistency"; import { draftPush } from "../sync/push"; import { SyncTestCase } from "../sync/types"; -import { readTestCasesFromDir, writeSingleTestCaseYaml } from "../sync/yml"; +import { readTestCasesFromDir, writeSingleTestCaseYaml } from "../sync/yaml"; import { waitForLocalChangesToBeFinished } from "./waitForLocalChanges"; type EditOptions = { diff --git a/tests/debugtopus/index.spec.ts b/tests/debugtopus/index.spec.ts index 328ab7f..43c797e 100644 --- a/tests/debugtopus/index.spec.ts +++ b/tests/debugtopus/index.spec.ts @@ -17,14 +17,14 @@ import { ensureChromiumIsInstalled } from "../../src/debugtopus/installation"; import { findOctomindFolder } from "../../src/helpers"; import { client } from "../../src/tools/client"; import { getPlaywrightConfig } from "../../src/tools/playwright"; -import { readTestCasesFromDir } from "../../src/tools/sync/yml"; +import { readTestCasesFromDir } from "../../src/tools/sync/yaml"; import { createMockSyncTestCase } from "../mocks"; vi.mock("fs/promises"); vi.mock("fs"); vi.mock("unzipper"); vi.mock("../../src/tools/client"); -vi.mock("../../src/tools/sync/yml"); +vi.mock("../../src/tools/sync/yaml"); vi.mock("../../src/tools/playwright"); vi.mock("../../src/debugtopus/installation"); vi.mock("../../src/helpers"); diff --git a/tests/tools/sync/push.spec.ts b/tests/tools/sync/push.spec.ts index f12c7da..cc371a5 100644 --- a/tests/tools/sync/push.spec.ts +++ b/tests/tools/sync/push.spec.ts @@ -4,10 +4,10 @@ import { DeepMockProxy, mock, mockDeep } from "vitest-mock-extended"; import { client } from "../../../src/tools/client"; import { getGitContext } from "../../../src/tools/sync/git"; import { push } from "../../../src/tools/sync/push"; -import { readTestCasesFromDir } from "../../../src/tools/sync/yml"; +import { readTestCasesFromDir } from "../../../src/tools/sync/yaml"; vi.mock("../../../src/tools/sync/git"); -vi.mock("../../../src/tools/sync/yml"); +vi.mock("../../../src/tools/sync/yaml"); describe("push", () => { let mockedClient: DeepMockProxy; diff --git a/tests/tools/sync/yaml.spec.ts b/tests/tools/sync/yaml.spec.ts index 8688b30..d143e02 100644 --- a/tests/tools/sync/yaml.spec.ts +++ b/tests/tools/sync/yaml.spec.ts @@ -10,10 +10,10 @@ import { buildFolderName, cleanupFilesystem, readTestCasesFromDir, -} from "../../../src/tools/sync/yml"; +} from "../../../src/tools/sync/yaml"; import { createMockSyncTestCase } from "../../mocks"; -describe("yml", () => { +describe("yaml", () => { let tmpDir: string; beforeEach(() => { @@ -193,7 +193,7 @@ describe("yml", () => { expect(readTestCasesFromDir(tmpDir)).toEqual([testCase]); }); - it("should throw on an invalid test case", () => { + it("should skip invalid test cases and log an error", () => { fs.mkdirSync(path.join(tmpDir, "test1")); const testCase = createMockSyncTestCase({ @@ -204,7 +204,8 @@ describe("yml", () => { yaml.stringify(testCase), ); - expect(() => readTestCasesFromDir(tmpDir)).toThrow(/Invalid UUID/); + const result = readTestCasesFromDir(tmpDir); + expect(result).toEqual([]); }); }); diff --git a/tests/tools/test-cases.spec.ts b/tests/tools/test-cases.spec.ts index 2ab7b8b..0731b48 100644 --- a/tests/tools/test-cases.spec.ts +++ b/tests/tools/test-cases.spec.ts @@ -6,12 +6,12 @@ import { afterEach, beforeEach, describe, expect, it, Mock, vi } from "vitest"; import { findOctomindFolder } from "../../src/helpers"; import { client, handleError } from "../../src/tools/client"; -import { buildFilename, readTestCasesFromDir } from "../../src/tools/sync/yml"; +import { buildFilename, readTestCasesFromDir } from "../../src/tools/sync/yaml"; import { deleteTestCase } from "../../src/tools/test-cases"; vi.mock("../../src/tools/client"); vi.mock("../../src/helpers"); -vi.mock("../../src/tools/sync/yml"); +vi.mock("../../src/tools/sync/yaml"); describe("test-cases", () => { let clientDELETE: Mock; diff --git a/tests/tools/test-targets.spec.ts b/tests/tools/test-targets.spec.ts index 2e7de09..c44b312 100644 --- a/tests/tools/test-targets.spec.ts +++ b/tests/tools/test-targets.spec.ts @@ -5,11 +5,11 @@ import { findOctomindFolder } from "../../src/helpers"; import { pushTestTarget } from "../../src/tools"; import { client } from "../../src/tools/client"; import { getGitContext } from "../../src/tools/sync/git"; -import { readTestCasesFromDir } from "../../src/tools/sync/yml"; +import { readTestCasesFromDir } from "../../src/tools/sync/yaml"; vi.mock("../../src/helpers"); vi.mock("../../src/tools/sync/git"); -vi.mock("../../src/tools/sync/yml"); +vi.mock("../../src/tools/sync/yaml"); vi.mock("../../src/tools/client"); describe("push", () => { diff --git a/tests/tools/yamlMutations/edit.spec.ts b/tests/tools/yamlMutations/edit.spec.ts index 48a8b44..b003621 100644 --- a/tests/tools/yamlMutations/edit.spec.ts +++ b/tests/tools/yamlMutations/edit.spec.ts @@ -11,7 +11,7 @@ import { } from "../../../src/helpers"; import { client } from "../../../src/tools/client"; import { draftPush } from "../../../src/tools/sync/push"; -import { readTestCasesFromDir } from "../../../src/tools/sync/yml"; +import { readTestCasesFromDir } from "../../../src/tools/sync/yaml"; import { edit } from "../../../src/tools/yamlMutations/edit"; import { waitForLocalChangesToBeFinished } from "../../../src/tools/yamlMutations/waitForLocalChanges"; import { createMockSyncTestCase } from "../../mocks"; @@ -21,7 +21,7 @@ vi.mock("open"); vi.mock("../../../src/helpers"); vi.mock("../../../src/tools/client"); vi.mock("../../../src/tools/sync/push"); -vi.mock("../../../src/tools/sync/yml"); +vi.mock("../../../src/tools/sync/yaml"); vi.mock("../../../src/tools/sync/consistency"); vi.mock("../../../src/tools/yamlMutations/waitForLocalChanges");