CI/CD Integration
Kane CLI runs headlessly in CI/CD pipelines using credentials passed as environment variables or inline flags. Tests fail fast on assertion errors and return standard exit codes for pipeline control flow.
Common Patterns
These patterns apply to every CI system; the platform-specific recipes below differ only in how they wire up the secrets.
- Always pass
--headless. CI runners have no display. - Always set
--timeout <seconds>. A hung run cannot be allowed to block the pipeline. - Authenticate with
--usernameand--access-keyfrom CI secrets. Do not callkane-cli loginin CI — that flow opens a browser for OAuth and will not work on a runner. - Load test data with
--variables-file <path>. Check the file into your repo (without secret values), or generate it before the step. - Check the exit code.
0passed,1failed,2error,3timeout or cancellation.
The runner spawns Chrome itself, so the CI image must have Chrome available on PATH. If your runner image cannot install Chrome, point Kane CLI at a remote browser with --cdp-endpoint <url> or --ws-endpoint <url> (for example, a TestMu AI wss:// endpoint).
Authentication in CI/CD
Pass credentials directly on the run command using environment variables from your secrets store:
kane-cli run "Verify checkout flow completes" \
--url https://staging.myapp.com \
--username "undefined" \
--access-key "undefined" \
--headless \
--agent \
--timeout 300
Get your username and access key from the TestMu AI dashboard > Credentials.
Exit Codes
| Code | Meaning | Pipeline Behavior |
|---|---|---|
0 | Test passed | Pipeline continues |
1 | Test failed (assertion not met) | Pipeline stops |
2 | Error (auth failure, Chrome crash) | Pipeline stops |
3 | Timeout or cancelled | Pipeline stops |
CI/CD Checklist
- Always use
--headlessand--agent: no display server in CI - Set
--timeout: prevents pipeline hangs (e.g.--timeout 300) - Set
--max-steps: caps run length (e.g.--max-steps 50) - Use
--variables-file: load test data from a committed config file - Store credentials as secrets: never hardcode in pipeline files
Platform Guides
- GitHub Actions
- GitLab CI
- Jenkins
- Bitbucket Pipelines
- Docker / Generic
Store LT_USERNAME and LT_ACCESS_KEY as repository secrets under Settings > Secrets and variables > Actions.
# .github/workflows/browser-tests.yml
name: Browser Tests
on: [push, pull_request]
jobs:
kane-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Chrome
uses: browser-actions/setup-chrome@v1
- name: Install Kane CLI
run: npm install -g @testmuai/kane-cli
- name: Run browser tests
env:
LT_USERNAME: ${{ secrets.LT_USERNAME }}
LT_ACCESS_KEY: ${{ secrets.LT_ACCESS_KEY }}
run: |
kane-cli run \
"Search for 'wireless headphones' on Amazon and open the first result" \
--headless \
--timeout 300 \
--username "$LT_USERNAME" \
--access-key "$LT_ACCESS_KEY" \
--variables-file ./tests/variables.json
- name: Upload test logs
if: always()
uses: actions/upload-artifact@v4
with:
name: kane-test-logs
path: ~/.testmuai/kaneai/sessions/
Define LT_USERNAME and LT_ACCESS_KEY as masked CI/CD variables in your project settings.
# .gitlab-ci.yml
stages:
- test
kane-cli:
stage: test
image: node:20
before_script:
- apt-get update && apt-get install -y wget gnupg
- wget -qO- https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
- echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list
- apt-get update && apt-get install -y google-chrome-stable
- npm install -g @testmuai/kane-cli
script:
- |
kane-cli run "Verify the homepage loads and the login button is visible" \
--headless \
--timeout 300 \
--username "$LT_USERNAME" \
--access-key "$LT_ACCESS_KEY" \
--variables-file ./tests/variables.json
variables:
LT_USERNAME: $LT_USERNAME
LT_ACCESS_KEY: $LT_ACCESS_KEY
artifacts:
paths:
- ~/.testmuai/kaneai/sessions/
when: always
expire_in: 7 days
Store credentials in Jenkins > Manage Jenkins > Manage Credentials. The two credentials(...) IDs refer to Username/Password or Secret Text credentials configured in Jenkins.
// Jenkinsfile
pipeline {
agent any
environment {
LT_USERNAME = credentials('lt-username')
LT_ACCESS_KEY = credentials('lt-access-key')
}
stages {
stage('Install') {
steps {
sh 'npm install -g @testmuai/kane-cli'
}
}
stage('Run kane-cli') {
steps {
sh '''
kane-cli run "Sign in and confirm the dashboard renders" \
--headless \
--timeout 300 \
--username "$LT_USERNAME" \
--access-key "$LT_ACCESS_KEY" \
--variables-file ./tests/variables.json
'''
}
}
}
post {
always {
archiveArtifacts artifacts: '~/.testmuai/kaneai/sessions/**',
allowEmptyArchive: true
}
}
}
The pipeline fails on any non-zero exit code from the sh step, which matches Kane CLI's exit-code semantics.
Add LT_USERNAME and LT_ACCESS_KEY as repository variables under Repository settings > Repository variables.
# bitbucket-pipelines.yml
pipelines:
default:
- step:
name: Browser Tests
image: node:20
script:
- npm install -g @testmuai/kane-cli
- kane-cli run
--url https://staging.myapp.com
--username $LT_USERNAME
--access-key $LT_ACCESS_KEY
--headless
--agent
--timeout 300
--max-steps 50
"Complete the checkout flow and verify order confirmation"
artifacts:
- ~/.testmuai/kaneai/sessions/**
The shell command below works in any CI that can run a Linux container with Chrome installed:
kane-cli run "Open the pricing page and verify the Pro plan is listed" \
--headless \
--timeout 300 \
--username "$LT_USERNAME" \
--access-key "$LT_ACCESS_KEY" \
--variables-file ./tests/variables.json
If your CI image cannot install Chrome — for example, a minimal Node Alpine image — point Kane CLI at a remote browser instead:
kane-cli run "Open the pricing page and verify the Pro plan is listed" \
--headless \
--timeout 300 \
--ws-endpoint "$LT_BROWSER_WSS" \
--username "$LT_USERNAME" \
--access-key "$LT_ACCESS_KEY" \
--variables-file ./tests/variables.json
--cdp-endpoint <url> works the same way for browsers that expose a Chrome DevTools Protocol URL. With either flag, Kane CLI skips its own Chrome launch and connects to the endpoint you provide.
Running Multiple Tests
Run several tests and fail the pipeline if any fail:
#!/bin/bash
set -e
PASS=0
FAIL=0
FAILED_TESTS=()
run_test() {
local name="$1"
local objective="$2"
echo "Running: $name"
if kane-cli run "$objective" \
--url https://staging.myapp.com \
--username $LT_USERNAME \
--access-key $LT_ACCESS_KEY \
--headless --agent --timeout 120; then
((PASS++))
else
((FAIL++))
FAILED_TESTS+=("$name")
fi
}
run_test "Login" "Log in with valid credentials and verify dashboard appears"
run_test "Search" "Search for 'laptop' and verify at least one result appears"
run_test "Checkout" "Add first product to cart and complete checkout"
run_test "Settings" "Open account settings and verify profile page loads"
echo ""
echo "Results: $PASS passed, $FAIL failed"
if [[ $FAIL -gt 0 ]]; then
echo "Failed tests: ${FAILED_TESTS[*]}"
exit 1
fi
Variables in CI/CD
Commit a non-secret variables file to your repo, and inject secrets at runtime:
{
"app_url": { "value": "https://staging.myapp.com" },
"test_product_sku": { "value": "PROD-001" }
}
Merge with secrets in your pipeline:
kane-cli run "Log in as {{email}} with {{password}} and verify dashboard" \
--variables-file ./test-variables.json \
--variables "{\"email\": {\"value\": \"$TEST_EMAIL\"}, \"password\": {\"value\": \"$TEST_PASSWORD\", \"secret\": true}}" \
--username $LT_USERNAME \
--access-key $LT_ACCESS_KEY \
--headless --agent
