Skip to content
This repository was archived by the owner on Jul 14, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ export const buildCmd = (): CompletableCommand => {
.helpGroup("execute")
.requiredOption("-u, --url <url>", "Url the tests should run against")
.option(
"-c, --test-case-id [uuid]",
"Id of the test case you want to run, if not provided will run all test cases in the test target",
"-p, --test-case-path [string]",
"Path of the test case you want to run, if not provided will run all test cases in the test target",
)
.option(
"-e, --environment-id [uuid]",
Expand Down Expand Up @@ -420,7 +420,7 @@ export const buildCmd = (): CompletableCommand => {
)
.addOption(
new Option(
"-d, --dependency-path <path>",
"-d, --dependency-path [path]",
"The path of to test case you want to use as dependency",
),
)
Expand Down
61 changes: 44 additions & 17 deletions src/debugtopus/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import ora from "ora";
import { Open } from "unzipper";

import { OCTOMIND_FOLDER_NAME } from "../constants";
import { findOctomindFolder } from "../helpers";
import {
findOctomindFolder,
getAbsoluteFilePathInOctomindRoot,
} from "../helpers";
import {
getEnvironments,
getPlaywrightCode,
Expand All @@ -21,7 +24,7 @@ import {
} from "../tools";
import { client, handleError } from "../tools/client";
import { SyncTestCase } from "../tools/sync/types";
import { readTestCasesFromDir } from "../tools/sync/yaml";
import { loadTestCase, readTestCasesFromDir } from "../tools/sync/yaml";
import { getRelevantTestCases } from "../tools/yamlMutations/getRelevantTestCases";
import { ensureChromiumIsInstalled } from "./installation";

Expand Down Expand Up @@ -180,19 +183,39 @@ const runTests = async ({
}
};

const getFilteredTestCaseWithDependencies = (
testCases: SyncTestCase[],
filterTestCaseId: string,
): SyncTestCase[] => {
const filteredTestCase = testCases.find(
(testCase) => testCase.id === filterTestCaseId,
);
const getFilteredTestCaseWithDependencies = async ({
testCases,
filterTestCasePath,
octomindRoot,
}: {
testCases: SyncTestCase[];
filterTestCasePath: string;
octomindRoot: string;
}): Promise<{
relevantTestCases: SyncTestCase[];
filterTestCaseId: string;
}> => {
const absoluteTestCaseFilePath = await getAbsoluteFilePathInOctomindRoot({
octomindRoot,
filePath: filterTestCasePath,
});
if (!absoluteTestCaseFilePath) {
throw new Error(
`Could not find ${filterTestCasePath} in folder ${octomindRoot}`,
);
}

const filteredTestCase = loadTestCase(absoluteTestCaseFilePath);
if (!filteredTestCase) {
throw new Error(`Could not find test case with id ${filterTestCaseId}`);
throw new Error(`Could not find test case with id ${filterTestCasePath}`);
}

const testCasesById = Object.fromEntries(testCases.map((tc) => [tc.id, tc]));
return getRelevantTestCases(testCasesById, filteredTestCase);
const relevantTestCases = getRelevantTestCases(
testCasesById,
filteredTestCase,
);
return { relevantTestCases, filterTestCaseId: filteredTestCase.id };
};

export const runDebugtopus = async (options: DebugtopusOptions) => {
Expand Down Expand Up @@ -284,7 +307,7 @@ export const runDebugtopus = async (options: DebugtopusOptions) => {
};

export const executeLocalTestCases = async (
options: DebugtopusOptions,
options: Omit<DebugtopusOptions, "testCaseId"> & { testCasePath?: string },
): Promise<void> => {
const octomindRoot = await findOctomindFolder();
if (!octomindRoot) {
Expand All @@ -296,19 +319,23 @@ export const executeLocalTestCases = async (
const throbber = ora("Generating code").start();

let testCases = readTestCasesFromDir(octomindRoot);
if (options.testCaseId) {
testCases = getFilteredTestCaseWithDependencies(
let filterTestCaseId: string | undefined = undefined;
if (options.testCasePath) {
const filtered = await getFilteredTestCaseWithDependencies({
testCases,
options.testCaseId,
);
filterTestCasePath: options.testCasePath,
octomindRoot,
});
testCases = filtered.relevantTestCases;
filterTestCaseId = filtered.filterTestCaseId;
}

const body = {
testCases,
testTargetId: options.testTargetId,
executionUrl: options.url,
environmentId: options.environmentId,
filterTestCaseIds: options.testCaseId ? [options.testCaseId] : undefined,
filterTestCaseIds: filterTestCaseId ? [filterTestCaseId] : undefined,
};
const { error, response } = await client.POST(
"/apiKey/beta/test-targets/{testTargetId}/code",
Expand Down
50 changes: 39 additions & 11 deletions tests/debugtopus/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ import {
readZipFromResponseBody,
} from "../../src/debugtopus/index";
import { ensureChromiumIsInstalled } from "../../src/debugtopus/installation";
import { findOctomindFolder } from "../../src/helpers";
import {
findOctomindFolder,
getAbsoluteFilePathInOctomindRoot,
} from "../../src/helpers";
import { client } from "../../src/tools/client";
import { getPlaywrightConfig } from "../../src/tools/playwright";
import { readTestCasesFromDir } from "../../src/tools/sync/yaml";
import { loadTestCase, readTestCasesFromDir } from "../../src/tools/sync/yaml";
import { getRelevantTestCases } from "../../src/tools/yamlMutations/getRelevantTestCases";
import { createMockSyncTestCase } from "../mocks";

vi.mock("fs/promises");
Expand All @@ -28,6 +32,7 @@ vi.mock("../../src/tools/sync/yaml");
vi.mock("../../src/tools/playwright");
vi.mock("../../src/debugtopus/installation");
vi.mock("../../src/helpers");
vi.mock("../../src/tools/yamlMutations/getRelevantTestCases");
vi.mock("child_process");
vi.mock("node:stream/promises");
vi.mock("util", () => ({
Expand All @@ -46,6 +51,11 @@ const mockedReadTestCasesFromDir = vi.mocked(readTestCasesFromDir);

const mockedGetPlaywrightConfig = vi.mocked(getPlaywrightConfig);
const mockedEnsureChromiumIsInstalled = vi.mocked(ensureChromiumIsInstalled);
const mockedGetAbsoluteFilePathInOctomindRoot = vi.mocked(
getAbsoluteFilePathInOctomindRoot,
);
const mockedLoadTestCase = vi.mocked(loadTestCase);
const mockedGetRelevantTestCases = vi.mocked(getRelevantTestCases);

describe("debugtopus", () => {
describe("readZipFromResponseBody", () => {
Expand Down Expand Up @@ -282,20 +292,35 @@ describe("debugtopus", () => {
);
});

it("should filter test cases by testCaseId when provided", async () => {
setupExecutionMocks();
mockedReadTestCasesFromDir.mockReturnValue([
it("should filter test cases by testCaseName when provided", async () => {
const targetTestCase = createMockSyncTestCase({ id: "target-id" });
const allTestCases = [
createMockSyncTestCase({ id: "other-1" }),
createMockSyncTestCase({ id: "target-id" }),
targetTestCase,
createMockSyncTestCase({ id: "other-2" }),
]);
];

setupExecutionMocks();
mockedReadTestCasesFromDir.mockReturnValue(allTestCases);
mockedGetAbsoluteFilePathInOctomindRoot.mockResolvedValue(
`${OCTOMIND_ROOT}/target-test.yaml`,
);
mockedLoadTestCase.mockReturnValue(targetTestCase);
mockedGetRelevantTestCases.mockReturnValue([targetTestCase]);

await executeLocalTestCases({
testTargetId: "test-target-id",
url: "https://example.com",
testCaseId: "target-id",
testCasePath: "target-test.yaml",
});

expect(mockedGetAbsoluteFilePathInOctomindRoot).toHaveBeenCalledWith({
octomindRoot: OCTOMIND_ROOT,
filePath: "target-test.yaml",
});
expect(mockedLoadTestCase).toHaveBeenCalledWith(
`${OCTOMIND_ROOT}/target-test.yaml`,
);
expect(mockedClient.POST).toHaveBeenCalledWith(
"/apiKey/beta/test-targets/{testTargetId}/code",
expect.objectContaining({
Expand All @@ -307,19 +332,22 @@ describe("debugtopus", () => {
);
});

it("should throw an error if testCaseId does not match any test case", async () => {
it("should throw an error if testCaseName file is not found", async () => {
vi.mocked(findOctomindFolder).mockResolvedValue(OCTOMIND_ROOT);
mockedReadTestCasesFromDir.mockReturnValue([
createMockSyncTestCase({ id: "test-case-1" }),
]);
mockedGetAbsoluteFilePathInOctomindRoot.mockResolvedValue(null);

await expect(
executeLocalTestCases({
testTargetId: "test-target-id",
url: "https://example.com",
testCaseId: "non-existent-id",
testCasePath: "non-existent.yaml",
}),
).rejects.toThrow("Could not find test case with id non-existent-id");
).rejects.toThrow(
`Could not find non-existent.yaml in folder ${OCTOMIND_ROOT}`,
);
});
});
});