From a3dd8c7d888fc756a33565c7f2b433d43e50e8b1 Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 13:58:22 +0200 Subject: [PATCH 1/9] generated api --- openapi.yaml | 1514 +++++++++++++++++++++++++++++++++++ package.json | 9 +- pnpm-lock.yaml | 185 ++++- src/api.ts | 1920 ++++++++++++++++++++++++++++++++++++--------- src/cli.ts | 4 +- src/tools.ts | 318 ++++++++ src/types.ts | 185 ----- tests/api.spec.ts | 294 ------- tests/cli.spec.ts | 5 +- 9 files changed, 3578 insertions(+), 856 deletions(-) create mode 100644 openapi.yaml create mode 100644 src/tools.ts delete mode 100644 src/types.ts delete mode 100644 tests/api.spec.ts diff --git a/openapi.yaml b/openapi.yaml new file mode 100644 index 0000000..f57be07 --- /dev/null +++ b/openapi.yaml @@ -0,0 +1,1514 @@ +openapi: 3.0.3 +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 +externalDocs: + description: Find out more + url: https://octomind.dev/docs/ +servers: + - url: https://app.octomind.dev/api + description: Main API Endpoint +components: + securitySchemes: + ApiKeyAuth: + type: apiKey + in: header + name: X-API-Key + schemas: + 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"] + + 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: [] + required: + - testTargetId + - url + - context + + TestTargetExecutionResponse: + type: object + properties: + testReportUrl: + type: string + description: The URL the test target was executed. + example: "https://example.com" + testReport: + type: object + description: The test report from the run. + example: "some json" + + TestReportContext: + type: object + properties: + source: + type: string + enum: [ "manual" ] + description: The source of the test trigger. + example: "manual" + description: + type: string + description: The description of the test context. + example: "manual trigger" + triggeredBy: + type: object + properties: + type: + type: string + enum: [ "USER" ] + description: The type of entity triggering the test. + example: "USER" + userId: + type: string + format: uuid + description: The unique identifier of the user who triggered the test. + example: "2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc" + + TestResult: + type: object + 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" + testCaseId: + type: string + format: uuid + description: Unique identifier of the test case 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" + + TestReport: + type: object + 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/TestReportContext" + 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 + + TestReportResponse: + type: object + 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" + + 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" + + EnvironmentResponse: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + testTargetId: + type: string + format: uuid + updatedAt: + type: string + format: date-time + type: + type: string + 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 + + TestSuiteRequestCommons: + type: object + properties: + beforeAll: + type: string + format: uuid + nullable: true + description: The test case to run before all test cases + afterAll: + type: string + format: uuid + nullable: true + description: The test case to run after all test cases + beforeEach: + type: string + format: uuid + nullable: true + description: The test case to run before each test case in the suite + afterEach: + type: string + format: uuid + nullable: true + description: The test case to run after each test case in the suite + + TestSuitePatchRequest: + allOf: + - type: object + properties: + name: + type: string + description: The name of the test suite + example: "regression for chat" + nullable: true + testCases: + type: array + items: + type: string + example: ["5b844cf1-d597-4048-9e74-7c0f9ce3e2ee"] + description: The test cases to include in the suite + nullable: true + environmentName: + type: string + description: the environment name you want to run your test suite against + example: "default" + nullable: true + - $ref: "#/components/schemas/TestSuiteRequestCommons" + + TestSuiteCreateRequest: + allOf: + - type: object + properties: + name: + type: string + description: The name of the test suite + example: "regression for chat" + testCases: + type: array + items: + type: string + example: ["5b844cf1-d597-4048-9e74-7c0f9ce3e2ee"] + description: The test cases to include in the suite + environmentName: + type: string + description: the environment name you want to run your test suite against + example: "default" + - $ref: "#/components/schemas/TestSuiteRequestCommons" + + TestSuiteResponse: + allOf: + - type: object + properties: + id: + type: string + format: uuid + - $ref: "#/components/schemas/TestSuiteCreateRequest" + + TestSuitesResponse: + type: array + items: + $ref: "#/components/schemas/TestSuiteResponse" + + 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" + +paths: + /apiKey/v2/test-suites: + get: + summary: Retrieve test suites + description: get a list of all defined test suites. + security: + - ApiKeyAuth: [ ] + tags: + - test-suites + responses: + "200": + description: test suites + content: + application/json: + schema: + $ref: "#/components/schemas/TestSuitesResponse" + post: + summary: Create a test suite + security: + - ApiKeyAuth: [ ] + tags: + - test-suites + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/TestSuiteCreateRequest" + responses: + "200": + description: test suites + content: + application/json: + schema: + $ref: "#/components/schemas/TestSuiteResponse" + "400": + description: Invalid request parameters + content: + application/json: + schema: + $ref: "#/components/schemas/ZodResponse" + + /apiKey/v2/test-suites/{testSuiteId}: + patch: + summary: Update a test suite + security: + - ApiKeyAuth: [ ] + tags: + - test-suites + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/TestSuitePatchRequest" + responses: + "200": + description: test suites + content: + application/json: + schema: + $ref: "#/components/schemas/TestSuiteResponse" + "400": + description: Invalid request parameters + content: + application/json: + schema: + $ref: "#/components/schemas/ZodResponse" + delete: + summary: Delete a test suite + security: + - ApiKeyAuth: [ ] + tags: + - test-suites + responses: + "204": + description: test suites + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "404": + description: test suite not found + + /apiKey/v2/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. + 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/TestReportResponse" + "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/v2/test-targets/{testTargetId}/environments/{environmentId}: + delete: + summary: Delete an environment + 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 + patch: + summary: Update an environment + 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 + + /apiKey/v2/test-targets/{testTargetId}/environments: + post: + summary: Create an environment + description: Create a custom environment. + 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" + + get: + summary: Retrieve environments + description: get a list of all defined environments. + 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/v2/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. + 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" + "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/v2/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. + 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/v2/test-targets/{testTargetId}/notifications: + get: + summary: Retrieve notifications + description: Get a list of notifications for a specific test target. + 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: + type: object + properties: + id: + type: string + format: uuid + testTargetId: + type: string + format: uuid + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + payload: + type: object + properties: + failed: + type: boolean + context: + $ref: '#/components/schemas/ExecutionContext' + testReportId: + type: string + format: uuid + testCaseId: + type: string + format: uuid + type: + type: string + enum: + - REPORT_EXECUTION_FINISHED + - VALIDATION_PASSED + ack: + type: string + enum: + - IN_WEB_APP + nullable: true + '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" + tags: + - private-location + 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" + tags: + - private-location + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/RegisterRequest" + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/SuccessResponse" + "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." + tags: + - private-location + 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" + "404": + description: private location of that name not found + "500": + description: Internal server error + + /apiKey/v2/test-targets/{testTargetId}/test-cases/{testCaseId}: + get: + summary: Retrieve a test case + description: Get detailed information about a specific test case + 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: + type: object + properties: + id: + type: string + format: uuid + 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 + discovery: + type: object + properties: + id: + type: string + format: uuid + freePrompt: + type: string + traceUrl: + type: string + nullable: true + traceJsonManifestUrl: + type: string + nullable: true + status: + type: string + enum: [OUTDATED] + abortCause: + type: string + nullable: true + message: + type: string + nullable: true + testCaseId: + type: string + format: uuid + lastJobExecutionName: + type: string + nullable: true + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + executedTestCaseElements: + type: array + items: + type: string + testCase: + type: object + properties: + id: + type: string + format: uuid + testTargetId: + type: string + format: uuid + description: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + entryPointUrlPath: + type: string + nullable: true + type: + type: string + nullable: true + status: + type: string + enum: [ENABLED] + runStatus: + type: string + enum: [ON] + interactionStatus: + type: string + enum: [NEW] + createdBy: + type: string + enum: [EDIT] + proposalRunId: + type: string + nullable: true + externalId: + type: string + nullable: true + folderId: + type: string + nullable: true + prerequisiteId: + type: string + nullable: true + predecessorId: + type: string + format: uuid + testTarget: + type: object + properties: + id: + type: string + format: uuid + app: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + orgId: + type: string + format: uuid + testIdAttribute: + type: string + nullable: true + timeoutPerStep: + type: integer + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target or test case not found + + /apiKey/v2/test-targets/{testTargetId}/discoveries: + post: + summary: Create a discovery + description: Create a new test case discovery with a given name and prompt + 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: + type: object + required: + - name + - prompt + properties: + name: + type: string + description: Name of the discovery + example: "foo" + prompt: + type: string + description: The prompt describing what to discover + example: "make sure current time is visible" + entryPointUrlPath: + type: string + description: Optional URL path for the entry point + nullable: true + prerequisiteId: + type: string + format: uuid + description: Optional ID of a prerequisite test case + nullable: true + externalId: + type: string + description: Optional external identifier + nullable: true + assignedTagIds: + type: array + description: Optional list of tag IDs to assign + items: + type: string + format: uuid + nullable: true + folderId: + type: string + format: uuid + description: Optional ID of the folder to place the discovery in + nullable: true + responses: + '200': + description: Discovery created successfully + content: + application/json: + schema: + 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 + '401': + description: Unauthorized - Invalid or missing API key + '404': + description: Test target not found + '400': + description: Invalid request body diff --git a/package.json b/package.json index be5e19b..c3b04b0 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.4", "description": "a command line client for octomind apis", "main": "./dist/index.js", - "packageManager": "pnpm@9.15.6+sha512.139cab068fdf0b751268179ac5f909b5be72afb4a75c513d1905d151befc8977b593d3cf8671ed83d4d6637c5c94b98ffbce108125de4a5a27a31233601a99de", + "packageManager": "pnpm@10.13.1", "engines": { "node": ">=20.0.0" }, @@ -12,7 +12,8 @@ }, "scripts": { "lint": "npx genversion -des src/version.ts && eslint src/**/*.ts tests/**/*.ts --max-warnings=0", - "build": "npx genversion -des src/version.ts && tsc --project tsconfig.build.json", + "apigen": "openapi-typescript ./openapi.yaml --output src/api.ts", + "build": "npx genversion -des src/version.ts && pnpm apigen && tsc --project tsconfig.build.json", "octomind": "tsx src/cli.ts", "test": "npx genversion -des src/version.ts && jest", "test:watch": "npx genversion -e src/version.ts && jest --watch" @@ -23,11 +24,12 @@ "dependencies": { "axios": "^1.7.9", "commander": "^14.0.0", + "openapi-fetch": "^0.14.0", "tsx": "^4.19.3" }, "devDependencies": { - "@types/node": "^24.0.1", "@types/jest": "^30.0.0", + "@types/node": "^24.0.1", "@typescript-eslint/parser": "^8.25.0", "eslint": "8.57.1", "eslint-config-prettier": "^10.0.1", @@ -37,6 +39,7 @@ "eslint-plugin-jest": "^29.0.1", "eslint-plugin-prettier": "^5.0.0", "jest": "^30.0.0", + "openapi-typescript": "^7.8.0", "prettier": "^3.0.1", "ts-jest": "^29.2.6", "ts-node": "^10.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aa79b1e..de9a59f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: commander: specifier: ^14.0.0 version: 14.0.0 + openapi-fetch: + specifier: ^0.14.0 + version: 0.14.0 tsx: specifier: ^4.19.3 version: 4.20.3 @@ -51,6 +54,9 @@ importers: jest: specifier: ^30.0.0 version: 30.0.5(@types/node@24.1.0)(ts-node@10.9.2(@types/node@24.1.0)(typescript@5.7.3)) + openapi-typescript: + specifier: ^7.8.0 + version: 7.8.0(typescript@5.7.3) prettier: specifier: ^3.0.1 version: 3.6.2 @@ -627,6 +633,16 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@redocly/ajv@8.11.2': + resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} + + '@redocly/config@0.22.2': + resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==} + + '@redocly/openapi-core@1.34.3': + resolution: {integrity: sha512-3arRdUp1fNx55itnjKiUhO6t4Mf91TsrTIYINDNLAZPS0TPd5YpiXRctwjel0qqWoOOhjA34cZ3m4dksLDFUYg==} + engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -1027,9 +1043,17 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -1215,6 +1239,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -1248,6 +1275,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -1824,6 +1854,10 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -1845,6 +1879,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + index-to-position@1.1.0: + resolution: {integrity: sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==} + engines: {node: '>=18'} + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. @@ -2164,6 +2202,10 @@ packages: node-notifier: optional: true + js-levenshtein@1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2189,6 +2231,9 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -2374,6 +2419,18 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + openapi-fetch@0.14.0: + resolution: {integrity: sha512-PshIdm1NgdLvb05zp8LqRQMNSKzIlPkyMxYFxwyHR+UlKD4t2nUjkDhNxeRbhRSEd3x5EUNh2w5sJYwkhOH4fg==} + + openapi-typescript-helpers@0.0.15: + resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} + + openapi-typescript@7.8.0: + resolution: {integrity: sha512-1EeVWmDzi16A+siQlo/SwSGIT7HwaFAVjvMA7/jG5HMLSnrUOzPL7uSTRZZa4v/LCRxHTApHKtNY6glApEoiUQ==} + hasBin: true + peerDependencies: + typescript: ^5.x + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2413,6 +2470,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2455,6 +2516,10 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -2508,6 +2573,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -2682,6 +2751,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + supports-color@10.0.0: + resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==} + engines: {node: '>=18'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2856,6 +2929,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + uri-js-replace@1.0.1: + resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -2916,6 +2992,9 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml-ast-parser@0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -2960,7 +3039,7 @@ snapshots: '@babel/traverse': 7.28.0 '@babel/types': 7.28.1 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -3117,7 +3196,7 @@ snapshots: '@babel/parser': 7.28.0 '@babel/template': 7.27.2 '@babel/types': 7.28.1 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) transitivePeerDependencies: - supports-color @@ -3272,7 +3351,7 @@ snapshots: '@eslint/eslintrc@3.3.0': dependencies: ajv: 6.12.6 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) espree: 10.3.0 globals: 14.0.0 ignore: 5.3.2 @@ -3578,6 +3657,29 @@ snapshots: '@pkgr/core@0.2.9': {} + '@redocly/ajv@8.11.2': + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js-replace: 1.0.1 + + '@redocly/config@0.22.2': {} + + '@redocly/openapi-core@1.34.3(supports-color@10.0.0)': + dependencies: + '@redocly/ajv': 8.11.2 + '@redocly/config': 0.22.2 + colorette: 1.4.0 + https-proxy-agent: 7.0.6(supports-color@10.0.0) + js-levenshtein: 1.1.6 + js-yaml: 4.1.0 + minimatch: 5.1.6 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - supports-color + '@rtsao/scc@1.1.0': {} '@sinclair/typebox@0.34.35': {} @@ -3700,7 +3802,7 @@ snapshots: '@typescript-eslint/types': 8.24.1 '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.7.3) '@typescript-eslint/visitor-keys': 8.24.1 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) eslint: 8.57.1 typescript: 5.7.3 transitivePeerDependencies: @@ -3712,7 +3814,7 @@ snapshots: '@typescript-eslint/types': 8.38.0 '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.7.3) '@typescript-eslint/visitor-keys': 8.38.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) eslint: 8.57.1 typescript: 5.7.3 transitivePeerDependencies: @@ -3722,7 +3824,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.34.1(typescript@5.7.3) '@typescript-eslint/types': 8.34.1 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -3731,7 +3833,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.7.3) '@typescript-eslint/types': 8.38.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) typescript: 5.7.3 transitivePeerDependencies: - supports-color @@ -3763,7 +3865,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.7.3) '@typescript-eslint/utils': 8.24.1(eslint@8.57.1)(typescript@5.7.3) - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) eslint: 8.57.1 ts-api-utils: 2.0.1(typescript@5.7.3) typescript: 5.7.3 @@ -3780,7 +3882,7 @@ snapshots: dependencies: '@typescript-eslint/types': 8.24.1 '@typescript-eslint/visitor-keys': 8.24.1 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -3796,7 +3898,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.34.1(typescript@5.7.3) '@typescript-eslint/types': 8.34.1 '@typescript-eslint/visitor-keys': 8.34.1 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -3812,7 +3914,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.7.3) '@typescript-eslint/types': 8.38.0 '@typescript-eslint/visitor-keys': 8.38.0 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) fast-glob: 3.3.3 is-glob: 4.0.3 minimatch: 9.0.5 @@ -3989,6 +4091,8 @@ snapshots: acorn@8.14.0: {} + agent-base@7.1.4: {} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -3996,6 +4100,8 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -4226,6 +4332,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + change-case@5.4.4: {} + char-regex@1.0.2: {} ci-info@4.2.0: {} @@ -4250,6 +4358,8 @@ snapshots: color-name@1.1.4: {} + colorette@1.4.0: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -4296,9 +4406,11 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.1: + debug@4.4.1(supports-color@10.0.0): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.0.0 dedent@1.6.0: {} @@ -4497,7 +4609,7 @@ snapshots: eslint-import-resolver-typescript@4.4.4(eslint-plugin-import@2.32.0)(eslint@8.57.1): dependencies: - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) eslint: 8.57.1 eslint-import-context: 0.1.9(unrs-resolver@1.9.2) get-tsconfig: 4.10.1 @@ -4958,6 +5070,13 @@ snapshots: html-escaper@2.0.2: {} + https-proxy-agent@7.0.6(supports-color@10.0.0): + dependencies: + agent-base: 7.1.4 + debug: 4.4.1(supports-color@10.0.0) + transitivePeerDependencies: + - supports-color + human-signals@2.1.0: {} ignore@5.3.2: {} @@ -4974,6 +5093,8 @@ snapshots: imurmurhash@0.1.4: {} + index-to-position@1.1.0: {} + inflight@1.0.6: dependencies: once: 1.4.0 @@ -5133,7 +5254,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.29 - debug: 4.4.1 + debug: 4.4.1(supports-color@10.0.0) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -5511,6 +5632,8 @@ snapshots: - supports-color - ts-node + js-levenshtein@1.1.6: {} + js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -5530,6 +5653,8 @@ snapshots: json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} json5@1.0.2: @@ -5694,6 +5819,22 @@ snapshots: dependencies: mimic-fn: 2.1.0 + openapi-fetch@0.14.0: + dependencies: + openapi-typescript-helpers: 0.0.15 + + openapi-typescript-helpers@0.0.15: {} + + openapi-typescript@7.8.0(typescript@5.7.3): + dependencies: + '@redocly/openapi-core': 1.34.3(supports-color@10.0.0) + ansi-colors: 4.1.3 + change-case: 5.4.4 + parse-json: 8.3.0 + supports-color: 10.0.0 + typescript: 5.7.3 + yargs-parser: 21.1.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -5740,6 +5881,12 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.27.1 + index-to-position: 1.1.0 + type-fest: 4.41.0 + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -5767,6 +5914,8 @@ snapshots: dependencies: find-up: 4.1.0 + pluralize@8.0.0: {} + possible-typed-array-names@1.1.0: {} prelude-ls@1.2.1: {} @@ -5821,6 +5970,8 @@ snapshots: require-directory@2.1.1: {} + require-from-string@2.0.2: {} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 @@ -6014,6 +6165,8 @@ snapshots: strip-json-comments@3.1.1: {} + supports-color@10.0.0: {} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -6238,6 +6391,8 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + uri-js-replace@1.0.1: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -6324,6 +6479,8 @@ snapshots: yallist@3.1.1: {} + yaml-ast-parser@0.0.43: {} + yargs-parser@21.1.1: {} yargs@17.7.2: diff --git a/src/api.ts b/src/api.ts index 4e326fb..3d2b590 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,356 +1,1566 @@ -import axios from "axios"; -import { - ExecuteTestsOptions, - GetTestReportOptions, - RegisterLocationOptions, - UnregisterLocationOptions, - ListPrivateLocationsOptions, - PrivateLocationInfo, - ListEnvironmentsOptions, - CreateEnvironmentOptions, - UpdateEnvironmentOptions, - DeleteEnvironmentOptions, - TestTargetExecutionRequest, - TestReportResponse, - RegisterRequest, - UnregisterRequest, - SuccessResponse, - Environment, - TestReport, -} from "./types"; +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ -const BASE_URL = "https://app.octomind.dev/api"; - -// Helper function for API calls -const apiCall = async ( - method: "get" | "post" | "put" | "delete" | "patch", - endpoint: string, - apiKey: string, - data?: unknown, -): Promise => { - try { - const response = await axios({ - method, - url: `${BASE_URL}${endpoint}`, - data, - headers: { - "X-API-Key": apiKey, - "Content-Type": "application/json", - }, - }); - return response.data as T; - } catch (error) { - if (axios.isAxiosError(error)) { - console.error("API Error:", error.response?.data || error.message); - } else { - console.error("Error:", error); - } - process.exit(1); - } -}; - -const outputResult = (result: unknown): void => { - console.log(JSON.stringify(result, null, 2)); -}; - -export const executeTests = async ( - options: ExecuteTestsOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - const requestBody: TestTargetExecutionRequest = { - testTargetId: options.testTargetId, - url: options.url, - context: { - source: "manual", - description: options.description || "CLI execution", - triggeredBy: { - type: "USER", - userId: "cli-user", - }, - }, - environmentName: options.environment, - tags: options.tags, - variablesToOverwrite: options.variablesToOverwrite, - }; - - const response = await apiCall( - "post", - "/apiKey/v2/execute", - options.apiKey, - requestBody, - ); - - if (options.json) { - outputResult(response); - return; - } - - console.log("Test execution started successfully!"); - console.log("Test Report URL:", response.testReportUrl); - console.log("Report Status:", response.testReport.status); - - if (response.testReport.testResults.length > 0) { - console.log("\nTest Results:"); - response.testReport.testResults.forEach((result) => { - console.log(`- Test ${result.testCaseId}: ${result.status}`); - if (result.errorMessage) { - console.log(` Error: ${result.errorMessage}`); - } - if (result.traceUrl) { - console.log(` Trace: ${result.traceUrl}`); - } - }); - } -}; - -export const getTestReport = async ( - options: GetTestReportOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - const response = await apiCall( - "get", - `/apiKey/v2/test-targets/${options.testTargetId}/test-reports/${options.reportId}`, - options.apiKey, - ); - - if (options.json) { - outputResult(response); - return; - } - - console.log("Test Report Details:"); - console.log("Status:", response.status); - console.log("Execution URL:", response.executionUrl); - - if (response.testResults.length > 0) { - console.log("\nTest Results:"); - response.testResults.forEach((result) => { - console.log(`- Test ${result.testCaseId}: ${result.status}`); - if (result.errorMessage) { - console.log(` Error: ${result.errorMessage}`); - } - if (result.traceUrl) { - console.log(` Trace: ${result.traceUrl}`); - } - }); - } -}; - -export const registerLocation = async ( - options: RegisterLocationOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - const requestBody: RegisterRequest = { - name: options.name, - registrationData: { - proxypass: options.proxypass, - proxyuser: options.proxyuser, - address: options.address, - }, - }; - - const response = await apiCall( - "put", - "/apiKey/v1/private-location/register", - options.apiKey, - requestBody, - ); - - if (options.json) { - outputResult(response); - return; - } - - console.log("Registration result:", response.success ? "Success" : "Failed"); -}; - -export const unregisterLocation = async ( - options: UnregisterLocationOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - const requestBody: UnregisterRequest = { - name: options.name, - }; - - const response = await apiCall( - "put", - "/apiKey/v1/private-location/unregister", - options.apiKey, - requestBody, - ); - - if (options.json) { - outputResult(response); - return; - } - - console.log( - "Unregistration result:", - response.success ? "Success" : "Failed", - ); -}; - -export const listPrivateLocations = async ( - options: ListPrivateLocationsOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - const response = await apiCall( - "get", - "/apiKey/v1/private-location", - options.apiKey, - ); - - if (options.json) { - outputResult(response); - return; - } - - console.log("Private Locations:"); - response.forEach((location) => { - console.log(`- Name: ${location.name}`); - console.log(` Status: ${location.status}`); - console.log(` Address: ${location.address}`); - }); -}; - -export const listEnvironments = async ( - options: ListEnvironmentsOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - const response = await apiCall( - "get", - `/apiKey/v2/test-targets/${options.testTargetId}/environments`, - options.apiKey, - ); - - if (options.json) { - outputResult(response); - return; - } - - console.log("Environments:"); - response.forEach((environment) => { - console.log(`- Name: ${environment.name}`); - console.log(` ID: ${environment.id}`); - console.log(` Discovery URL: ${environment.discoveryUrl}`); - console.log(` Updated At: ${environment.updatedAt}`); - }); -}; - -export const createEnvironment = async ( - options: CreateEnvironmentOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - const requestBody = { - name: options.name, - discoveryUrl: options.discoveryUrl, - testAccount: options.testAccount, - basicAuth: options.basicAuth, - privateLocationName: options.privateLocationName, - additionalHeaderFields: options.additionalHeaderFields, - }; - - const response = await apiCall( - "post", - `/apiKey/v2/test-targets/${options.testTargetId}/environments`, - options.apiKey, - requestBody, - ); - - if (options.json) { - outputResult(response); - return; - } - - console.log("Environment created successfully!"); - console.log(`- Name: ${response.name}`); - console.log(` ID: ${response.id}`); - console.log(` Discovery URL: ${response.discoveryUrl}`); - console.log(` Updated At: ${response.updatedAt}`); -}; - -export const updateEnvironment = async ( - options: UpdateEnvironmentOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - const requestBody = { - name: options.name, - discoveryUrl: options.discoveryUrl, - testAccount: options.testAccount, - basicAuth: options.basicAuth, - privateLocationName: options.privateLocationName, - additionalHeaderFields: options.additionalHeaderFields, - }; - - const response = await apiCall( - "patch", - `/apiKey/v2/test-targets/${options.testTargetId}/environments/${options.environmentId}`, - options.apiKey, - requestBody, - ); - - if (options.json) { - outputResult(response); - return; - } - - console.log("Environment updated successfully!"); - console.log(`- Name: ${response.name}`); - console.log(` ID: ${response.id}`); - console.log(` Discovery URL: ${response.discoveryUrl}`); - console.log(` Updated At: ${response.updatedAt}`); -}; - -export const deleteEnvironment = async ( - options: DeleteEnvironmentOptions, -): Promise => { - if (!options.apiKey) { - console.error("API key is required"); - process.exit(1); - } - - await apiCall( - "delete", - `/apiKey/v2/test-targets/${options.testTargetId}/environments/${options.environmentId}`, - options.apiKey, - ); - - if (options.json) { - outputResult({ success: true }); - return; - } - - console.log("Environment deleted successfully!"); -}; +export interface paths { + "/apiKey/v2/test-suites": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve test suites + * @description get a list of all defined test suites. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description test suites */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestSuitesResponse"]; + }; + }; + }; + }; + put?: never; + /** Create a test suite */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TestSuiteCreateRequest"]; + }; + }; + responses: { + /** @description test suites */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestSuiteResponse"]; + }; + }; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-suites/{testSuiteId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Delete a test suite */ + delete: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description test suites */ + 204: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SuccessResponse"]; + }; + }; + /** @description test suite not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + options?: never; + head?: never; + /** Update a test suite */ + patch: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TestSuitePatchRequest"]; + }; + }; + responses: { + /** @description test suites */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestSuiteResponse"]; + }; + }; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; + }; + }; + }; + trace?: never; + }; + "/apiKey/v2/execute": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * 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. + * + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TestTargetExecutionRequest"]; + }; + }; + responses: { + /** @description Test executed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestReportResponse"]; + }; + }; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; + }; + /** @description Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Delete an environment */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the test report belongs to */ + testTargetId: string; + /** @description ID of the environment to update */ + environmentId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Environment deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + options?: never; + head?: never; + /** Update an environment */ + patch: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the environment belongs to */ + testTargetId: string; + /** @description ID of the environment to update */ + environmentId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + name?: string | null; + /** Format: url */ + discoveryUrl?: string | null; + testAccount?: { + username?: string; + password?: string; + otpInitializerKey?: string | null; + } | null; + basicAuth?: { + username?: string; + password?: string; + } | null; + /** @description name of the private location */ + privateLocationName?: string | null; + additionalHeaderFields?: { + [key: string]: string; + } | null; + }; + }; + }; + responses: { + /** @description Environment updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/environments": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve environments + * @description get a list of all defined environments. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the test report belongs to */ + testTargetId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description environments */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["EnvironmentsResponse"]; + }; + }; + }; + }; + put?: never; + /** + * Create an environment + * @description Create a custom environment. + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the environment belongs to */ + testTargetId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + name?: string; + /** Format: url */ + discoveryUrl?: string; + testAccount?: { + username?: string; + password?: string; + otpInitializerKey?: string | null; + } | null; + basicAuth?: { + username?: string; + password?: string; + } | null; + /** @description name of the private location */ + privateLocationName?: string; + additionalHeaderFields?: { + [key: string]: string; + } | null; + }; + }; + }; + responses: { + /** @description environment created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["EnvironmentResponse"]; + }; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve information about a test report + * @description Poll from within a CI-pipeline to wait for the completion of a report. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the test report belongs to */ + testTargetId: string; + /** @description ID of the test report to fetch */ + testReportId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Test Report information */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestReport"]; + }; + }; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; + }; + /** @description Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/test-reports": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve paginated information about test reports + * @description Allow fetching the history of test reports for your test target. + */ + get: { + parameters: { + query?: { + key?: { + /** + * 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 + */ + createdAt?: string; + }; + filter?: { + /** + * @description The name of the property to filter for, e.g. an environmentId + * @example environmentId + */ + key?: string; + /** + * @description How to compare the property in question, only EQUALS is supported so far. + * @enum {string} + */ + operator?: "EQUALS"; + /** + * Format: uuid + * @description The value to compare with to find matches. + * @example 3435918b-3d29-4ebd-8c68-9a540532f45a + */ + value?: string; + }[]; + }; + header?: never; + path: { + /** @description ID of the test target for which to fetch the history for */ + testTargetId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Test Reports information */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + data?: components["schemas"]["TestReport"][]; + key?: { + /** + * 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 + */ + createdAt?: string; + }; + /** @description If the query in question has another page to retrieve */ + hasNextPage?: boolean; + }; + }; + }; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; + }; + /** @description Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/notifications": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve notifications + * @description Get a list of notifications for a specific test target. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description The ID of the test target */ + testTargetId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of notifications */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** Format: uuid */ + id?: string; + /** Format: uuid */ + testTargetId?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + payload?: { + failed?: boolean; + context?: components["schemas"]["ExecutionContext"]; + /** Format: uuid */ + testReportId?: string; + /** Format: uuid */ + testCaseId?: string; + }; + /** @enum {string} */ + type?: "REPORT_EXECUTION_FINISHED" | "VALIDATION_PASSED"; + /** @enum {string|null} */ + ack?: "IN_WEB_APP" | null; + }[]; + }; + }; + /** @description Unauthorized - Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Test target not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v1/private-location": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve all private locations + * @description gets a list of private location workers + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PrivateLocationInfo"]; + }; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v1/private-location/register": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Register a private location + * @description registers a private location worker + */ + put: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["RegisterRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SuccessResponse"]; + }; + }; + /** @description private location of that name not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v1/private-location/unregister": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Unregister a private location + * @description Unregisters a private location worker. + */ + put: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UnregisterRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SuccessResponse"]; + }; + }; + /** @description private location of that name not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/test-cases/{testCaseId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve a test case + * @description Get detailed information about a specific test case + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description The ID of the test target */ + testTargetId: string; + /** @description The ID of the test case */ + testCaseId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Test case details */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** Format: uuid */ + id?: string; + /** Format: uuid */ + testTargetId?: string; + type?: string | null; + elements?: { + /** Format: uuid */ + id?: string; + index?: number; + interaction?: { + /** Format: uuid */ + id?: string; + /** @enum {string} */ + action?: "EXTRACT" | "ENTER_TEXT" | "CLICK" | "SELECT_OPTION" | "TYPE_TEXT" | "KEY_PRESS" | "HOVER" | "UPLOAD" | "GO_TO" | "DRAG_AND_DROP" | "CLOSE_PAGE" | "OPEN_EMAIL"; + calledWith?: string | null; + /** Format: uuid */ + testCaseElementId?: string; + } | null; + assertion?: { + /** Format: uuid */ + id?: string; + /** @enum {string} */ + expectation?: "VISIBLE" | "NOT_VISIBLE" | "TO_BE_CHECKED" | "NOT_TO_BE_CHECKED" | "TO_HAVE_VALUE" | "TO_CONTAIN_TEXT" | "TO_HAVE_STYLE"; + calledWith?: string | null; + /** Format: uuid */ + testCaseElementId?: string; + } | null; + scrollState?: Record | null; + selectors?: { + /** Format: uuid */ + id?: string; + index?: number; + selector?: string; + /** @enum {string} */ + selectorType?: "TEXT" | "LABEL" | "PLACEHOLDER" | "ROLE"; + options?: { + name?: string; + } | null; + /** Format: uuid */ + testCaseElementId?: string; + scrollStateId?: string | null; + }[]; + /** Format: uuid */ + testCaseId?: string; + ignoreFailure?: boolean; + }[]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + description?: string; + /** @enum {string} */ + status?: "ENABLED" | "DRAFT"; + externalId?: string | null; + entryPointUrlPath?: string | null; + tags?: string[]; + /** @enum {string} */ + createdBy?: "EDIT"; + /** @enum {string} */ + runStatus?: "ON" | "OFF"; + prerequisiteId?: string | null; + proposalRunId?: string | null; + folderId?: string | null; + discovery?: { + /** Format: uuid */ + id?: string; + freePrompt?: string; + traceUrl?: string | null; + traceJsonManifestUrl?: string | null; + /** @enum {string} */ + status?: "OUTDATED"; + abortCause?: string | null; + message?: string | null; + /** Format: uuid */ + testCaseId?: string; + lastJobExecutionName?: string | null; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + executedTestCaseElements?: string[]; + testCase?: { + /** Format: uuid */ + id?: string; + /** Format: uuid */ + testTargetId?: string; + description?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + entryPointUrlPath?: string | null; + type?: string | null; + /** @enum {string} */ + status?: "ENABLED"; + /** @enum {string} */ + runStatus?: "ON"; + /** @enum {string} */ + interactionStatus?: "NEW"; + /** @enum {string} */ + createdBy?: "EDIT"; + proposalRunId?: string | null; + externalId?: string | null; + folderId?: string | null; + prerequisiteId?: string | null; + /** Format: uuid */ + predecessorId?: string; + testTarget?: { + /** Format: uuid */ + id?: string; + app?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: uuid */ + orgId?: string; + testIdAttribute?: string | null; + timeoutPerStep?: number; + }; + }; + }; + }; + }; + }; + /** @description Unauthorized - Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Test target or test case not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/discoveries": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create a discovery + * @description Create a new test case discovery with a given name and prompt + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description The ID of the test target */ + testTargetId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * @description Name of the discovery + * @example foo + */ + name: string; + /** + * @description The prompt describing what to discover + * @example make sure current time is visible + */ + prompt: string; + /** @description Optional URL path for the entry point */ + entryPointUrlPath?: string | null; + /** + * Format: uuid + * @description Optional ID of a prerequisite test case + */ + prerequisiteId?: string | null; + /** @description Optional external identifier */ + externalId?: string | null; + /** @description Optional list of tag IDs to assign */ + assignedTagIds?: string[] | null; + /** + * Format: uuid + * @description Optional ID of the folder to place the discovery in + */ + folderId?: string | null; + }; + }; + }; + responses: { + /** @description Discovery created successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * Format: uuid + * @description The ID of the created discovery + */ + discoveryId: string; + /** + * Format: uuid + * @description The ID of the associated test case + */ + testCaseId: string; + }; + }; + }; + /** @description Invalid request body */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized - Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Test target not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + ExecutionContext: { + /** + * @example github + * @enum {string} + */ + source?: "github"; + /** @example 123 */ + issueNumber?: number | null; + /** @example refs/heads/main */ + ref?: string | null; + /** @example abc123def456 */ + sha?: string | null; + /** @example my-repo */ + repo?: string; + /** @example repo-owner */ + owner?: string; + triggeredBy?: { + /** + * @example USER + * @enum {string} + */ + type?: "USER"; + /** @example user123 */ + userId?: string; + } | null; + /** @example node-123 */ + nodeId?: string | null; + } | { + /** + * @example azureDevOps + * @enum {string} + */ + source?: "azureDevOps"; + /** @example token123 */ + accessToken?: string; + /** @example my-org */ + organization?: string; + /** @example my-project */ + project?: string; + /** @example repo-123 */ + repositoryId?: string; + /** @example abc123def456 */ + sha?: string | null; + /** @example refs/heads/main */ + ref?: string | null; + /** @example 101 */ + pullRequestId?: number | null; + triggeredBy?: { + /** + * @example USER + * @enum {string} + */ + type?: "USER"; + /** @example user123 */ + userId?: string; + } | null; + /** @example thread-123 */ + threadId?: string | null; + } | { + /** + * @example discovery + * @enum {string} + */ + source?: "discovery"; + /** @example A discovery test */ + description?: string; + triggeredBy?: { + /** + * @example INITIAL + * @enum {string} + */ + type?: "INITIAL"; + } | { + /** + * @example USER + * @enum {string} + */ + type?: "USER"; + /** @example user123 */ + userId?: string; + }; + } | { + /** + * @example manual + * @enum {string} + */ + source?: "manual"; + /** @example A manual trigger */ + description?: string; + triggeredBy?: { + /** + * @example USER + * @enum {string} + */ + type?: "USER"; + /** @example user123 */ + userId?: string; + }; + } | { + /** + * @example scheduled + * @enum {string} + */ + source?: "scheduled"; + triggeredBy?: { + /** + * @example USER + * @enum {string} + */ + type?: "USER"; + /** @example user123 */ + userId?: string; + } | null; + } | { + /** + * @example proposal + * @enum {string} + */ + source?: "proposal"; + /** @example A proposal trigger */ + description?: string; + triggeredBy?: { + /** + * @example INITIAL + * @enum {string} + */ + type?: "INITIAL"; + } | { + /** + * @example USER + * @enum {string} + */ + type?: "USER"; + /** @example user123 */ + userId?: string; + }; + }; + /** + * @description The variables to overwrite exclusively for this test run. + * @example { + * "SPACE_ID": [ + * "64ee32b4-7365-47a6-b5b0-2903b6ad849d" + * ] + * } + */ + Variables: { + [key: string]: string[]; + }; + TestTargetExecutionRequest: { + /** + * Format: uuid + * @description Unique identifier for the testTarget. + * @example 2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc + */ + testTargetId: string; + /** + * Format: uri + * @description The URL of the test target for this run. + * @example https://example.com + */ + url: string; + context: components["schemas"]["ExecutionContext"]; + /** + * Format: environment name + * @description the environment name you want to run your test against + * @default default + */ + environmentName: string; + variablesToOverwrite?: components["schemas"]["Variables"]; + /** + * @default [] + * @example [ + * "tag1", + * "tag2" + * ] + */ + tags: string[]; + }; + TestTargetExecutionResponse: { + /** + * @description The URL the test target was executed. + * @example https://example.com + */ + testReportUrl?: string; + /** + * @description The test report from the run. + * @example some json + */ + testReport?: Record; + }; + TestReportContext: { + /** + * @description The source of the test trigger. + * @example manual + * @enum {string} + */ + source?: "manual"; + /** + * @description The description of the test context. + * @example manual trigger + */ + description?: string; + triggeredBy?: { + /** + * @description The type of entity triggering the test. + * @example USER + * @enum {string} + */ + type?: "USER"; + /** + * Format: uuid + * @description The unique identifier of the user who triggered the test. + * @example 2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc + */ + userId?: string; + }; + }; + TestResult: { + /** + * Format: uuid + * @description Unique identifier for the test result. + * @example 826c15af-644b-4b28-89b4-f50ff34e46b7 + */ + id?: string; + /** + * Format: uuid + * @description Unique identifier of the test report this result belongs to. + * @example 3435918b-3d29-4ebd-8c68-9a540532f45a + */ + testTargetId?: string; + /** + * Format: uuid + * @description Unique identifier of the test case this result belongs to. + * @example 5b844cf1-d597-4048-9e74-7c0f9ce3e2ee + */ + testCaseId?: string; + /** + * Format: date-time + * @description The timestamp when the test result was created. + * @example 2024-09-06T13:01:51.686Z + */ + createdAt?: string; + /** + * Format: date-time + * @description The timestamp when the test result was last updated. + * @example 2024-09-06T13:01:51.686Z + */ + updatedAt?: string; + /** + * @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. + * @enum {string} + */ + status?: "WAITING" | "PASSED" | "FAILED" | "ERROR"; + /** + * @description The error that has occurred during execution - only set if the status is FAILED or ERROR. + * @example TimeoutError: locator.click: Timeout 30000ms exceeded. + */ + errorMessage?: string | null; + /** + * @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 + */ + traceUrl?: string | null; + }; + TestReport: { + /** + * Format: uuid + * @description Unique identifier for the test report. + * @example 826c15af-644b-4b28-89b4-f50ff34e46b7 + */ + id?: string; + /** + * Format: uuid + * @description The unique identifier of the test target. + * @example 3435918b-3d29-4ebd-8c68-9a540532f45a + */ + testTargetId?: string; + /** + * Format: date-time + * @description The timestamp when the test report was created. + * @example 2024-09-06T13:01:51.686Z + */ + createdAt?: string; + /** + * Format: date-time + * @description The timestamp when the test report was last updated. + * @example 2024-09-06T13:01:51.686Z + */ + updatedAt?: string; + /** + * Format: uri + * @description The URL where the test execution was performed. + * @example https://en.wikipedia.org/ + */ + executionUrl?: string; + /** + * @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 + * @enum {string} + */ + status?: "WAITING" | "PASSED" | "FAILED"; + context?: components["schemas"]["TestReportContext"]; + testResults?: components["schemas"]["TestResult"][]; + }; + PrivateLocationInfo: { + /** @enum {string} */ + status: "OFFLINE" | "ONLINE"; + /** + * Format: uri + * @example https://example.com:3128 + */ + address: string; + /** @example my-private-location */ + name: string; + }[]; + TestReportResponse: { + /** + * Format: uri + * @description The URL where the test report can be accessed. + * @example https://app.octomind.dev/testreports/826c15af-644b-4b28-89b4-f50ff34e46b7 + */ + testReportUrl?: string; + testReport?: components["schemas"]["TestReport"]; + }; + SuccessResponse: { + /** + * @description Indicates whether the operation was successful. + * @example true + */ + success?: boolean; + }; + UnregisterRequest: { + name?: string; + }; + RegisterRequest: { + name?: string; + registrationData?: { + /** @example secret22 */ + proxypass?: string; + /** @example user */ + proxyuser?: string; + /** + * @description the address of the remote endpoint. IP and port + * @example 34.45.23.22:23455 + */ + address?: string; + }; + }; + EnvironmentsResponse: components["schemas"]["EnvironmentResponse"][]; + EnvironmentResponse: { + /** Format: uuid */ + id?: string; + name?: string; + /** Format: uuid */ + testTargetId?: string; + /** Format: date-time */ + updatedAt?: string; + type?: string; + /** Format: url */ + discoveryUrl?: string; + additionalHeaderFields?: { + [key: string]: string; + } | null; + testAccount?: { + username?: string; + password?: string; + otpInitializerKey?: string | null; + /** Format: date-time */ + updatedAt?: string; + } | null; + basicAuth?: { + username?: string; + password?: string; + /** Format: date-time */ + updatedAt?: string; + } | null; + privateLocation?: { + /** Format: uuid */ + id?: string; + name?: string; + status?: string; + type?: string; + }; + }; + TestSuiteRequestCommons: { + /** + * Format: uuid + * @description The test case to run before all test cases + */ + beforeAll?: string | null; + /** + * Format: uuid + * @description The test case to run after all test cases + */ + afterAll?: string | null; + /** + * Format: uuid + * @description The test case to run before each test case in the suite + */ + beforeEach?: string | null; + /** + * Format: uuid + * @description The test case to run after each test case in the suite + */ + afterEach?: string | null; + }; + TestSuitePatchRequest: { + /** + * @description The name of the test suite + * @example regression for chat + */ + name?: string | null; + /** + * @description The test cases to include in the suite + * @example [ + * "5b844cf1-d597-4048-9e74-7c0f9ce3e2ee" + * ] + */ + testCases?: string[] | null; + /** + * @description the environment name you want to run your test suite against + * @example default + */ + environmentName?: string | null; + } & components["schemas"]["TestSuiteRequestCommons"]; + TestSuiteCreateRequest: { + /** + * @description The name of the test suite + * @example regression for chat + */ + name?: string; + /** + * @description The test cases to include in the suite + * @example [ + * "5b844cf1-d597-4048-9e74-7c0f9ce3e2ee" + * ] + */ + testCases?: string[]; + /** + * @description the environment name you want to run your test suite against + * @example default + */ + environmentName?: string; + } & components["schemas"]["TestSuiteRequestCommons"]; + TestSuiteResponse: { + /** Format: uuid */ + id?: string; + } & components["schemas"]["TestSuiteCreateRequest"]; + TestSuitesResponse: components["schemas"]["TestSuiteResponse"][]; + ZodResponse: { + /** + * @description What error code happened while parsing the request + * @example invalid_type + */ + code?: string; + /** + * @description What the expected type was + * @example object + */ + expected?: string; + /** + * @description What the actual passed type was + * @example string + */ + received?: string; + path?: string[]; + /** + * @description Human-readable message of the error that occurred while parsing. + * @example Expected object, received string + */ + message?: string; + }[]; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export type operations = Record; diff --git a/src/cli.ts b/src/cli.ts index a8b93c8..f939d3c 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -10,7 +10,7 @@ import { registerLocation, unregisterLocation, updateEnvironment, -} from "./api"; +} from "./tools"; const apiKeyOption = new Option( "-k, --api-key ", @@ -54,7 +54,7 @@ export const buildCmd = (): Command => { createCommandWithCommonOptions("report") .description("Get test report details") .requiredOption("-t, --test-target-id ", "Test target ID") - .requiredOption("-r, --report-id ", "Test report ID") + .requiredOption("-r, --test-report-id ", "Test report ID") .action(getTestReport); createCommandWithCommonOptions("register-location") diff --git a/src/tools.ts b/src/tools.ts new file mode 100644 index 0000000..a48daab --- /dev/null +++ b/src/tools.ts @@ -0,0 +1,318 @@ + +import type { paths, components } from "./api"; // generated by openapi-typescript +import createClient, { Middleware } from "openapi-fetch"; + +export type listEnvironmentsOptions = paths["/apiKey/v2/test-targets/{testTargetId}/environments"]["get"]["parameters"]["path"]; +export type executeTestsBody = components["schemas"]["TestTargetExecutionRequest"]; +export type gettestReportParams = paths["/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}"]["get"]["parameters"]["path"]; +export type TestReport = components["schemas"]["TestReport"]; +export type SuccessResponse = components["schemas"]["SuccessResponse"]; +export type PrivateLocationInfo = components["schemas"]["PrivateLocationInfo"]; +export type EnvironmentRequest = paths["/apiKey/v2/test-targets/{testTargetId}/environments"]["post"]["requestBody"]["content"]["application/json"] & { testTargetId: string }; +export type Environment = components["schemas"]["EnvironmentResponse"]; +export type UpdateEnvironmentOptions = paths["/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}"]["patch"]["requestBody"]["content"]["application/json"]; +export type EnvironmentResponse = components["schemas"]["EnvironmentResponse"]; + +const BASE_URL = "https://app.octomind.dev/api"; + +const client = createClient({ baseUrl: BASE_URL }); + +const authMiddleware: Middleware = { + async onRequest({ request, options }) { + // set "foo" header + const apiKey = process.env.APIKEY; + if (!apiKey) { + throw new Error("APIKEY environment variable is not set"); + } + request.headers.set("x-api-key", apiKey); + return request; + }, +}; +client.use(authMiddleware); + +const handleError = (error: any) => { + if (error) { + console.error(error); + process.exit(1); + } +}; + +export const listEnvironments = async ( + options: listEnvironmentsOptions & { json?: boolean } +): Promise => { + + const { data, error } = await client.GET("/apiKey/v2/test-targets/{testTargetId}/environments", { + params: { + path: { testTargetId: options.testTargetId }, + } + } ); + + handleError(error); + + if (options.json) { + outputResult(data); + return; + } + + console.log("Environments:"); + if( data ) { + data.forEach((environment) => { + console.log(`- Name: ${environment.name}`); + console.log(` ID: ${environment.id}`); + console.log(` Discovery URL: ${environment.discoveryUrl}`); + console.log(` Updated At: ${environment.updatedAt}`); + }); + } +}; + +const outputResult = (result: unknown): void => { + console.log(JSON.stringify(result, null, 2)); +}; + + +export const executeTests = async ( + options: executeTestsBody & { json?: boolean, description?: string } +): Promise => { + + const { data, error } = await client.POST("/apiKey/v2/execute", { + body: { + testTargetId: options.testTargetId, + url: options.url, + context: { + source: "manual", + description: options.description || "CLI execution", + triggeredBy: { + type: "USER", + userId: "cli-user", + }, + }, + environmentName: options.environmentName, + tags: options.tags, + variablesToOverwrite: options.variablesToOverwrite, + }, + }); + + handleError(error); + + if (options.json) { + outputResult(data); + return; + } + + if( data ) { + console.log("Test execution started successfully!"); + console.log("Test Report URL:", data.testReportUrl); + console.log("Report Status:", data.testReport?.status); + + if (data.testReport?.testResults?.length ?? 0 > 0) { + console.log("\nTest Results:"); + data.testReport?.testResults?.forEach((result) => { + console.log(`- Test ${result.testCaseId}: ${result.status}`); + if (result.errorMessage) { + console.log(` Error: ${result.errorMessage}`); + } + if (result.traceUrl) { + console.log(` Trace: ${result.traceUrl}`); + } + }); + } +} +}; + +export const getTestReport = async ( + options: gettestReportParams & { json?: boolean } +): Promise => { + + const { data, error } = await client.GET("/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}", { + params: { + path: { testTargetId: options.testTargetId, testReportId: options.testReportId }, + } }); + + handleError(error); + + if (options.json) { + outputResult(data); + return; + } + + const response = data as TestReport; + console.log("Test Report Details:"); + console.log("Status:", response.status); + console.log("Execution URL:", response.executionUrl); + + if ((response.testResults ?? []).length > 0) { + console.log("\nTest Results:"); + (response.testResults ?? []).forEach((result) => { + console.log(`- Test ${result.testCaseId}: ${result.status}`); + if (result.errorMessage) { + console.log(` Error: ${result.errorMessage}`); + } + if (result.traceUrl) { + console.log(` Trace: ${result.traceUrl}`); + } + }); + } +}; + + +export const registerLocation = async ( + options:{ address: string, name: string, username: string, password: string, json?: boolean }, +): Promise => { + + const { data, error } = await client.PUT("/apiKey/v1/private-location/register", { + body: { + name: options.name, + registrationData: { + address: options.address, + username: options.username, + password: options.password, + }, + }, + }); + + handleError(error); + + const response = data as SuccessResponse; + + if (options.json) { + outputResult(response); + return; + } + + console.log("Registration result:", response.success ? "Success" : "Failed"); +}; + +export const unregisterLocation = async ( + options: { name: string, json?: boolean } +): Promise => { + + const { data, error } = await client.PUT("/apiKey/v1/private-location/unregister", { + body: { + name: options.name, + } + } + ); + + handleError(error); + const response = data as SuccessResponse; + + if (options.json) { + outputResult(response); + return; + } + + console.log( + "Unregistration result:", + response.success ? "Success" : "Failed", + ); +}; + + +export const listPrivateLocations = async ( + options: { json?: boolean }, +): Promise => { + const { data, error } = await client.GET("/apiKey/v1/private-location"); + + handleError(error); + + const response = data as PrivateLocationInfo; + if (options.json) { + outputResult(response); + return; + } + + console.log("Private Locations:"); + response.forEach((location) => { + console.log(`- Name: ${location.name}`); + console.log(` Status: ${location.status}`); + console.log(` Address: ${location.address}`); + }); +}; + + +export const createEnvironment = async ( + options: EnvironmentRequest & { json?: boolean }, +): Promise => { + + const { data, error } = await client.POST("/apiKey/v2/test-targets/{testTargetId}/environments", { + params: { + path: { testTargetId: options.testTargetId }, + }, + body: { + name: options.name, + discoveryUrl: options.discoveryUrl, + testAccount: options.testAccount, + basicAuth: options.basicAuth, + privateLocationName: options.privateLocationName, + additionalHeaderFields: options.additionalHeaderFields, + }, + }); + + handleError(error); + + const response = data as Environment; + + if (options.json) { + outputResult(response); + return; + } + + console.log("Environment created successfully!"); + console.log(`- Name: ${response.name}`); + console.log(` ID: ${response.id}`); + console.log(` Discovery URL: ${response.discoveryUrl}`); + console.log(` Updated At: ${response.updatedAt}`); +}; + +export const updateEnvironment = async ( + options: UpdateEnvironmentOptions & { testTargetId: string, environmentId: string, json?: boolean } +): Promise => { + + const { data, error } = await client.PATCH("/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}", { + params: { + path: { testTargetId: options.testTargetId, environmentId: options.environmentId }, + }, + body: { + name: options.name, + discoveryUrl: options.discoveryUrl, + testAccount: options.testAccount, + basicAuth: options.basicAuth, + privateLocationName: options.privateLocationName, + additionalHeaderFields: options.additionalHeaderFields, + }, + }); + + handleError(error); + + const response = data! as EnvironmentResponse; + + if (options.json) { + outputResult(response); + return; + } + + console.log("Environment updated successfully!"); + console.log(`- Name: ${response.name}`); + console.log(` ID: ${response.id}`); + console.log(` Discovery URL: ${response.discoveryUrl}`); + console.log(` Updated At: ${response.updatedAt}`); +}; + +export const deleteEnvironment = async ( + options: { testTargetId: string, environmentId: string, json?: boolean, apiKey?: string } +): Promise => { + const { data, error } = await client.DELETE("/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}", { + params: { + path: { testTargetId: options.testTargetId, environmentId: options.environmentId }, + }, + }); + + handleError(error); + + if (options.json) { + outputResult({ success: true }); + return; + } + + console.log("Environment deleted successfully!"); +}; diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index cba3100..0000000 --- a/src/types.ts +++ /dev/null @@ -1,185 +0,0 @@ -export interface ExecutionContext { - source: - | "manual" - | "github" - | "azureDevOps" - | "discovery" - | "scheduled" - | "proposal"; - description?: string; - triggeredBy?: { - type: "USER" | "INITIAL"; - userId?: string; - }; -} - -export interface TestTargetExecutionRequest { - testTargetId: string; - url: string; - context: ExecutionContext; - environmentName?: string; - tags?: string[]; - variablesToOverwrite?: Record; -} - -export interface TestResult { - id: string; - testTargetId: string; - testCaseId: string; - status: "WAITING" | "PASSED" | "FAILED" | "ERROR"; - errorMessage?: string; - traceUrl?: string; -} - -export interface TestReport { - id: string; - testTargetId: string; - status: "WAITING" | "PASSED" | "FAILED"; - executionUrl: string; - testResults: TestResult[]; -} - -export interface TestReportResponse { - testReportUrl: string; - testReport: TestReport; -} - -export interface RegisterRequest { - name: string; - registrationData: { - proxypass: string; - proxyuser: string; - address: string; - }; -} - -export interface UnregisterRequest { - name: string; -} - -export interface SuccessResponse { - success: boolean; -} - -export interface ExecuteTestsOptions { - apiKey: string; - testTargetId: string; - url: string; - environment?: string; - description?: string; - json?: boolean; - tags?: string[]; - variablesToOverwrite?: Record; -} - -export interface GetTestReportOptions { - apiKey: string; - testTargetId: string; - reportId: string; - json?: boolean; -} - -export interface RegisterLocationOptions { - apiKey: string; - name: string; - proxypass: string; - proxyuser: string; - address: string; - json?: boolean; -} - -export interface UnregisterLocationOptions { - apiKey: string; - name: string; - json?: boolean; -} - -export interface ListPrivateLocationsOptions { - apiKey: string; - json?: boolean; -} - -export interface PrivateLocationInfo { - status: "OFFLINE" | "ONLINE"; - address: string; - name: string; -} - -export interface Environment { - id: string; - name: string; - testTargetId: string; - updatedAt: string; - type: string; - discoveryUrl: string; - additionalHeaderFields?: Record; - testAccount?: { - username: string; - password: string; - otpInitializerKey?: string; - updatedAt: string; - }; - basicAuth?: { - username: string; - password: string; - updatedAt: string; - }; - privateLocation?: { - id: string; - name: string; - status: string; - type: string; - }; -} - -export interface ListEnvironmentsOptions { - apiKey: string; - testTargetId: string; - json?: boolean; -} - -export interface CreateEnvironmentOptions { - apiKey: string; - testTargetId: string; - name: string; - discoveryUrl: string; - testAccount?: { - username: string; - password: string; - otpInitializerKey?: string; - }; - basicAuth?: { - username: string; - password: string; - }; - privateLocationName?: string; - additionalHeaderFields?: Record; - json?: boolean; -} - -export interface UpdateEnvironmentOptions { - apiKey: string; - testTargetId: string; - environmentId: string; - name?: string; - discoveryUrl?: string; - testAccount?: { - username: string; - password: string; - otpInitializerKey?: string; - }; - basicAuth?: { - username: string; - password: string; - }; - privateLocationName?: string; - additionalHeaderFields?: Record; - json?: boolean; -} - -export interface DeleteEnvironmentOptions { - apiKey: string; - testTargetId: string; - environmentId: string; - json?: boolean; -} diff --git a/tests/api.spec.ts b/tests/api.spec.ts deleted file mode 100644 index 5669d04..0000000 --- a/tests/api.spec.ts +++ /dev/null @@ -1,294 +0,0 @@ -import axios from "axios"; -import { - createEnvironment, - deleteEnvironment, - executeTests, - getTestReport, - listEnvironments, - listPrivateLocations, - registerLocation, - unregisterLocation, - updateEnvironment, -} from "../src/api"; -import { - CreateEnvironmentOptions, - DeleteEnvironmentOptions, - ExecuteTestsOptions, - GetTestReportOptions, - ListEnvironmentsOptions, - ListPrivateLocationsOptions, - RegisterLocationOptions, - UnregisterLocationOptions, - UpdateEnvironmentOptions, -} from "../src/types"; - -jest.mock("axios"); -const mockedAxios = jest.mocked(axios); - -describe("CLI Commands", () => { - const apiKey = "test-api-key"; - const BASE_URL = "https://app.octomind.dev"; - afterEach(() => { - jest.clearAllMocks(); - }); - - it("executeTests", async () => { - const options: ExecuteTestsOptions = { - apiKey, - testTargetId: "test-target-id", - url: "https://example.com", - environment: "default", - description: "Test description", - json: true, - }; - - mockedAxios.mockResolvedValue({ - data: { - testReportUrl: "https://example.com", - testReport: { status: "PASSED", testResults: [] }, - }, - }); - - await executeTests(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "post", - url: `${BASE_URL}/api/apiKey/v2/execute`, - data: expect.any(Object), - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); - - it("getTestReport", async () => { - const options: GetTestReportOptions = { - apiKey, - testTargetId: "test-target-id", - reportId: "test-report-id", - json: true, - }; - - mockedAxios.mockResolvedValue({ - data: { - status: "PASSED", - executionUrl: "https://example.com", - testResults: [], - }, - }); - - await getTestReport(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "get", - url: `${BASE_URL}/api/apiKey/v2/test-targets/test-target-id/test-reports/test-report-id`, - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); - - it("registerLocation", async () => { - const options: RegisterLocationOptions = { - apiKey, - name: "test-location", - proxypass: "password", - proxyuser: "user", - address: "address", - json: true, - }; - - mockedAxios.mockResolvedValue({ data: { success: true } }); - - await registerLocation(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "put", - url: `${BASE_URL}/api/apiKey/v1/private-location/register`, - data: expect.any(Object), - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); - - it("unregisterLocation", async () => { - const options: UnregisterLocationOptions = { - apiKey, - name: "test-location", - json: true, - }; - - mockedAxios.mockResolvedValue({ data: { success: true } }); - - await unregisterLocation(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "put", - url: `${BASE_URL}/api/apiKey/v1/private-location/unregister`, - data: expect.any(Object), - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); - - it("listPrivateLocations", async () => { - const options: ListPrivateLocationsOptions = { - apiKey, - json: true, - }; - - mockedAxios.mockResolvedValue({ - data: [{ name: "location1", status: "ONLINE", address: "address1" }], - }); - - await listPrivateLocations(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "get", - url: `${BASE_URL}/api/apiKey/v1/private-location`, - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); - - it("listEnvironments", async () => { - const options: ListEnvironmentsOptions = { - apiKey, - testTargetId: "test-target-id", - json: true, - }; - - mockedAxios.mockResolvedValue({ - data: [ - { - id: "env1", - name: "env1", - discoveryUrl: "https://example.com", - updatedAt: "2023-01-01", - }, - ], - }); - - await listEnvironments(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "get", - url: `${BASE_URL}/api/apiKey/v2/test-targets/test-target-id/environments`, - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); - - it("createEnvironment", async () => { - const options: CreateEnvironmentOptions = { - apiKey, - testTargetId: "test-target-id", - name: "env1", - discoveryUrl: "https://example.com", - json: true, - }; - - mockedAxios.mockResolvedValue({ - data: { - id: "env1", - name: "env1", - discoveryUrl: "https://example.com", - updatedAt: "2023-01-01", - }, - }); - - await createEnvironment(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "post", - url: `${BASE_URL}/api/apiKey/v2/test-targets/test-target-id/environments`, - data: expect.any(Object), - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); - - it("updateEnvironment", async () => { - const options: UpdateEnvironmentOptions = { - apiKey, - testTargetId: "test-target-id", - environmentId: "env1", - name: "env1-updated", - discoveryUrl: "https://example.com", - json: true, - }; - - mockedAxios.mockResolvedValue({ - data: { - id: "env1", - name: "env1-updated", - discoveryUrl: "https://example.com", - updatedAt: "2023-01-01", - }, - }); - - await updateEnvironment(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "patch", - url: `${BASE_URL}/api/apiKey/v2/test-targets/test-target-id/environments/env1`, - data: expect.any(Object), - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); - - it("deleteEnvironment", async () => { - const options: DeleteEnvironmentOptions = { - apiKey, - testTargetId: "test-target-id", - environmentId: "env1", - json: true, - }; - - mockedAxios.mockResolvedValue({ data: { success: true } }); - - await deleteEnvironment(options); - - expect(mockedAxios).toHaveBeenCalledWith( - expect.objectContaining({ - method: "delete", - url: `${BASE_URL}/api/apiKey/v2/test-targets/test-target-id/environments/env1`, - headers: expect.objectContaining({ - "X-API-Key": apiKey, - "Content-Type": "application/json", - }), - }), - ); - }); -}); diff --git a/tests/cli.spec.ts b/tests/cli.spec.ts index 31911d4..06e1ebe 100644 --- a/tests/cli.spec.ts +++ b/tests/cli.spec.ts @@ -1,8 +1,7 @@ import { program } from "commander"; import { buildCmd } from "../src/cli"; -import { executeTests } from "../src/api"; - -jest.mock("../src/api"); +import { executeTests } from "../src/tools"; +jest.mock("../src/tools"); describe("CLI Commands parsing options", () => { const stdArgs = [ From 38c54ab4289a0d5dd4d6ce83db96e1cb05ab9edc Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 14:10:29 +0200 Subject: [PATCH 2/9] fixes update env, rm axios dep --- openapi.yaml | 4 + package.json | 1 - src/api.ts | 4 +- src/tools.ts | 245 +++++++++++++++++++++++++++++---------------------- 4 files changed, 148 insertions(+), 106 deletions(-) diff --git a/openapi.yaml b/openapi.yaml index f57be07..5e1901d 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -809,6 +809,10 @@ paths: responses: '200': description: Environment updated successfully + content: + application/json: + schema: + $ref: "#/components/schemas/EnvironmentResponse" /apiKey/v2/test-targets/{testTargetId}/environments: post: diff --git a/package.json b/package.json index c3b04b0..1d4a692 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "author": "", "license": "MIT", "dependencies": { - "axios": "^1.7.9", "commander": "^14.0.0", "openapi-fetch": "^0.14.0", "tsx": "^4.19.3" diff --git a/src/api.ts b/src/api.ts index 3d2b590..156fa7c 100644 --- a/src/api.ts +++ b/src/api.ts @@ -297,7 +297,9 @@ export interface paths { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["EnvironmentResponse"]; + }; }; }; }; diff --git a/src/tools.ts b/src/tools.ts index a48daab..e312b75 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -1,16 +1,22 @@ - import type { paths, components } from "./api"; // generated by openapi-typescript import createClient, { Middleware } from "openapi-fetch"; -export type listEnvironmentsOptions = paths["/apiKey/v2/test-targets/{testTargetId}/environments"]["get"]["parameters"]["path"]; -export type executeTestsBody = components["schemas"]["TestTargetExecutionRequest"]; -export type gettestReportParams = paths["/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}"]["get"]["parameters"]["path"]; +export type listEnvironmentsOptions = + paths["/apiKey/v2/test-targets/{testTargetId}/environments"]["get"]["parameters"]["path"]; +export type executeTestsBody = + components["schemas"]["TestTargetExecutionRequest"]; +export type gettestReportParams = + paths["/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}"]["get"]["parameters"]["path"]; export type TestReport = components["schemas"]["TestReport"]; export type SuccessResponse = components["schemas"]["SuccessResponse"]; export type PrivateLocationInfo = components["schemas"]["PrivateLocationInfo"]; -export type EnvironmentRequest = paths["/apiKey/v2/test-targets/{testTargetId}/environments"]["post"]["requestBody"]["content"]["application/json"] & { testTargetId: string }; +export type EnvironmentRequest = + paths["/apiKey/v2/test-targets/{testTargetId}/environments"]["post"]["requestBody"]["content"]["application/json"] & { + testTargetId: string; + }; export type Environment = components["schemas"]["EnvironmentResponse"]; -export type UpdateEnvironmentOptions = paths["/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}"]["patch"]["requestBody"]["content"]["application/json"]; +export type UpdateEnvironmentOptions = + paths["/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}"]["patch"]["requestBody"]["content"]["application/json"]; export type EnvironmentResponse = components["schemas"]["EnvironmentResponse"]; const BASE_URL = "https://app.octomind.dev/api"; @@ -18,7 +24,7 @@ const BASE_URL = "https://app.octomind.dev/api"; const client = createClient({ baseUrl: BASE_URL }); const authMiddleware: Middleware = { - async onRequest({ request, options }) { + async onRequest({ request }) { // set "foo" header const apiKey = process.env.APIKEY; if (!apiKey) { @@ -38,14 +44,16 @@ const handleError = (error: any) => { }; export const listEnvironments = async ( - options: listEnvironmentsOptions & { json?: boolean } + options: listEnvironmentsOptions & { json?: boolean }, ): Promise => { - - const { data, error } = await client.GET("/apiKey/v2/test-targets/{testTargetId}/environments", { - params: { - path: { testTargetId: options.testTargetId }, - } - } ); + const { data, error } = await client.GET( + "/apiKey/v2/test-targets/{testTargetId}/environments", + { + params: { + path: { testTargetId: options.testTargetId }, + }, + }, + ); handleError(error); @@ -55,7 +63,7 @@ export const listEnvironments = async ( } console.log("Environments:"); - if( data ) { + if (data) { data.forEach((environment) => { console.log(`- Name: ${environment.name}`); console.log(` ID: ${environment.id}`); @@ -69,11 +77,9 @@ const outputResult = (result: unknown): void => { console.log(JSON.stringify(result, null, 2)); }; - export const executeTests = async ( - options: executeTestsBody & { json?: boolean, description?: string } + options: executeTestsBody & { json?: boolean; description?: string }, ): Promise => { - const { data, error } = await client.POST("/apiKey/v2/execute", { body: { testTargetId: options.testTargetId, @@ -99,34 +105,40 @@ export const executeTests = async ( return; } - if( data ) { - console.log("Test execution started successfully!"); - console.log("Test Report URL:", data.testReportUrl); - console.log("Report Status:", data.testReport?.status); - - if (data.testReport?.testResults?.length ?? 0 > 0) { - console.log("\nTest Results:"); - data.testReport?.testResults?.forEach((result) => { - console.log(`- Test ${result.testCaseId}: ${result.status}`); - if (result.errorMessage) { - console.log(` Error: ${result.errorMessage}`); - } - if (result.traceUrl) { - console.log(` Trace: ${result.traceUrl}`); - } - }); + if (data) { + console.log("Test execution started successfully!"); + console.log("Test Report URL:", data.testReportUrl); + console.log("Report Status:", data.testReport?.status); + + if (data.testReport?.testResults?.length ?? 0 > 0) { + console.log("\nTest Results:"); + data.testReport?.testResults?.forEach((result) => { + console.log(`- Test ${result.testCaseId}: ${result.status}`); + if (result.errorMessage) { + console.log(` Error: ${result.errorMessage}`); + } + if (result.traceUrl) { + console.log(` Trace: ${result.traceUrl}`); + } + }); + } } -} }; export const getTestReport = async ( - options: gettestReportParams & { json?: boolean } + options: gettestReportParams & { json?: boolean }, ): Promise => { - - const { data, error } = await client.GET("/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}", { - params: { - path: { testTargetId: options.testTargetId, testReportId: options.testReportId }, - } }); + const { data, error } = await client.GET( + "/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}", + { + params: { + path: { + testTargetId: options.testTargetId, + testReportId: options.testReportId, + }, + }, + }, + ); handleError(error); @@ -154,21 +166,26 @@ export const getTestReport = async ( } }; - -export const registerLocation = async ( - options:{ address: string, name: string, username: string, password: string, json?: boolean }, -): Promise => { - - const { data, error } = await client.PUT("/apiKey/v1/private-location/register", { - body: { - name: options.name, - registrationData: { - address: options.address, - username: options.username, - password: options.password, +export const registerLocation = async (options: { + address: string; + name: string; + username: string; + password: string; + json?: boolean; +}): Promise => { + const { data, error } = await client.PUT( + "/apiKey/v1/private-location/register", + { + body: { + name: options.name, + registrationData: { + address: options.address, + username: options.username, + password: options.password, + }, }, }, - }); + ); handleError(error); @@ -182,15 +199,17 @@ export const registerLocation = async ( console.log("Registration result:", response.success ? "Success" : "Failed"); }; -export const unregisterLocation = async ( - options: { name: string, json?: boolean } -): Promise => { - - const { data, error } = await client.PUT("/apiKey/v1/private-location/unregister", { - body: { - name: options.name, - } - } +export const unregisterLocation = async (options: { + name: string; + json?: boolean; +}): Promise => { + const { data, error } = await client.PUT( + "/apiKey/v1/private-location/unregister", + { + body: { + name: options.name, + }, + }, ); handleError(error); @@ -207,10 +226,9 @@ export const unregisterLocation = async ( ); }; - -export const listPrivateLocations = async ( - options: { json?: boolean }, -): Promise => { +export const listPrivateLocations = async (options: { + json?: boolean; +}): Promise => { const { data, error } = await client.GET("/apiKey/v1/private-location"); handleError(error); @@ -229,29 +247,30 @@ export const listPrivateLocations = async ( }); }; - export const createEnvironment = async ( options: EnvironmentRequest & { json?: boolean }, ): Promise => { - - const { data, error } = await client.POST("/apiKey/v2/test-targets/{testTargetId}/environments", { - params: { - path: { testTargetId: options.testTargetId }, - }, - body: { - name: options.name, - discoveryUrl: options.discoveryUrl, - testAccount: options.testAccount, - basicAuth: options.basicAuth, - privateLocationName: options.privateLocationName, - additionalHeaderFields: options.additionalHeaderFields, + const { data, error } = await client.POST( + "/apiKey/v2/test-targets/{testTargetId}/environments", + { + params: { + path: { testTargetId: options.testTargetId }, + }, + body: { + name: options.name, + discoveryUrl: options.discoveryUrl, + testAccount: options.testAccount, + basicAuth: options.basicAuth, + privateLocationName: options.privateLocationName, + additionalHeaderFields: options.additionalHeaderFields, + }, }, - }); + ); handleError(error); const response = data as Environment; - + if (options.json) { outputResult(response); return; @@ -265,26 +284,35 @@ export const createEnvironment = async ( }; export const updateEnvironment = async ( - options: UpdateEnvironmentOptions & { testTargetId: string, environmentId: string, json?: boolean } + options: UpdateEnvironmentOptions & { + testTargetId: string; + environmentId: string; + json?: boolean; + }, ): Promise => { - - const { data, error } = await client.PATCH("/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}", { - params: { - path: { testTargetId: options.testTargetId, environmentId: options.environmentId }, - }, - body: { - name: options.name, - discoveryUrl: options.discoveryUrl, - testAccount: options.testAccount, - basicAuth: options.basicAuth, - privateLocationName: options.privateLocationName, - additionalHeaderFields: options.additionalHeaderFields, + const { data, error } = await client.PATCH( + "/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}", + { + params: { + path: { + testTargetId: options.testTargetId, + environmentId: options.environmentId, + }, + }, + body: { + name: options.name, + discoveryUrl: options.discoveryUrl, + testAccount: options.testAccount, + basicAuth: options.basicAuth, + privateLocationName: options.privateLocationName, + additionalHeaderFields: options.additionalHeaderFields, + }, }, - }); + ); handleError(error); - const response = data! as EnvironmentResponse; + const response = data as EnvironmentResponse; if (options.json) { outputResult(response); @@ -298,14 +326,23 @@ export const updateEnvironment = async ( console.log(` Updated At: ${response.updatedAt}`); }; -export const deleteEnvironment = async ( - options: { testTargetId: string, environmentId: string, json?: boolean, apiKey?: string } -): Promise => { - const { data, error } = await client.DELETE("/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}", { - params: { - path: { testTargetId: options.testTargetId, environmentId: options.environmentId }, +export const deleteEnvironment = async (options: { + testTargetId: string; + environmentId: string; + json?: boolean; + apiKey?: string; +}): Promise => { + const { error } = await client.DELETE( + "/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}", + { + params: { + path: { + testTargetId: options.testTargetId, + environmentId: options.environmentId, + }, + }, }, - }); + ); handleError(error); From ae89899d74b0eb8814610b5e2f263f2b12a7ce7d Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 14:14:56 +0200 Subject: [PATCH 3/9] lint --- src/tools.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools.ts b/src/tools.ts index e312b75..0b14b7b 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -19,6 +19,8 @@ export type UpdateEnvironmentOptions = paths["/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}"]["patch"]["requestBody"]["content"]["application/json"]; export type EnvironmentResponse = components["schemas"]["EnvironmentResponse"]; +export type ErrorResponse = components["schemas"]["ZodResponse"] | undefined; + const BASE_URL = "https://app.octomind.dev/api"; const client = createClient({ baseUrl: BASE_URL }); @@ -36,7 +38,7 @@ const authMiddleware: Middleware = { }; client.use(authMiddleware); -const handleError = (error: any) => { +const handleError = (error: ErrorResponse) => { if (error) { console.error(error); process.exit(1); From 4ac2864071ae1156456d7666d9afd041017b1a75 Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 14:16:07 +0200 Subject: [PATCH 4/9] lock file --- pnpm-lock.yaml | 75 -------------------------------------------------- 1 file changed, 75 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index de9a59f..98d708f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - axios: - specifier: ^1.7.9 - version: 1.10.0 commander: specifier: ^14.0.0 version: 14.0.0 @@ -1129,9 +1126,6 @@ packages: async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1140,9 +1134,6 @@ packages: resolution: {integrity: sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==} engines: {node: '>=4'} - axios@1.10.0: - resolution: {integrity: sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==} - axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -1278,10 +1269,6 @@ packages: colorette@1.4.0: resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - commander@14.0.0: resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} engines: {node: '>=20'} @@ -1363,10 +1350,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -1712,15 +1695,6 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} @@ -1729,10 +1703,6 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - form-data@4.0.3: - resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==} - engines: {node: '>= 6'} - fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -2328,14 +2298,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -2545,9 +2507,6 @@ packages: resolution: {integrity: sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4189,22 +4148,12 @@ snapshots: async@3.2.6: {} - asynckit@0.4.0: {} - available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 axe-core@4.10.2: {} - axios@1.10.0: - dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.3 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - axobject-query@4.1.0: {} babel-jest@30.0.5(@babel/core@7.28.0): @@ -4360,10 +4309,6 @@ snapshots: colorette@1.4.0: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - commander@14.0.0: {} concat-map@0.0.1: {} @@ -4430,8 +4375,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - delayed-stream@1.0.0: {} - detect-newline@3.1.0: {} diff@4.0.2: {} @@ -4928,8 +4871,6 @@ snapshots: flatted@3.3.3: {} - follow-redirects@1.15.9: {} - for-each@0.3.5: dependencies: is-callable: 1.2.7 @@ -4939,14 +4880,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - form-data@4.0.3: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -5736,12 +5669,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - mimic-fn@2.1.0: {} minimatch@3.1.2: @@ -5938,8 +5865,6 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - proxy-from-env@1.1.0: {} - punycode@2.3.1: {} pure-rand@7.0.1: {} From 09ab2e54b9e30203e7c9fd6a58b44066ffc0ec74 Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 14:16:42 +0200 Subject: [PATCH 5/9] remove comment --- src/tools.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools.ts b/src/tools.ts index 0b14b7b..bb836d3 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -27,7 +27,6 @@ const client = createClient({ baseUrl: BASE_URL }); const authMiddleware: Middleware = { async onRequest({ request }) { - // set "foo" header const apiKey = process.env.APIKEY; if (!apiKey) { throw new Error("APIKEY environment variable is not set"); From adcbee085ef89ba9ab5bb063e1f0a65ad10b940e Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 14:18:02 +0200 Subject: [PATCH 6/9] lint --- src/api.ts | 2969 ++++++++++++++++++++++++++-------------------------- 1 file changed, 1499 insertions(+), 1470 deletions(-) diff --git a/src/api.ts b/src/api.ts index 156fa7c..0d5c655 100644 --- a/src/api.ts +++ b/src/api.ts @@ -4,1161 +4,1185 @@ */ export interface paths { - "/apiKey/v2/test-suites": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + "/apiKey/v2/test-suites": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve test suites + * @description get a list of all defined test suites. + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description test suites */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestSuitesResponse"]; + }; }; - /** - * Retrieve test suites - * @description get a list of all defined test suites. - */ - get: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description test suites */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["TestSuitesResponse"]; - }; - }; - }; + }; + }; + put?: never; + /** Create a test suite */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TestSuiteCreateRequest"]; }; - put?: never; - /** Create a test suite */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["TestSuiteCreateRequest"]; - }; - }; - responses: { - /** @description test suites */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["TestSuiteResponse"]; - }; - }; - /** @description Invalid request parameters */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ZodResponse"]; - }; - }; - }; + }; + responses: { + /** @description test suites */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestSuiteResponse"]; + }; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/apiKey/v2/test-suites/{testSuiteId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; }; - get?: never; - put?: never; - post?: never; - /** Delete a test suite */ - delete: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description test suites */ - 204: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["SuccessResponse"]; - }; - }; - /** @description test suite not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-suites/{testSuiteId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** Delete a test suite */ + delete: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description test suites */ + 204: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SuccessResponse"]; + }; }; - options?: never; - head?: never; - /** Update a test suite */ - patch: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["TestSuitePatchRequest"]; - }; - }; - responses: { - /** @description test suites */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["TestSuiteResponse"]; - }; - }; - /** @description Invalid request parameters */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ZodResponse"]; - }; - }; - }; + /** @description test suite not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - trace?: never; + }; }; - "/apiKey/v2/execute": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + options?: never; + head?: never; + /** Update a test suite */ + patch: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TestSuitePatchRequest"]; }; - get?: never; - put?: never; - /** - * 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. - * - */ - post: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["TestTargetExecutionRequest"]; - }; - }; - responses: { - /** @description Test executed successfully */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["TestReportResponse"]; - }; - }; - /** @description Invalid request parameters */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ZodResponse"]; - }; - }; - /** @description Invalid or missing API key */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Internal server error */ - 500: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + }; + responses: { + /** @description test suites */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestSuiteResponse"]; + }; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; + }; + }; + }; + trace?: never; + }; + "/apiKey/v2/execute": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + get?: never; + put?: never; + /** + * 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. + * + */ + post: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["TestTargetExecutionRequest"]; }; - get?: never; - put?: never; - post?: never; - /** Delete an environment */ - delete: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the test target to which the test report belongs to */ - testTargetId: string; - /** @description ID of the environment to update */ - environmentId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Environment deleted successfully */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + }; + responses: { + /** @description Test executed successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestReportResponse"]; + }; }; - options?: never; - head?: never; - /** Update an environment */ - patch: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the test target to which the environment belongs to */ - testTargetId: string; - /** @description ID of the environment to update */ - environmentId: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - name?: string | null; - /** Format: url */ - discoveryUrl?: string | null; - testAccount?: { - username?: string; - password?: string; - otpInitializerKey?: string | null; - } | null; - basicAuth?: { - username?: string; - password?: string; - } | null; - /** @description name of the private location */ - privateLocationName?: string | null; - additionalHeaderFields?: { - [key: string]: string; - } | null; - }; - }; - }; - responses: { - /** @description Environment updated successfully */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["EnvironmentResponse"]; - }; - }; - }; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; }; - trace?: never; + /** @description Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/apiKey/v2/test-targets/{testTargetId}/environments": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + get?: never; + put?: never; + post?: never; + /** Delete an environment */ + delete: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the test report belongs to */ + testTargetId: string; + /** @description ID of the environment to update */ + environmentId: string; }; - /** - * Retrieve environments - * @description get a list of all defined environments. - */ - get: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the test target to which the test report belongs to */ - testTargetId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description environments */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["EnvironmentsResponse"]; - }; - }; - }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Environment deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - put?: never; - /** - * Create an environment - * @description Create a custom environment. - */ - post: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the test target to which the environment belongs to */ - testTargetId: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - name?: string; - /** Format: url */ - discoveryUrl?: string; - testAccount?: { - username?: string; - password?: string; - otpInitializerKey?: string | null; - } | null; - basicAuth?: { - username?: string; - password?: string; - } | null; - /** @description name of the private location */ - privateLocationName?: string; - additionalHeaderFields?: { - [key: string]: string; - } | null; - }; - }; - }; - responses: { - /** @description environment created */ - 201: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["EnvironmentResponse"]; - }; - }; - }; + }; + }; + options?: never; + head?: never; + /** Update an environment */ + patch: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the environment belongs to */ + testTargetId: string; + /** @description ID of the environment to update */ + environmentId: string; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + name?: string | null; + /** Format: url */ + discoveryUrl?: string | null; + testAccount?: { + username?: string; + password?: string; + otpInitializerKey?: string | null; + } | null; + basicAuth?: { + username?: string; + password?: string; + } | null; + /** @description name of the private location */ + privateLocationName?: string | null; + additionalHeaderFields?: { + [key: string]: string; + } | null; + }; + }; + }; + responses: { + /** @description Environment updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["EnvironmentResponse"]; + }; + }; + }; + }; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/environments": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + /** + * Retrieve environments + * @description get a list of all defined environments. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the test report belongs to */ + testTargetId: string; }; - /** - * Retrieve information about a test report - * @description Poll from within a CI-pipeline to wait for the completion of a report. - */ - get: { - parameters: { - query?: never; - header?: never; - path: { - /** @description ID of the test target to which the test report belongs to */ - testTargetId: string; - /** @description ID of the test report to fetch */ - testReportId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Test Report information */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["TestReport"]; - }; - }; - /** @description Invalid request parameters */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ZodResponse"]; - }; - }; - /** @description Invalid or missing API key */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Internal server error */ - 500: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description environments */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["EnvironmentsResponse"]; + }; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; }; - "/apiKey/v2/test-targets/{testTargetId}/test-reports": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + put?: never; + /** + * Create an environment + * @description Create a custom environment. + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the environment belongs to */ + testTargetId: string; }; - /** - * Retrieve paginated information about test reports - * @description Allow fetching the history of test reports for your test target. - */ - get: { - parameters: { - query?: { - key?: { - /** - * 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 - */ - createdAt?: string; - }; - filter?: { - /** - * @description The name of the property to filter for, e.g. an environmentId - * @example environmentId - */ - key?: string; - /** - * @description How to compare the property in question, only EQUALS is supported so far. - * @enum {string} - */ - operator?: "EQUALS"; - /** - * Format: uuid - * @description The value to compare with to find matches. - * @example 3435918b-3d29-4ebd-8c68-9a540532f45a - */ - value?: string; - }[]; - }; - header?: never; - path: { - /** @description ID of the test target for which to fetch the history for */ - testTargetId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Test Reports information */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - data?: components["schemas"]["TestReport"][]; - key?: { - /** - * 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 - */ - createdAt?: string; - }; - /** @description If the query in question has another page to retrieve */ - hasNextPage?: boolean; - }; - }; - }; - /** @description Invalid request parameters */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["ZodResponse"]; - }; - }; - /** @description Invalid or missing API key */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Internal server error */ - 500: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + name?: string; + /** Format: url */ + discoveryUrl?: string; + testAccount?: { + username?: string; + password?: string; + otpInitializerKey?: string | null; + } | null; + basicAuth?: { + username?: string; + password?: string; + } | null; + /** @description name of the private location */ + privateLocationName?: string; + additionalHeaderFields?: { + [key: string]: string; + } | null; + }; + }; + }; + responses: { + /** @description environment created */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["EnvironmentResponse"]; + }; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; + }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/apiKey/v2/test-targets/{testTargetId}/notifications": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + /** + * Retrieve information about a test report + * @description Poll from within a CI-pipeline to wait for the completion of a report. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description ID of the test target to which the test report belongs to */ + testTargetId: string; + /** @description ID of the test report to fetch */ + testReportId: string; }; - /** - * Retrieve notifications - * @description Get a list of notifications for a specific test target. - */ - get: { - parameters: { - query?: never; - header?: never; - path: { - /** @description The ID of the test target */ - testTargetId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description List of notifications */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** Format: uuid */ - id?: string; - /** Format: uuid */ - testTargetId?: string; - /** Format: date-time */ - createdAt?: string; - /** Format: date-time */ - updatedAt?: string; - payload?: { - failed?: boolean; - context?: components["schemas"]["ExecutionContext"]; - /** Format: uuid */ - testReportId?: string; - /** Format: uuid */ - testCaseId?: string; - }; - /** @enum {string} */ - type?: "REPORT_EXECUTION_FINISHED" | "VALIDATION_PASSED"; - /** @enum {string|null} */ - ack?: "IN_WEB_APP" | null; - }[]; - }; - }; - /** @description Unauthorized - Invalid or missing API key */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Test target not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Test Report information */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["TestReport"]; + }; + }; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; + }; + /** @description Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; }; - "/apiKey/v1/private-location": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/test-reports": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve paginated information about test reports + * @description Allow fetching the history of test reports for your test target. + */ + get: { + parameters: { + query?: { + key?: { + /** + * 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 + */ + createdAt?: string; + }; + filter?: { + /** + * @description The name of the property to filter for, e.g. an environmentId + * @example environmentId + */ + key?: string; + /** + * @description How to compare the property in question, only EQUALS is supported so far. + * @enum {string} + */ + operator?: "EQUALS"; + /** + * Format: uuid + * @description The value to compare with to find matches. + * @example 3435918b-3d29-4ebd-8c68-9a540532f45a + */ + value?: string; + }[]; }; - /** - * Retrieve all private locations - * @description gets a list of private location workers - */ - get: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description OK */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["PrivateLocationInfo"]; - }; - }; + header?: never; + path: { + /** @description ID of the test target for which to fetch the history for */ + testTargetId: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Test Reports information */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + data?: components["schemas"]["TestReport"][]; + key?: { + /** + * 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 + */ + createdAt?: string; + }; + /** @description If the query in question has another page to retrieve */ + hasNextPage?: boolean; }; + }; + }; + /** @description Invalid request parameters */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZodResponse"]; + }; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + /** @description Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/notifications": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/apiKey/v1/private-location/register": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + /** + * Retrieve notifications + * @description Get a list of notifications for a specific test target. + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description The ID of the test target */ + testTargetId: string; }; - get?: never; - /** - * Register a private location - * @description registers a private location worker - */ - put: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["RegisterRequest"]; - }; - }; - responses: { - /** @description OK */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["SuccessResponse"]; - }; - }; - /** @description private location of that name not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Internal server error */ - 500: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List of notifications */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** Format: uuid */ + id?: string; + /** Format: uuid */ + testTargetId?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + payload?: { + failed?: boolean; + context?: components["schemas"]["ExecutionContext"]; + /** Format: uuid */ + testReportId?: string; + /** Format: uuid */ + testCaseId?: string; + }; + /** @enum {string} */ + type?: "REPORT_EXECUTION_FINISHED" | "VALIDATION_PASSED"; + /** @enum {string|null} */ + ack?: "IN_WEB_APP" | null; + }[]; + }; + }; + /** @description Unauthorized - Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Test target not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + }; }; - "/apiKey/v1/private-location/unregister": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v1/private-location": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve all private locations + * @description gets a list of private location workers + */ + get: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PrivateLocationInfo"]; + }; }; - get?: never; - /** - * Unregister a private location - * @description Unregisters a private location worker. - */ - put: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["UnregisterRequest"]; - }; - }; - responses: { - /** @description OK */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["SuccessResponse"]; - }; - }; - /** @description private location of that name not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Internal server error */ - 500: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v1/private-location/register": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Register a private location + * @description registers a private location worker + */ + put: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["RegisterRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SuccessResponse"]; + }; + }; + /** @description private location of that name not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v1/private-location/unregister": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/apiKey/v2/test-targets/{testTargetId}/test-cases/{testCaseId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + get?: never; + /** + * Unregister a private location + * @description Unregisters a private location worker. + */ + put: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UnregisterRequest"]; }; - /** - * Retrieve a test case - * @description Get detailed information about a specific test case - */ - get: { - parameters: { - query?: never; - header?: never; - path: { - /** @description The ID of the test target */ - testTargetId: string; - /** @description The ID of the test case */ - testCaseId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description Test case details */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** Format: uuid */ - id?: string; - /** Format: uuid */ - testTargetId?: string; - type?: string | null; - elements?: { - /** Format: uuid */ - id?: string; - index?: number; - interaction?: { - /** Format: uuid */ - id?: string; - /** @enum {string} */ - action?: "EXTRACT" | "ENTER_TEXT" | "CLICK" | "SELECT_OPTION" | "TYPE_TEXT" | "KEY_PRESS" | "HOVER" | "UPLOAD" | "GO_TO" | "DRAG_AND_DROP" | "CLOSE_PAGE" | "OPEN_EMAIL"; - calledWith?: string | null; - /** Format: uuid */ - testCaseElementId?: string; - } | null; - assertion?: { - /** Format: uuid */ - id?: string; - /** @enum {string} */ - expectation?: "VISIBLE" | "NOT_VISIBLE" | "TO_BE_CHECKED" | "NOT_TO_BE_CHECKED" | "TO_HAVE_VALUE" | "TO_CONTAIN_TEXT" | "TO_HAVE_STYLE"; - calledWith?: string | null; - /** Format: uuid */ - testCaseElementId?: string; - } | null; - scrollState?: Record | null; - selectors?: { - /** Format: uuid */ - id?: string; - index?: number; - selector?: string; - /** @enum {string} */ - selectorType?: "TEXT" | "LABEL" | "PLACEHOLDER" | "ROLE"; - options?: { - name?: string; - } | null; - /** Format: uuid */ - testCaseElementId?: string; - scrollStateId?: string | null; - }[]; - /** Format: uuid */ - testCaseId?: string; - ignoreFailure?: boolean; - }[]; - /** Format: date-time */ - createdAt?: string; - /** Format: date-time */ - updatedAt?: string; - description?: string; - /** @enum {string} */ - status?: "ENABLED" | "DRAFT"; - externalId?: string | null; - entryPointUrlPath?: string | null; - tags?: string[]; - /** @enum {string} */ - createdBy?: "EDIT"; - /** @enum {string} */ - runStatus?: "ON" | "OFF"; - prerequisiteId?: string | null; - proposalRunId?: string | null; - folderId?: string | null; - discovery?: { - /** Format: uuid */ - id?: string; - freePrompt?: string; - traceUrl?: string | null; - traceJsonManifestUrl?: string | null; - /** @enum {string} */ - status?: "OUTDATED"; - abortCause?: string | null; - message?: string | null; - /** Format: uuid */ - testCaseId?: string; - lastJobExecutionName?: string | null; - /** Format: date-time */ - createdAt?: string; - /** Format: date-time */ - updatedAt?: string; - executedTestCaseElements?: string[]; - testCase?: { - /** Format: uuid */ - id?: string; - /** Format: uuid */ - testTargetId?: string; - description?: string; - /** Format: date-time */ - createdAt?: string; - /** Format: date-time */ - updatedAt?: string; - entryPointUrlPath?: string | null; - type?: string | null; - /** @enum {string} */ - status?: "ENABLED"; - /** @enum {string} */ - runStatus?: "ON"; - /** @enum {string} */ - interactionStatus?: "NEW"; - /** @enum {string} */ - createdBy?: "EDIT"; - proposalRunId?: string | null; - externalId?: string | null; - folderId?: string | null; - prerequisiteId?: string | null; - /** Format: uuid */ - predecessorId?: string; - testTarget?: { - /** Format: uuid */ - id?: string; - app?: string; - /** Format: date-time */ - createdAt?: string; - /** Format: date-time */ - updatedAt?: string; - /** Format: uuid */ - orgId?: string; - testIdAttribute?: string | null; - timeoutPerStep?: number; - }; - }; - }; - }; - }; - }; - /** @description Unauthorized - Invalid or missing API key */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Test target or test case not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SuccessResponse"]; + }; }; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + /** @description private location of that name not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/test-cases/{testCaseId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; }; - "/apiKey/v2/test-targets/{testTargetId}/discoveries": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; + /** + * Retrieve a test case + * @description Get detailed information about a specific test case + */ + get: { + parameters: { + query?: never; + header?: never; + path: { + /** @description The ID of the test target */ + testTargetId: string; + /** @description The ID of the test case */ + testCaseId: string; }; - get?: never; - put?: never; - /** - * Create a discovery - * @description Create a new test case discovery with a given name and prompt - */ - post: { - parameters: { - query?: never; - header?: never; - path: { - /** @description The ID of the test target */ - testTargetId: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": { - /** - * @description Name of the discovery - * @example foo - */ - name: string; - /** - * @description The prompt describing what to discover - * @example make sure current time is visible - */ - prompt: string; - /** @description Optional URL path for the entry point */ - entryPointUrlPath?: string | null; - /** - * Format: uuid - * @description Optional ID of a prerequisite test case - */ - prerequisiteId?: string | null; - /** @description Optional external identifier */ - externalId?: string | null; - /** @description Optional list of tag IDs to assign */ - assignedTagIds?: string[] | null; - /** - * Format: uuid - * @description Optional ID of the folder to place the discovery in - */ - folderId?: string | null; - }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Test case details */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** Format: uuid */ + id?: string; + /** Format: uuid */ + testTargetId?: string; + type?: string | null; + elements?: { + /** Format: uuid */ + id?: string; + index?: number; + interaction?: { + /** Format: uuid */ + id?: string; + /** @enum {string} */ + action?: + | "EXTRACT" + | "ENTER_TEXT" + | "CLICK" + | "SELECT_OPTION" + | "TYPE_TEXT" + | "KEY_PRESS" + | "HOVER" + | "UPLOAD" + | "GO_TO" + | "DRAG_AND_DROP" + | "CLOSE_PAGE" + | "OPEN_EMAIL"; + calledWith?: string | null; + /** Format: uuid */ + testCaseElementId?: string; + } | null; + assertion?: { + /** Format: uuid */ + id?: string; + /** @enum {string} */ + expectation?: + | "VISIBLE" + | "NOT_VISIBLE" + | "TO_BE_CHECKED" + | "NOT_TO_BE_CHECKED" + | "TO_HAVE_VALUE" + | "TO_CONTAIN_TEXT" + | "TO_HAVE_STYLE"; + calledWith?: string | null; + /** Format: uuid */ + testCaseElementId?: string; + } | null; + scrollState?: Record | null; + selectors?: { + /** Format: uuid */ + id?: string; + index?: number; + selector?: string; + /** @enum {string} */ + selectorType?: "TEXT" | "LABEL" | "PLACEHOLDER" | "ROLE"; + options?: { + name?: string; + } | null; + /** Format: uuid */ + testCaseElementId?: string; + scrollStateId?: string | null; + }[]; + /** Format: uuid */ + testCaseId?: string; + ignoreFailure?: boolean; + }[]; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + description?: string; + /** @enum {string} */ + status?: "ENABLED" | "DRAFT"; + externalId?: string | null; + entryPointUrlPath?: string | null; + tags?: string[]; + /** @enum {string} */ + createdBy?: "EDIT"; + /** @enum {string} */ + runStatus?: "ON" | "OFF"; + prerequisiteId?: string | null; + proposalRunId?: string | null; + folderId?: string | null; + discovery?: { + /** Format: uuid */ + id?: string; + freePrompt?: string; + traceUrl?: string | null; + traceJsonManifestUrl?: string | null; + /** @enum {string} */ + status?: "OUTDATED"; + abortCause?: string | null; + message?: string | null; + /** Format: uuid */ + testCaseId?: string; + lastJobExecutionName?: string | null; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + executedTestCaseElements?: string[]; + testCase?: { + /** Format: uuid */ + id?: string; + /** Format: uuid */ + testTargetId?: string; + description?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + entryPointUrlPath?: string | null; + type?: string | null; + /** @enum {string} */ + status?: "ENABLED"; + /** @enum {string} */ + runStatus?: "ON"; + /** @enum {string} */ + interactionStatus?: "NEW"; + /** @enum {string} */ + createdBy?: "EDIT"; + proposalRunId?: string | null; + externalId?: string | null; + folderId?: string | null; + prerequisiteId?: string | null; + /** Format: uuid */ + predecessorId?: string; + testTarget?: { + /** Format: uuid */ + id?: string; + app?: string; + /** Format: date-time */ + createdAt?: string; + /** Format: date-time */ + updatedAt?: string; + /** Format: uuid */ + orgId?: string; + testIdAttribute?: string | null; + timeoutPerStep?: number; + }; }; + }; }; - responses: { - /** @description Discovery created successfully */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": { - /** - * Format: uuid - * @description The ID of the created discovery - */ - discoveryId: string; - /** - * Format: uuid - * @description The ID of the associated test case - */ - testCaseId: string; - }; - }; - }; - /** @description Invalid request body */ - 400: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Unauthorized - Invalid or missing API key */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Test target not found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; + }; + }; + /** @description Unauthorized - Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Test target or test case not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/apiKey/v2/test-targets/{testTargetId}/discoveries": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create a discovery + * @description Create a new test case discovery with a given name and prompt + */ + post: { + parameters: { + query?: never; + header?: never; + path: { + /** @description The ID of the test target */ + testTargetId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": { + /** + * @description Name of the discovery + * @example foo + */ + name: string; + /** + * @description The prompt describing what to discover + * @example make sure current time is visible + */ + prompt: string; + /** @description Optional URL path for the entry point */ + entryPointUrlPath?: string | null; + /** + * Format: uuid + * @description Optional ID of a prerequisite test case + */ + prerequisiteId?: string | null; + /** @description Optional external identifier */ + externalId?: string | null; + /** @description Optional list of tag IDs to assign */ + assignedTagIds?: string[] | null; + /** + * Format: uuid + * @description Optional ID of the folder to place the discovery in + */ + folderId?: string | null; + }; + }; + }; + responses: { + /** @description Discovery created successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + /** + * Format: uuid + * @description The ID of the created discovery + */ + discoveryId: string; + /** + * Format: uuid + * @description The ID of the associated test case + */ + testCaseId: string; }; + }; + }; + /** @description Invalid request body */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; }; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; + /** @description Unauthorized - Invalid or missing API key */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Test target not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; }; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; } export type webhooks = Record; export interface components { - schemas: { - ExecutionContext: { + schemas: { + ExecutionContext: + | { + /** + * @example github + * @enum {string} + */ + source?: "github"; + /** @example 123 */ + issueNumber?: number | null; + /** @example refs/heads/main */ + ref?: string | null; + /** @example abc123def456 */ + sha?: string | null; + /** @example my-repo */ + repo?: string; + /** @example repo-owner */ + owner?: string; + triggeredBy?: { /** - * @example github + * @example USER * @enum {string} */ - source?: "github"; - /** @example 123 */ - issueNumber?: number | null; - /** @example refs/heads/main */ - ref?: string | null; - /** @example abc123def456 */ - sha?: string | null; - /** @example my-repo */ - repo?: string; - /** @example repo-owner */ - owner?: string; - triggeredBy?: { - /** - * @example USER - * @enum {string} - */ - type?: "USER"; - /** @example user123 */ - userId?: string; - } | null; - /** @example node-123 */ - nodeId?: string | null; - } | { + type?: "USER"; + /** @example user123 */ + userId?: string; + } | null; + /** @example node-123 */ + nodeId?: string | null; + } + | { + /** + * @example azureDevOps + * @enum {string} + */ + source?: "azureDevOps"; + /** @example token123 */ + accessToken?: string; + /** @example my-org */ + organization?: string; + /** @example my-project */ + project?: string; + /** @example repo-123 */ + repositoryId?: string; + /** @example abc123def456 */ + sha?: string | null; + /** @example refs/heads/main */ + ref?: string | null; + /** @example 101 */ + pullRequestId?: number | null; + triggeredBy?: { /** - * @example azureDevOps + * @example USER * @enum {string} */ - source?: "azureDevOps"; - /** @example token123 */ - accessToken?: string; - /** @example my-org */ - organization?: string; - /** @example my-project */ - project?: string; - /** @example repo-123 */ - repositoryId?: string; - /** @example abc123def456 */ - sha?: string | null; - /** @example refs/heads/main */ - ref?: string | null; - /** @example 101 */ - pullRequestId?: number | null; - triggeredBy?: { - /** - * @example USER - * @enum {string} - */ - type?: "USER"; - /** @example user123 */ - userId?: string; - } | null; - /** @example thread-123 */ - threadId?: string | null; - } | { - /** - * @example discovery - * @enum {string} - */ - source?: "discovery"; - /** @example A discovery test */ - description?: string; - triggeredBy?: { + type?: "USER"; + /** @example user123 */ + userId?: string; + } | null; + /** @example thread-123 */ + threadId?: string | null; + } + | { + /** + * @example discovery + * @enum {string} + */ + source?: "discovery"; + /** @example A discovery test */ + description?: string; + triggeredBy?: + | { /** * @example INITIAL * @enum {string} */ type?: "INITIAL"; - } | { + } + | { /** * @example USER * @enum {string} @@ -1166,54 +1190,59 @@ export interface components { type?: "USER"; /** @example user123 */ userId?: string; - }; - } | { - /** - * @example manual - * @enum {string} - */ - source?: "manual"; - /** @example A manual trigger */ - description?: string; - triggeredBy?: { - /** - * @example USER - * @enum {string} - */ - type?: "USER"; - /** @example user123 */ - userId?: string; - }; - } | { + }; + } + | { + /** + * @example manual + * @enum {string} + */ + source?: "manual"; + /** @example A manual trigger */ + description?: string; + triggeredBy?: { /** - * @example scheduled + * @example USER * @enum {string} */ - source?: "scheduled"; - triggeredBy?: { - /** - * @example USER - * @enum {string} - */ - type?: "USER"; - /** @example user123 */ - userId?: string; - } | null; - } | { + type?: "USER"; + /** @example user123 */ + userId?: string; + }; + } + | { + /** + * @example scheduled + * @enum {string} + */ + source?: "scheduled"; + triggeredBy?: { /** - * @example proposal + * @example USER * @enum {string} */ - source?: "proposal"; - /** @example A proposal trigger */ - description?: string; - triggeredBy?: { + type?: "USER"; + /** @example user123 */ + userId?: string; + } | null; + } + | { + /** + * @example proposal + * @enum {string} + */ + source?: "proposal"; + /** @example A proposal trigger */ + description?: string; + triggeredBy?: + | { /** * @example INITIAL * @enum {string} */ type?: "INITIAL"; - } | { + } + | { /** * @example USER * @enum {string} @@ -1221,348 +1250,348 @@ export interface components { type?: "USER"; /** @example user123 */ userId?: string; - }; + }; }; + /** + * @description The variables to overwrite exclusively for this test run. + * @example { + * "SPACE_ID": [ + * "64ee32b4-7365-47a6-b5b0-2903b6ad849d" + * ] + * } + */ + Variables: { + [key: string]: string[]; + }; + TestTargetExecutionRequest: { + /** + * Format: uuid + * @description Unique identifier for the testTarget. + * @example 2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc + */ + testTargetId: string; + /** + * Format: uri + * @description The URL of the test target for this run. + * @example https://example.com + */ + url: string; + context: components["schemas"]["ExecutionContext"]; + /** + * Format: environment name + * @description the environment name you want to run your test against + * @default default + */ + environmentName: string; + variablesToOverwrite?: components["schemas"]["Variables"]; + /** + * @default [] + * @example [ + * "tag1", + * "tag2" + * ] + */ + tags: string[]; + }; + TestTargetExecutionResponse: { + /** + * @description The URL the test target was executed. + * @example https://example.com + */ + testReportUrl?: string; + /** + * @description The test report from the run. + * @example some json + */ + testReport?: Record; + }; + TestReportContext: { + /** + * @description The source of the test trigger. + * @example manual + * @enum {string} + */ + source?: "manual"; + /** + * @description The description of the test context. + * @example manual trigger + */ + description?: string; + triggeredBy?: { /** - * @description The variables to overwrite exclusively for this test run. - * @example { - * "SPACE_ID": [ - * "64ee32b4-7365-47a6-b5b0-2903b6ad849d" - * ] - * } + * @description The type of entity triggering the test. + * @example USER + * @enum {string} */ - Variables: { - [key: string]: string[]; - }; - TestTargetExecutionRequest: { - /** - * Format: uuid - * @description Unique identifier for the testTarget. - * @example 2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc - */ - testTargetId: string; - /** - * Format: uri - * @description The URL of the test target for this run. - * @example https://example.com - */ - url: string; - context: components["schemas"]["ExecutionContext"]; - /** - * Format: environment name - * @description the environment name you want to run your test against - * @default default - */ - environmentName: string; - variablesToOverwrite?: components["schemas"]["Variables"]; - /** - * @default [] - * @example [ - * "tag1", - * "tag2" - * ] - */ - tags: string[]; - }; - TestTargetExecutionResponse: { - /** - * @description The URL the test target was executed. - * @example https://example.com - */ - testReportUrl?: string; - /** - * @description The test report from the run. - * @example some json - */ - testReport?: Record; - }; - TestReportContext: { - /** - * @description The source of the test trigger. - * @example manual - * @enum {string} - */ - source?: "manual"; - /** - * @description The description of the test context. - * @example manual trigger - */ - description?: string; - triggeredBy?: { - /** - * @description The type of entity triggering the test. - * @example USER - * @enum {string} - */ - type?: "USER"; - /** - * Format: uuid - * @description The unique identifier of the user who triggered the test. - * @example 2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc - */ - userId?: string; - }; - }; - TestResult: { - /** - * Format: uuid - * @description Unique identifier for the test result. - * @example 826c15af-644b-4b28-89b4-f50ff34e46b7 - */ - id?: string; - /** - * Format: uuid - * @description Unique identifier of the test report this result belongs to. - * @example 3435918b-3d29-4ebd-8c68-9a540532f45a - */ - testTargetId?: string; - /** - * Format: uuid - * @description Unique identifier of the test case this result belongs to. - * @example 5b844cf1-d597-4048-9e74-7c0f9ce3e2ee - */ - testCaseId?: string; - /** - * Format: date-time - * @description The timestamp when the test result was created. - * @example 2024-09-06T13:01:51.686Z - */ - createdAt?: string; - /** - * Format: date-time - * @description The timestamp when the test result was last updated. - * @example 2024-09-06T13:01:51.686Z - */ - updatedAt?: string; - /** - * @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. - * @enum {string} - */ - status?: "WAITING" | "PASSED" | "FAILED" | "ERROR"; - /** - * @description The error that has occurred during execution - only set if the status is FAILED or ERROR. - * @example TimeoutError: locator.click: Timeout 30000ms exceeded. - */ - errorMessage?: string | null; - /** - * @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 - */ - traceUrl?: string | null; - }; - TestReport: { - /** - * Format: uuid - * @description Unique identifier for the test report. - * @example 826c15af-644b-4b28-89b4-f50ff34e46b7 - */ - id?: string; - /** - * Format: uuid - * @description The unique identifier of the test target. - * @example 3435918b-3d29-4ebd-8c68-9a540532f45a - */ - testTargetId?: string; - /** - * Format: date-time - * @description The timestamp when the test report was created. - * @example 2024-09-06T13:01:51.686Z - */ - createdAt?: string; - /** - * Format: date-time - * @description The timestamp when the test report was last updated. - * @example 2024-09-06T13:01:51.686Z - */ - updatedAt?: string; - /** - * Format: uri - * @description The URL where the test execution was performed. - * @example https://en.wikipedia.org/ - */ - executionUrl?: string; - /** - * @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 - * @enum {string} - */ - status?: "WAITING" | "PASSED" | "FAILED"; - context?: components["schemas"]["TestReportContext"]; - testResults?: components["schemas"]["TestResult"][]; - }; - PrivateLocationInfo: { - /** @enum {string} */ - status: "OFFLINE" | "ONLINE"; - /** - * Format: uri - * @example https://example.com:3128 - */ - address: string; - /** @example my-private-location */ - name: string; - }[]; - TestReportResponse: { - /** - * Format: uri - * @description The URL where the test report can be accessed. - * @example https://app.octomind.dev/testreports/826c15af-644b-4b28-89b4-f50ff34e46b7 - */ - testReportUrl?: string; - testReport?: components["schemas"]["TestReport"]; - }; - SuccessResponse: { - /** - * @description Indicates whether the operation was successful. - * @example true - */ - success?: boolean; - }; - UnregisterRequest: { - name?: string; - }; - RegisterRequest: { - name?: string; - registrationData?: { - /** @example secret22 */ - proxypass?: string; - /** @example user */ - proxyuser?: string; - /** - * @description the address of the remote endpoint. IP and port - * @example 34.45.23.22:23455 - */ - address?: string; - }; - }; - EnvironmentsResponse: components["schemas"]["EnvironmentResponse"][]; - EnvironmentResponse: { - /** Format: uuid */ - id?: string; - name?: string; - /** Format: uuid */ - testTargetId?: string; - /** Format: date-time */ - updatedAt?: string; - type?: string; - /** Format: url */ - discoveryUrl?: string; - additionalHeaderFields?: { - [key: string]: string; - } | null; - testAccount?: { - username?: string; - password?: string; - otpInitializerKey?: string | null; - /** Format: date-time */ - updatedAt?: string; - } | null; - basicAuth?: { - username?: string; - password?: string; - /** Format: date-time */ - updatedAt?: string; - } | null; - privateLocation?: { - /** Format: uuid */ - id?: string; - name?: string; - status?: string; - type?: string; - }; - }; - TestSuiteRequestCommons: { - /** - * Format: uuid - * @description The test case to run before all test cases - */ - beforeAll?: string | null; - /** - * Format: uuid - * @description The test case to run after all test cases - */ - afterAll?: string | null; - /** - * Format: uuid - * @description The test case to run before each test case in the suite - */ - beforeEach?: string | null; - /** - * Format: uuid - * @description The test case to run after each test case in the suite - */ - afterEach?: string | null; - }; - TestSuitePatchRequest: { - /** - * @description The name of the test suite - * @example regression for chat - */ - name?: string | null; - /** - * @description The test cases to include in the suite - * @example [ - * "5b844cf1-d597-4048-9e74-7c0f9ce3e2ee" - * ] - */ - testCases?: string[] | null; - /** - * @description the environment name you want to run your test suite against - * @example default - */ - environmentName?: string | null; - } & components["schemas"]["TestSuiteRequestCommons"]; - TestSuiteCreateRequest: { - /** - * @description The name of the test suite - * @example regression for chat - */ - name?: string; - /** - * @description The test cases to include in the suite - * @example [ - * "5b844cf1-d597-4048-9e74-7c0f9ce3e2ee" - * ] - */ - testCases?: string[]; - /** - * @description the environment name you want to run your test suite against - * @example default - */ - environmentName?: string; - } & components["schemas"]["TestSuiteRequestCommons"]; - TestSuiteResponse: { - /** Format: uuid */ - id?: string; - } & components["schemas"]["TestSuiteCreateRequest"]; - TestSuitesResponse: components["schemas"]["TestSuiteResponse"][]; - ZodResponse: { - /** - * @description What error code happened while parsing the request - * @example invalid_type - */ - code?: string; - /** - * @description What the expected type was - * @example object - */ - expected?: string; - /** - * @description What the actual passed type was - * @example string - */ - received?: string; - path?: string[]; - /** - * @description Human-readable message of the error that occurred while parsing. - * @example Expected object, received string - */ - message?: string; - }[]; + type?: "USER"; + /** + * Format: uuid + * @description The unique identifier of the user who triggered the test. + * @example 2e2bb27b-a19c-47ce-a9b6-cd1bd31622dc + */ + userId?: string; + }; + }; + TestResult: { + /** + * Format: uuid + * @description Unique identifier for the test result. + * @example 826c15af-644b-4b28-89b4-f50ff34e46b7 + */ + id?: string; + /** + * Format: uuid + * @description Unique identifier of the test report this result belongs to. + * @example 3435918b-3d29-4ebd-8c68-9a540532f45a + */ + testTargetId?: string; + /** + * Format: uuid + * @description Unique identifier of the test case this result belongs to. + * @example 5b844cf1-d597-4048-9e74-7c0f9ce3e2ee + */ + testCaseId?: string; + /** + * Format: date-time + * @description The timestamp when the test result was created. + * @example 2024-09-06T13:01:51.686Z + */ + createdAt?: string; + /** + * Format: date-time + * @description The timestamp when the test result was last updated. + * @example 2024-09-06T13:01:51.686Z + */ + updatedAt?: string; + /** + * @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. + * @enum {string} + */ + status?: "WAITING" | "PASSED" | "FAILED" | "ERROR"; + /** + * @description The error that has occurred during execution - only set if the status is FAILED or ERROR. + * @example TimeoutError: locator.click: Timeout 30000ms exceeded. + */ + errorMessage?: string | null; + /** + * @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 + */ + traceUrl?: string | null; + }; + TestReport: { + /** + * Format: uuid + * @description Unique identifier for the test report. + * @example 826c15af-644b-4b28-89b4-f50ff34e46b7 + */ + id?: string; + /** + * Format: uuid + * @description The unique identifier of the test target. + * @example 3435918b-3d29-4ebd-8c68-9a540532f45a + */ + testTargetId?: string; + /** + * Format: date-time + * @description The timestamp when the test report was created. + * @example 2024-09-06T13:01:51.686Z + */ + createdAt?: string; + /** + * Format: date-time + * @description The timestamp when the test report was last updated. + * @example 2024-09-06T13:01:51.686Z + */ + updatedAt?: string; + /** + * Format: uri + * @description The URL where the test execution was performed. + * @example https://en.wikipedia.org/ + */ + executionUrl?: string; + /** + * @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 + * @enum {string} + */ + status?: "WAITING" | "PASSED" | "FAILED"; + context?: components["schemas"]["TestReportContext"]; + testResults?: components["schemas"]["TestResult"][]; + }; + PrivateLocationInfo: { + /** @enum {string} */ + status: "OFFLINE" | "ONLINE"; + /** + * Format: uri + * @example https://example.com:3128 + */ + address: string; + /** @example my-private-location */ + name: string; + }[]; + TestReportResponse: { + /** + * Format: uri + * @description The URL where the test report can be accessed. + * @example https://app.octomind.dev/testreports/826c15af-644b-4b28-89b4-f50ff34e46b7 + */ + testReportUrl?: string; + testReport?: components["schemas"]["TestReport"]; + }; + SuccessResponse: { + /** + * @description Indicates whether the operation was successful. + * @example true + */ + success?: boolean; + }; + UnregisterRequest: { + name?: string; + }; + RegisterRequest: { + name?: string; + registrationData?: { + /** @example secret22 */ + proxypass?: string; + /** @example user */ + proxyuser?: string; + /** + * @description the address of the remote endpoint. IP and port + * @example 34.45.23.22:23455 + */ + address?: string; + }; + }; + EnvironmentsResponse: components["schemas"]["EnvironmentResponse"][]; + EnvironmentResponse: { + /** Format: uuid */ + id?: string; + name?: string; + /** Format: uuid */ + testTargetId?: string; + /** Format: date-time */ + updatedAt?: string; + type?: string; + /** Format: url */ + discoveryUrl?: string; + additionalHeaderFields?: { + [key: string]: string; + } | null; + testAccount?: { + username?: string; + password?: string; + otpInitializerKey?: string | null; + /** Format: date-time */ + updatedAt?: string; + } | null; + basicAuth?: { + username?: string; + password?: string; + /** Format: date-time */ + updatedAt?: string; + } | null; + privateLocation?: { + /** Format: uuid */ + id?: string; + name?: string; + status?: string; + type?: string; + }; + }; + TestSuiteRequestCommons: { + /** + * Format: uuid + * @description The test case to run before all test cases + */ + beforeAll?: string | null; + /** + * Format: uuid + * @description The test case to run after all test cases + */ + afterAll?: string | null; + /** + * Format: uuid + * @description The test case to run before each test case in the suite + */ + beforeEach?: string | null; + /** + * Format: uuid + * @description The test case to run after each test case in the suite + */ + afterEach?: string | null; }; - responses: never; - parameters: never; - requestBodies: never; - headers: never; - pathItems: never; + TestSuitePatchRequest: { + /** + * @description The name of the test suite + * @example regression for chat + */ + name?: string | null; + /** + * @description The test cases to include in the suite + * @example [ + * "5b844cf1-d597-4048-9e74-7c0f9ce3e2ee" + * ] + */ + testCases?: string[] | null; + /** + * @description the environment name you want to run your test suite against + * @example default + */ + environmentName?: string | null; + } & components["schemas"]["TestSuiteRequestCommons"]; + TestSuiteCreateRequest: { + /** + * @description The name of the test suite + * @example regression for chat + */ + name?: string; + /** + * @description The test cases to include in the suite + * @example [ + * "5b844cf1-d597-4048-9e74-7c0f9ce3e2ee" + * ] + */ + testCases?: string[]; + /** + * @description the environment name you want to run your test suite against + * @example default + */ + environmentName?: string; + } & components["schemas"]["TestSuiteRequestCommons"]; + TestSuiteResponse: { + /** Format: uuid */ + id?: string; + } & components["schemas"]["TestSuiteCreateRequest"]; + TestSuitesResponse: components["schemas"]["TestSuiteResponse"][]; + ZodResponse: { + /** + * @description What error code happened while parsing the request + * @example invalid_type + */ + code?: string; + /** + * @description What the expected type was + * @example object + */ + expected?: string; + /** + * @description What the actual passed type was + * @example string + */ + received?: string; + path?: string[]; + /** + * @description Human-readable message of the error that occurred while parsing. + * @example Expected object, received string + */ + message?: string; + }[]; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; } export type $defs = Record; export type operations = Record; From 3410f63b8eb315d0057586185c04e09c80e02958 Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 14:38:44 +0200 Subject: [PATCH 7/9] lint & name mismatches --- src/cli.ts | 12 +++++++----- src/tools.ts | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index f939d3c..4446a02 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -41,7 +41,7 @@ export const buildCmd = (): Command => { .description("Execute test cases") .requiredOption("-t, --test-target-id ", "Test target ID") .requiredOption("-u, --url ", "URL to test") - .option("-e, --environment ", "Environment name", "default") + .option("-e, --environmentName ", "Environment name", "default") .option("-d, --description ", "Test description") .option("-g, --tags ", "comma separated list of tags", splitter) .option( @@ -60,8 +60,8 @@ export const buildCmd = (): Command => { createCommandWithCommonOptions("register-location") .description("Register a private location") .requiredOption("-n, --name ", "Location name") - .requiredOption("-p, --proxypass ", "Proxy password") - .requiredOption("-u, --proxyuser ", "Proxy user") + .requiredOption("-p, --password ", "Proxy password") + .requiredOption("-u, --username ", "Proxy user") .requiredOption("-a, --address
", "Location address") .action(registerLocation); @@ -93,7 +93,10 @@ export const buildCmd = (): Command => { .option("--basic-auth-username ", "Basic auth username") .option("--basic-auth-password ", "Basic auth password") .option("--private-location-name ", "Private location name") - .option("--additional-header-fields ", "Additional header fields") + .option( + "--test-account-otp-initializer-key ", + "Test account OTP initializer key", + ) .action(createEnvironment); createCommandWithCommonOptions("update-environment") @@ -111,7 +114,6 @@ export const buildCmd = (): Command => { .option("--basic-auth-username ", "Basic auth username") .option("--basic-auth-password ", "Basic auth password") .option("--private-location-name ", "Private location name") - .option("--additional-header-fields ", "Additional header fields") .action(updateEnvironment); createCommandWithCommonOptions("delete-environment") diff --git a/src/tools.ts b/src/tools.ts index bb836d3..bcabc4f 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -249,7 +249,15 @@ export const listPrivateLocations = async (options: { }; export const createEnvironment = async ( - options: EnvironmentRequest & { json?: boolean }, + options: EnvironmentRequest & { + json?: boolean; + testAccountUsername?: string; + testAccountPassword?: string; + basicAuthUsername?: string; + basicAuthPassword?: string; + privateLocationName?: string; + testAccountOtpInitializerKey?: string; + }, ): Promise => { const { data, error } = await client.POST( "/apiKey/v2/test-targets/{testTargetId}/environments", @@ -260,8 +268,15 @@ export const createEnvironment = async ( body: { name: options.name, discoveryUrl: options.discoveryUrl, - testAccount: options.testAccount, - basicAuth: options.basicAuth, + testAccount: { + username: options.testAccountUsername, + password: options.testAccountPassword, + }, + basicAuth: { + username: options.basicAuthUsername, + password: options.basicAuthPassword, + }, + testAccountOtpInitializerKey: options.testAccountOtpInitializerKey, privateLocationName: options.privateLocationName, additionalHeaderFields: options.additionalHeaderFields, }, @@ -289,6 +304,12 @@ export const updateEnvironment = async ( testTargetId: string; environmentId: string; json?: boolean; + testAccountUsername?: string; + testAccountPassword?: string; + basicAuthUsername?: string; + basicAuthPassword?: string; + privateLocationName?: string; + testAccountOtpInitializerKey?: string; }, ): Promise => { const { data, error } = await client.PATCH( @@ -303,10 +324,16 @@ export const updateEnvironment = async ( body: { name: options.name, discoveryUrl: options.discoveryUrl, - testAccount: options.testAccount, - basicAuth: options.basicAuth, + testAccount: { + username: options.testAccountUsername, + password: options.testAccountPassword, + }, + otpInitializerKey: options.testAccountOtpInitializerKey, + basicAuth: { + username: options.basicAuthUsername, + password: options.basicAuthPassword, + }, privateLocationName: options.privateLocationName, - additionalHeaderFields: options.additionalHeaderFields, }, }, ); From 0c269e2e56bfc8ac475a93718d72ad1d063cf953 Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 14:43:53 +0200 Subject: [PATCH 8/9] pr comments --- src/cli.ts | 2 +- src/tools.ts | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 4446a02..6047777 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -51,7 +51,7 @@ export const buildCmd = (): Command => { ) .action(executeTests); - createCommandWithCommonOptions("report") + createCommandWithCommonOptions("test-report") .description("Get test report details") .requiredOption("-t, --test-target-id ", "Test target ID") .requiredOption("-r, --test-report-id ", "Test report ID") diff --git a/src/tools.ts b/src/tools.ts index bcabc4f..7af6a08 100644 --- a/src/tools.ts +++ b/src/tools.ts @@ -5,16 +5,16 @@ export type listEnvironmentsOptions = paths["/apiKey/v2/test-targets/{testTargetId}/environments"]["get"]["parameters"]["path"]; export type executeTestsBody = components["schemas"]["TestTargetExecutionRequest"]; -export type gettestReportParams = +export type getTestReportParams = paths["/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}"]["get"]["parameters"]["path"]; export type TestReport = components["schemas"]["TestReport"]; export type SuccessResponse = components["schemas"]["SuccessResponse"]; export type PrivateLocationInfo = components["schemas"]["PrivateLocationInfo"]; -export type EnvironmentRequest = +export type PostEnvironmentOptions = paths["/apiKey/v2/test-targets/{testTargetId}/environments"]["post"]["requestBody"]["content"]["application/json"] & { testTargetId: string; }; -export type Environment = components["schemas"]["EnvironmentResponse"]; + export type UpdateEnvironmentOptions = paths["/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}"]["patch"]["requestBody"]["content"]["application/json"]; export type EnvironmentResponse = components["schemas"]["EnvironmentResponse"]; @@ -127,7 +127,7 @@ export const executeTests = async ( }; export const getTestReport = async ( - options: gettestReportParams & { json?: boolean }, + options: getTestReportParams & { json?: boolean }, ): Promise => { const { data, error } = await client.GET( "/apiKey/v2/test-targets/{testTargetId}/test-reports/{testReportId}", @@ -249,7 +249,7 @@ export const listPrivateLocations = async (options: { }; export const createEnvironment = async ( - options: EnvironmentRequest & { + options: PostEnvironmentOptions & { json?: boolean; testAccountUsername?: string; testAccountPassword?: string; @@ -285,7 +285,7 @@ export const createEnvironment = async ( handleError(error); - const response = data as Environment; + const response = data as EnvironmentResponse; if (options.json) { outputResult(response); @@ -358,7 +358,6 @@ export const deleteEnvironment = async (options: { testTargetId: string; environmentId: string; json?: boolean; - apiKey?: string; }): Promise => { const { error } = await client.DELETE( "/apiKey/v2/test-targets/{testTargetId}/environments/{environmentId}", From cbc9bb4e4837db9a6d99d52570b3af3b4041dd38 Mon Sep 17 00:00:00 2001 From: Stefan Rinke Date: Wed, 23 Jul 2025 14:45:24 +0200 Subject: [PATCH 9/9] fix double option --- src/cli.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 6047777..aae21a2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -93,10 +93,6 @@ export const buildCmd = (): Command => { .option("--basic-auth-username ", "Basic auth username") .option("--basic-auth-password ", "Basic auth password") .option("--private-location-name ", "Private location name") - .option( - "--test-account-otp-initializer-key ", - "Test account OTP initializer key", - ) .action(createEnvironment); createCommandWithCommonOptions("update-environment")