From 5b038e71e7297e1945b7bb0311199b12e26de551 Mon Sep 17 00:00:00 2001
From: stephanieoghenemega-eng
<288002234+stephanieoghenemega-eng@users.noreply.github.com>
Date: Sun, 18 Oct 2026 09:17:04 +0100
Subject: [PATCH] test: component tests for coverage, limits, audit options,
and workflow switching
- Add component tests for coverage option combinations (fixes #200)
- Add component tests for limits option combinations (fixes #199)
- Add component tests for audit option combinations (fixes #198)
- Add component tests for workflow switching across all tabs (fixes #201)
- Update README with workflow verification documentation
---
README.md | 9 ++
src/App.test.tsx | 268 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 277 insertions(+)
diff --git a/README.md b/README.md
index 7995ec8..a651bbb 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,15 @@ A visual companion to [Soroban Testkit](https://github.com/soroban-testkit/testk
The interface does not execute contracts in the browser. Generated commands run locally through `soroban-testkit`, keeping contract tests deterministic and offline as required by the core project.
+## Workflow Testing & Verification
+
+Comprehensive component testing ensures complete coverage of interactive command builder combinations:
+
+- **Coverage Workflow**: Component tests verifying report format selections (`html`, `lcov`, `text`), `--open` flag toggling, path quoting, and combined option configurations.
+- **Limits Workflow**: Component tests verifying `--contract` path resolution (including paths with spaces), custom function identifiers (`--fn`), and ramp parameters (`--ramp`).
+- **Audit Workflow**: Component tests verifying strict mode toggling (`--strict`), contract source paths, and spaces in path arguments.
+- **Workflow Switching**: Component tests ensuring instantaneous tab state changes, workflow description synchronization, dynamic mounting/unmounting of workflow-specific inputs, and seamless clipboard command generation.
+
## Development
```sh
diff --git a/src/App.test.tsx b/src/App.test.tsx
index 8676631..74cdc68 100644
--- a/src/App.test.tsx
+++ b/src/App.test.tsx
@@ -63,3 +63,271 @@ describe("App command copy", () => {
expect(await screen.findByRole("button", { name: "Copied" })).toBeInTheDocument();
});
});
+
+describe("Coverage option combinations component tests (#200)", () => {
+ const originalClipboard = navigator.clipboard;
+
+ afterEach(() => {
+ Object.defineProperty(navigator, "clipboard", {
+ value: originalClipboard,
+ configurable: true,
+ });
+ vi.restoreAllMocks();
+ });
+
+ it("updates format dropdown options (html, lcov, text)", () => {
+ render();
+ const formatSelect = screen.getByLabelText(/report format/i);
+
+ fireEvent.change(formatSelect, { target: { value: "lcov" } });
+ expect(
+ screen.getByText("soroban-testkit coverage . --format lcov --open"),
+ ).toBeInTheDocument();
+
+ fireEvent.change(formatSelect, { target: { value: "text" } });
+ expect(
+ screen.getByText("soroban-testkit coverage . --format text --open"),
+ ).toBeInTheDocument();
+
+ fireEvent.change(formatSelect, { target: { value: "html" } });
+ expect(
+ screen.getByText("soroban-testkit coverage . --format html --open"),
+ ).toBeInTheDocument();
+ });
+
+ it("toggles open report checkbox flag", () => {
+ render();
+ const openCheckbox = screen.getByLabelText(/open report when complete/i);
+
+ // Uncheck open report
+ fireEvent.click(openCheckbox);
+ expect(
+ screen.getByText("soroban-testkit coverage . --format html"),
+ ).toBeInTheDocument();
+
+ // Check open report back on
+ fireEvent.click(openCheckbox);
+ expect(
+ screen.getByText("soroban-testkit coverage . --format html --open"),
+ ).toBeInTheDocument();
+ });
+
+ it("quotes coverage path when containing spaces and copies combined command", async () => {
+ const writeText = vi.fn().mockResolvedValue(undefined);
+ Object.defineProperty(navigator, "clipboard", {
+ value: { writeText },
+ configurable: true,
+ });
+
+ render();
+
+ const pathInput = screen.getByLabelText(/project or contract path/i);
+ const formatSelect = screen.getByLabelText(/report format/i);
+ const openCheckbox = screen.getByLabelText(/open report when complete/i);
+
+ fireEvent.change(pathInput, { target: { value: "./contracts/my escrow" } });
+ fireEvent.change(formatSelect, { target: { value: "lcov" } });
+ fireEvent.click(openCheckbox); // unchecked
+
+ const expectedCommand = 'soroban-testkit coverage "./contracts/my escrow" --format lcov';
+ expect(screen.getByText(expectedCommand)).toBeInTheDocument();
+
+ fireEvent.click(screen.getByRole("button", { name: "Copy" }));
+ await waitFor(() => expect(writeText).toHaveBeenCalledWith(expectedCommand));
+ });
+});
+
+describe("Limits option combinations component tests (#199)", () => {
+ const originalClipboard = navigator.clipboard;
+
+ afterEach(() => {
+ Object.defineProperty(navigator, "clipboard", {
+ value: originalClipboard,
+ configurable: true,
+ });
+ vi.restoreAllMocks();
+ });
+
+ it("renders default limits options and allows editing function and ramp", () => {
+ render();
+ fireEvent.click(screen.getByRole("button", { name: "limits" }));
+
+ const fnInput = screen.getByLabelText(/function/i);
+ const rampInput = screen.getByLabelText(/ramp parameter/i);
+
+ expect(fnInput).toHaveValue("batch_payout");
+ expect(rampInput).toHaveValue("recipients");
+
+ fireEvent.change(fnInput, { target: { value: "deposit_tokens" } });
+ fireEvent.change(rampInput, { target: { value: "depositors" } });
+
+ expect(
+ screen.getByText(
+ "soroban-testkit limits --contract . --fn deposit_tokens --ramp depositors",
+ ),
+ ).toBeInTheDocument();
+ });
+
+ it("handles paths with spaces and copies limits command combinations", async () => {
+ const writeText = vi.fn().mockResolvedValue(undefined);
+ Object.defineProperty(navigator, "clipboard", {
+ value: { writeText },
+ configurable: true,
+ });
+
+ render();
+ fireEvent.click(screen.getByRole("button", { name: "limits" }));
+
+ const pathInput = screen.getByLabelText(/project or contract path/i);
+ const fnInput = screen.getByLabelText(/function/i);
+ const rampInput = screen.getByLabelText(/ramp parameter/i);
+
+ fireEvent.change(pathInput, {
+ target: { value: "./target/release build/token.wasm" },
+ });
+ fireEvent.change(fnInput, { target: { value: "mint_batch" } });
+ fireEvent.change(rampInput, { target: { value: "accounts" } });
+
+ const expectedCommand =
+ 'soroban-testkit limits --contract "./target/release build/token.wasm" --fn mint_batch --ramp accounts';
+ expect(screen.getByText(expectedCommand)).toBeInTheDocument();
+
+ fireEvent.click(screen.getByRole("button", { name: "Copy" }));
+ await waitFor(() => expect(writeText).toHaveBeenCalledWith(expectedCommand));
+ });
+});
+
+describe("Audit option combinations component tests (#198)", () => {
+ const originalClipboard = navigator.clipboard;
+
+ afterEach(() => {
+ Object.defineProperty(navigator, "clipboard", {
+ value: originalClipboard,
+ configurable: true,
+ });
+ vi.restoreAllMocks();
+ });
+
+ it("toggles fail on warnings strict mode in audit workflow", () => {
+ render();
+ fireEvent.click(screen.getByRole("button", { name: "audit" }));
+
+ const strictCheckbox = screen.getByLabelText(/fail on warnings/i);
+ expect(strictCheckbox).toBeChecked();
+ expect(screen.getByText("soroban-testkit audit . --strict")).toBeInTheDocument();
+
+ // Uncheck strict
+ fireEvent.click(strictCheckbox);
+ expect(strictCheckbox).not.toBeChecked();
+ expect(screen.getByText("soroban-testkit audit .")).toBeInTheDocument();
+
+ // Check strict again
+ fireEvent.click(strictCheckbox);
+ expect(strictCheckbox).toBeChecked();
+ expect(screen.getByText("soroban-testkit audit . --strict")).toBeInTheDocument();
+ });
+
+ it("quotes audit path with spaces and copies command to clipboard", async () => {
+ const writeText = vi.fn().mockResolvedValue(undefined);
+ Object.defineProperty(navigator, "clipboard", {
+ value: { writeText },
+ configurable: true,
+ });
+
+ render();
+ fireEvent.click(screen.getByRole("button", { name: "audit" }));
+
+ const pathInput = screen.getByLabelText(/project or contract path/i);
+ const strictCheckbox = screen.getByLabelText(/fail on warnings/i);
+
+ fireEvent.change(pathInput, { target: { value: "./contracts/safe math" } });
+ fireEvent.click(strictCheckbox); // uncheck strict
+
+ const expectedCommand = 'soroban-testkit audit "./contracts/safe math"';
+ expect(screen.getByText(expectedCommand)).toBeInTheDocument();
+
+ fireEvent.click(screen.getByRole("button", { name: "Copy" }));
+ await waitFor(() => expect(writeText).toHaveBeenCalledWith(expectedCommand));
+ });
+});
+
+describe("Workflow switching component tests (#201)", () => {
+ it("switches between all three workflows and updates descriptions and controls", () => {
+ render();
+
+ const coverageButton = screen.getByRole("button", { name: "coverage" });
+ const limitsButton = screen.getByRole("button", { name: "limits" });
+ const auditButton = screen.getByRole("button", { name: "audit" });
+
+ // Initial state: coverage
+ expect(coverageButton).toHaveClass("active");
+ expect(limitsButton).not.toHaveClass("active");
+ expect(auditButton).not.toHaveClass("active");
+ expect(
+ screen.getByText("Generate contract-test coverage through cargo-llvm-cov."),
+ ).toBeInTheDocument();
+ expect(screen.getByLabelText(/report format/i)).toBeInTheDocument();
+ expect(screen.getByLabelText(/open report when complete/i)).toBeInTheDocument();
+
+ // Switch to limits
+ fireEvent.click(limitsButton);
+ expect(coverageButton).not.toHaveClass("active");
+ expect(limitsButton).toHaveClass("active");
+ expect(auditButton).not.toHaveClass("active");
+ expect(
+ screen.getByText("Ramp a contract input to find its practical resource ceiling."),
+ ).toBeInTheDocument();
+ expect(screen.getByLabelText(/function/i)).toBeInTheDocument();
+ expect(screen.getByLabelText(/ramp parameter/i)).toBeInTheDocument();
+ expect(screen.queryByLabelText(/report format/i)).not.toBeInTheDocument();
+
+ // Switch to audit
+ fireEvent.click(auditButton);
+ expect(coverageButton).not.toHaveClass("active");
+ expect(limitsButton).not.toHaveClass("active");
+ expect(auditButton).toHaveClass("active");
+ expect(
+ screen.getByText("Scan contract sources for common auth, arithmetic, and TTL risks."),
+ ).toBeInTheDocument();
+ expect(screen.getByLabelText(/fail on warnings/i)).toBeInTheDocument();
+ expect(screen.queryByLabelText(/function/i)).not.toBeInTheDocument();
+
+ // Switch back to coverage
+ fireEvent.click(coverageButton);
+ expect(coverageButton).toHaveClass("active");
+ expect(screen.getByLabelText(/report format/i)).toBeInTheDocument();
+ expect(screen.queryByLabelText(/fail on warnings/i)).not.toBeInTheDocument();
+ });
+
+ it("updates generated command and copies accurately when switching workflows", async () => {
+ const writeText = vi.fn().mockResolvedValue(undefined);
+ Object.defineProperty(navigator, "clipboard", {
+ value: { writeText },
+ configurable: true,
+ });
+
+ render();
+
+ // In coverage
+ fireEvent.click(screen.getByRole("button", { name: "Copy" }));
+ await waitFor(() =>
+ expect(writeText).toHaveBeenCalledWith("soroban-testkit coverage . --format html --open"),
+ );
+
+ // Switch to limits
+ fireEvent.click(screen.getByRole("button", { name: "limits" }));
+ fireEvent.click(screen.getByRole("button", { name: "Copy" }));
+ await waitFor(() =>
+ expect(writeText).toHaveBeenCalledWith(
+ "soroban-testkit limits --contract . --fn batch_payout --ramp recipients",
+ ),
+ );
+
+ // Switch to audit
+ fireEvent.click(screen.getByRole("button", { name: "audit" }));
+ fireEvent.click(screen.getByRole("button", { name: "Copy" }));
+ await waitFor(() =>
+ expect(writeText).toHaveBeenCalledWith("soroban-testkit audit . --strict"),
+ );
+ });
+});