Skip to content

Add API client and runner functionality#365

Merged
hawkeyexl merged 6 commits into
mainfrom
api-integrations
Oct 25, 2025
Merged

Add API client and runner functionality#365
hawkeyexl merged 6 commits into
mainfrom
api-integrations

Conversation

@hawkeyexl
Copy link
Copy Markdown
Contributor

@hawkeyexl hawkeyexl commented Oct 25, 2025

Summary by CodeRabbit

  • New Features
    • Added support for running tests via a remote API when API credentials are provided.
    • Tests now automatically choose API-based or local execution based on configuration.
    • Accepted optional pre-resolved test payloads to skip local resolution and use supplied results.
    • Preserves existing result logging, telemetry, and temporary-file cleanup behavior.

@hawkeyexl hawkeyexl requested a review from Copilot October 25, 2025 03:00
Copy link
Copy Markdown
Contributor Author

@hawkeyexl hawkeyexl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai review

@hawkeyexl hawkeyexl self-assigned this Oct 25, 2025
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds functionality to run tests via an external API as an alternative to local execution. When an API key is configured, tests are submitted to a remote service for execution instead of running locally.

Key changes:

  • Added runViaApi function to handle API-based test execution with polling for results
  • Modified runTests to conditionally route to API or local execution based on configuration
  • Added API key configuration support through environment variables

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
src/tests.js Implements runViaApi function for remote test execution via API with polling mechanism
src/index.js Updates runTests to route execution to API when API key is present in config
dev/index.js Adds API key configuration example using environment variable
Comments suppressed due to low confidence (1)

src/tests.js:1

  • The config parameter is not passed to runViaApi, but the function signature accepts it as config = {}. This means API timeout configuration (config.apiMaxWaitTime) won't be accessible. Pass the config object: results = await runViaApi({ resolvedTests, apiKey: config.integrations.docDetectiveApi.apiKey, config })
const kill = require("tree-kill");

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tests.js Outdated
Comment thread src/tests.js Outdated
Comment thread src/tests.js
Comment thread src/tests.js Outdated
Comment thread src/tests.js Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Oct 25, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds config wiring for a DocDetective API key, modifies the test runner to accept pre-resolved tests and choose between local or API execution, and implements an API-driven execution path that creates, starts, polls, and retrieves run reports.

Changes

Cohort / File(s) Summary of Changes
Dev config: API key wiring
dev/index.js
Adds integrations.docDetectiveApi.apiKey to the config payload, populated from env KEY.
Runner orchestration
src/index.js
Changes runTests(config)runTests(config, options = {}); accepts optional options.resolvedTests (overrides and may replace detection); uses detectAndResolveTests when not provided; chooses execution path: API (runViaApi) if config.integrations.docDetectiveApi.apiKey present, otherwise local (runSpecs); retains telemetry, logging, and cleanup.
API-based test execution
src/tests.js
Adds and exports runViaApi({ resolvedTests, apiKey, config = {} }): POSTs run, starts run, polls status with jitter and max wait, handles errors, and returns structured final report or error.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as Caller
  participant R as runTests
  participant DR as detectAndResolveTests
  participant L as runSpecs (local)
  participant A as runViaApi

  U->>R: runTests(config, options)
  alt options.resolvedTests provided
    R->>R: use options.resolvedTests\noverride config with resolvedTests.config
  else
    R->>DR: detectAndResolveTests(config)
    DR-->>R: resolvedTests or none
    R->>R: error if none found
  end

  alt config.integrations.docDetectiveApi.apiKey present
    R->>A: runViaApi({resolvedTests, apiKey, config})
    A-->>R: results/report or error
  else
    R->>L: runSpecs(resolvedTests, config)
    L-->>R: results/report
  end

  R->>R: telemetry, logging, cleanup
  R-->>U: final results
Loading
sequenceDiagram
  autonumber
  participant A as runViaApi
  participant S as DocDetective API
  participant P as Poller

  A->>S: POST /runs (resolvedTests) {apiKey}
  S-->>A: 201 Created {runId}
  A->>S: POST /runs/{runId}/start
  S-->>A: 202 Accepted

  loop Poll until complete or timeout
    A->>S: GET /runs/{runId}/status
    S-->>A: {status: running|completed|failed}
    Note over A,P: randomized interval (jitter), enforce maxWaitTime
  end

  alt completed
    A->>S: GET /runs/{runId}/report
    S-->>A: Final report
    A-->>Caller: {status: success, report}
  else failed/timeout/error
    A-->>Caller: {status: error, error}
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect polling logic in src/tests.js (jitter, backoff, max wait, error paths).
  • Verify precedence and config override when options.resolvedTests is provided (src/index.js).
  • Confirm safe handling when config.integrations.docDetectiveApi or apiKey is absent (dev/index.js and runtime checks).

Possibly related PRs

Poem

A rabbit taps the run command—hop!
Keys in paw, it sends a plop.
Starts the run, then waits with glee,
Polls the cloud till results are free.
Reports arrive — a joyous hop! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Add API client and runner functionality" directly and accurately reflects the primary changes in this changeset. The PR introduces a new API-based test execution pathway through the runViaApi function in src/tests.js, integrates API key configuration in dev/index.js, and conditionally routes test execution through either the API or local execution in src/index.js. The title is specific and descriptive enough that it clearly conveys the main objective—adding API client and runner capabilities—without being vague or overly broad, making it suitable for historical scanning.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch api-integrations

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f77c2d and 6661512.

📒 Files selected for processing (1)
  • src/tests.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/tests.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: test (macos-latest, 22)
  • GitHub Check: test (macos-latest, 18)
  • GitHub Check: test (macos-latest, 24)
  • GitHub Check: test (macos-latest, 20)
  • GitHub Check: test (windows-latest, 22)
  • GitHub Check: test (windows-latest, 20)
  • GitHub Check: test (windows-latest, 24)
  • GitHub Check: test (ubuntu-latest, 24)
  • GitHub Check: test (ubuntu-latest, 22)
  • GitHub Check: test (ubuntu-latest, 18)
  • GitHub Check: test (windows-latest, 18)
  • GitHub Check: test (ubuntu-latest, 20)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
src/tests.js (4)

260-270: Potential null reference error when accessing error.response.

If error.response is undefined (which occurs during network errors like ECONNREFUSED or timeouts before receiving a response), accessing error.response.status and error.response.data.error will throw a TypeError.

Apply this diff to add defensive checks:

   } catch (error) {
-    return { status: error.response.status, error: error.response.data.error };
+    return error.response
+      ? { status: error.response.status, error: error.response.data?.error || error.message }
+      : { status: "NETWORK_ERROR", error: error.message };
   }

274-287: Potential null reference error when accessing error.response.

If error.response is undefined (which occurs during network errors like ECONNREFUSED or timeouts before receiving a response), accessing error.response.status and error.response.data.error will throw a TypeError.

Apply this diff to add defensive checks:

   } catch (error) {
-    return { status: error.response.status, error: error.response.data.error };
+    return error.response
+      ? { status: error.response.status, error: error.response.data?.error || error.message }
+      : { status: "NETWORK_ERROR", error: error.message };
   }

289-305: Status type inconsistency: mixing string and numeric status codes.

The timeout returns status: "TIMEOUT" (string) while other error paths return numeric HTTP status codes. This inconsistency could cause issues for consumers expecting uniform status types.

Consider using a consistent format. Options include:

  1. Use a numeric code for timeout (e.g., 408 for request timeout)
  2. Wrap all statuses in a structured object with separate type and code fields
  3. Document the mixed types clearly if intentional

307-319: Potential null reference error when accessing error.response.

If error.response is undefined (which occurs during network errors like ECONNREFUSED or timeouts before receiving a response), accessing error.response.status and error.response.data.error will throw a TypeError.

Apply this diff to add defensive checks:

     } catch (error) {
-      return {
-        status: error.response.status,
-        error: error.response.data.error,
-      };
+      return error.response
+        ? {
+            status: error.response.status,
+            error: error.response.data?.error || error.message,
+          }
+        : {
+            status: "NETWORK_ERROR",
+            error: error.message,
+          };
     }
🧹 Nitpick comments (1)
dev/index.js (1)

20-25: Consider adding validation for the API key.

The apiKey is sourced directly from process.env.KEY without validation. If the environment variable is not set, undefined will be passed to the configuration, which may lead to unclear error messages downstream.

Consider adding a check or fallback:

   }],
   integrations: {
     docDetectiveApi: {
-      apiKey: process.env.KEY
+      apiKey: process.env.KEY // Set KEY environment variable to test API integration
     }
   }
 };

Alternatively, add validation before calling runTests:

if (!process.env.KEY) {
  console.warn("Warning: KEY environment variable not set. API integration will be disabled.");
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bd4c48c and 0f77c2d.

📒 Files selected for processing (3)
  • dev/index.js (1 hunks)
  • src/index.js (2 hunks)
  • src/tests.js (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
dev/index.js (1)
src/config.js (1)
  • setConfig (168-258)
src/tests.js (2)
src/tests/httpRequest.js (4)
  • require (1-1)
  • require (6-6)
  • require (7-7)
  • axios (2-2)
src/utils.js (1)
  • axios (4-4)
src/index.js (1)
src/tests.js (2)
  • config (357-357)
  • results (335-335)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: test (macos-latest, 20)
  • GitHub Check: test (macos-latest, 24)
  • GitHub Check: test (macos-latest, 22)
  • GitHub Check: test (macos-latest, 18)
  • GitHub Check: test (windows-latest, 24)
  • GitHub Check: test (windows-latest, 18)
  • GitHub Check: test (windows-latest, 22)
  • GitHub Check: test (windows-latest, 20)
  • GitHub Check: test (ubuntu-latest, 22)
🔇 Additional comments (9)
src/tests.js (5)

5-5: LGTM!

The axios import is correctly placed and necessary for the new API integration functionality.


31-31: LGTM!

The runViaApi export properly exposes the new API-based test execution pathway for external use.


242-258: LGTM!

The function setup correctly configures the base URL with environment variable fallback and properly configures axios with authentication headers and connection settings. The explicit keepAlive: false setting prevents connection reuse issues that could occur in batch operations.


326-331: Verify the polling variance calculation produces expected results.

The variance calculation uses Math.random() * pollIntervalVariance * 2 - pollIntervalVariance, which produces values in the range [-pollIntervalVariance, +pollIntervalVariance]. With pollIntervalVariance = 2000, the actual wait time ranges from 3 to 7 seconds. Ensure this randomization aligns with the intended load distribution on the API.


242-338: Consider whether the full config object should be passed to the API.

Currently, runViaApi receives resolvedTests and apiKey, but only uses config.apiMaxWaitTime from the config. The API endpoint receives the resolved tests but not the original configuration settings (e.g., logLevel, recording, allowUnsafeSteps). Verify whether the API should receive additional config parameters to match local execution behavior.

If the API needs access to config settings, consider modifying the function signature:

async function runViaApi({ resolvedTests, apiKey, config = {} }) {
  // Include relevant config in the API request body
  const payload = {
    ...resolvedTests,
    settings: {
      logLevel: config.logLevel,
      recording: config.recording,
      // other relevant settings
    }
  };
  // ...
}
src/index.js (4)

1-5: LGTM!

The import updates correctly reflect the new dependencies: detectAndResolveTests from the resolver package and runViaApi from the local tests module. The changes support the new API-based execution pathway.


19-26: LGTM!

The signature change to accept an options parameter is backward compatible (defaults to {}), and the logic to handle pre-resolved tests via options.resolvedTests is clean. Overriding config with resolvedTests.config ensures consistency when tests are pre-resolved.


31-37: LGTM!

The conditional test resolution correctly skips detection when resolvedTests are already provided, avoiding unnecessary work and improving performance when tests are pre-resolved externally.


39-49: Add defensive check for nested property access.

Line 40 accesses deeply nested properties (config.integrations.docDetectiveApi.apiKey) without checking if intermediate properties exist. If config.integrations or config.integrations.docDetectiveApi is undefined, this will throw a TypeError.

Apply this diff to add optional chaining:

-  if (config.integrations && config.integrations.docDetectiveApi && config.integrations.docDetectiveApi.apiKey) {
+  if (config.integrations?.docDetectiveApi?.apiKey) {
     // Run test specs via API
     results = await runViaApi({
       resolvedTests,
       apiKey: config.integrations.docDetectiveApi.apiKey,
     });

Likely an incorrect or invalid review comment.

Comment thread src/tests.js Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@promptless
Copy link
Copy Markdown

promptless Bot commented Oct 25, 2025

📝 Documentation updates detected!

New suggestion: Document API client and runner functionality

@hawkeyexl
Copy link
Copy Markdown
Contributor Author

@copilot Write tests for the functionality introduced in this PR.

@hawkeyexl hawkeyexl merged commit 44a28eb into main Oct 25, 2025
19 checks passed
@hawkeyexl hawkeyexl deleted the api-integrations branch October 25, 2025 03:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Run tests via Orchestration API instead of locally based on integration array entry

3 participants