Testing is organized in four tiers:
| Tier | Scope | Runner | CI/CD |
|---|---|---|---|
| Unit + Component | Vue components, API endpoints, services | Vitest (WUI), pytest (API) | Every push |
| UI E2E (local) | WUI pages, navigation, i18n, payment wizard | Puppeteer + Mocha (test-1xx, test-2xx) |
Every push (test-ui job) |
| Tesla Semi-Auto E2E | Full OAuth → payment → report → PDF flow | Puppeteer + manual login + automation (test-304) |
After deploy (if session available) |
| Tesla Full-Blind E2E | Fully automated Tesla OAuth (unreliable) | Puppeteer + KeePassXC (test-303) |
Disabled (on-demand only) |
# Run all unit tests with coverage
cd bnc-cpt-wui/src/vue/app && npm run test:coverage
# Run a specific test file
npx vitest run tests/components/ReportDashboard.test.ts
Coverage thresholds: statements 40%, branches 30%, functions 40%, lines 40%.
# Run all tests
cd bnc-cpt-api/src/python/cpt-api && poetry run pytest
# Run Tesla-specific tests
poetry run pytest tests/test_tesla.py -v
Coverage threshold: 79%.
Local page-level tests that don't require Tesla credentials.
# Via Make (Docker container)
make test-wui # headless, localhost
make test-wui-dev # headless, dev environment
make test-wui-headed # visible browser, localhost
# Via npm
cd bnc-cpt-wui/src/nodejs/the-bot
ORG=bnc APP=cpt ENV=lcl npm test
# Via shell action
ENV=dev ./run -a do_run_wui_test
Test suites:
- test-101 Landing page
- test-102 Payment step UI
- test-103 Language switcher
- test-104 i18n completeness
- test-105 User journey
- test-106 Back navigation
- test-107 Support page
- test-108 Service agreement
- test-109 Error states
- test-110 Session persistence
- test-201 Stripe payment wizard
- test-202 PayPal payment
Two-phase approach that avoids Tesla bot detection entirely: 1. Phase 1 (human, ~30s): A real browser opens, human completes Tesla login 2. Phase 2 (automated): Puppeteer takes over for package selection, Stripe payment, report generation, and PDF download
Tesla's login page (auth.tesla.com) is protected by Akamai Bot Manager which uses: - TLS fingerprinting (JA3/JA4) — detects headless Chromium at the TCP layer - Browser fingerprinting — canvas, WebGL, audio context, 100+ signals - Behavioral analysis — mouse movement patterns, keystroke timing - CAPTCHA escalation — hCaptcha when detection score is high
No amount of header spoofing or navigator overrides can reliably bypass this. The semi-auto approach uses a real human for the protected login page and automates everything else.
When the API has E2E_TEST_MODE=true, session TTL extends from 30 minutes to 2 hours, giving ample time for the human login + automated test execution.
Set it via environment variable:
# In the API's .env or environment
E2E_TEST_MODE=true
# Step 1: Obtain session (opens browser, human logs into Tesla)
ENV=dev ./run -a do_tesla_obtain_session
# Step 2: Run automated E2E tests
ENV=dev ./run -a do_run_tesla_semi_auto_test
# Or combine both (auto-detects if session is valid):
ENV=dev ./run -a do_run_tesla_semi_auto_test
make test-wui-obtain-session # Phase 1: manual Tesla login
make test-wui-semi-auto # Phase 2: automated post-OAuth flow
make test-wui-semi-auto-headed # Phase 2 with visible browser
The session is saved to bnc-cpt-wui/dat/tmp/sec/tesla-test-session.json:
{
"session_id": "abc123...",
"obtained_at": "2026-03-13T10:00:00.000Z",
"expires_at": "2026-03-13T12:00:00.000Z",
"env": "dev",
"entrypoint": "https://dev.carpulsetracker.com"
}
0600 (owner-only read/write)dat/tmp/sec/ (gitignored)E2E_TEST_MODE=true)| Phase | What it tests | Timeout |
|---|---|---|
| Phase 1 | Session resume, vehicle list rendering | 15s |
| Phase 2 | Plan selection, Stripe payment flow | 60s |
| Phase 3 | Report generation, PDF download | 60s |
Screenshots are saved to dat/test-report/screenshots/semi-*.png.
Fully automated but unreliable — uses keyboard-only input to fill Tesla auth pages. Gets blocked by Akamai ~60% of the time. Tests gracefully skip when blocked.
# Via shell action
ENV=dev ./run -a do_run_tesla_blind_flow_test
# Via Make
make test-wui-blind # headless
make test-wui-blind-headed # visible browser
# Via npm
ORG=bnc APP=cpt ENV=dev npm run test:full-blind
Credentials come from KeePassXC (TESLA-OTP entry in bnc-cpt-crs.kdbx).
bnc-cpt-wui/.github/workflows/ci.yaml)| Job | What | Trigger |
|---|---|---|
build |
Docker build + type-check | Every push |
test-support |
i18n content tests (en, fi, sv) | Every push |
test-unit |
Vitest with coverage | Every push |
test-ui |
Puppeteer E2E (test-1xx, test-2xx) |
Every push |
deploy |
GCS bucket deploy (inf, dev) | master push |
post-deploy-test |
Smoke tests against deployed env | After deploy |
test-semi-auto |
Tesla semi-auto E2E (test-304) |
After deploy (if session available) |
Tesla full-blind tests (test-301, test-303) are disabled in CI — they run on-demand only.
Tesla semi-auto tests (test-304) run in CI via the test-semi-auto job if a valid session is available in GitHub repo variables.
The test-semi-auto job bridges local human login with CI automation:
ENV=dev ./run -a do_tesla_obtain_session — opens browser for human Tesla loginsession_id, expires_at, env, and entrypoint to GitHub repo variables via gh variable settest-semi-auto job reads these variables, validates the session is still unexpired, creates the session file inside the Docker container, and runs npm run test:semi-autoGitHub repo variables used:
- TESLA_E2E_SESSION_ID — the OAuth session_id
- TESLA_E2E_SESSION_EXPIRES — ISO 8601 expiry timestamp
- TESLA_E2E_SESSION_ENV — target environment (dev, tst)
- TESLA_E2E_SESSION_ENTRYPOINT — WUI base URL
bnc-cpt-api/.github/workflows/ci.yaml)| Job | What | Trigger |
|---|---|---|
build-and-test |
pytest with coverage | Every push |
deploy |
Cloud Run deploy (inf, dev) | master push |
post-deploy-test |
Health + auth smoke tests | After deploy |
| Secret | Source | Used by |
|---|---|---|
| Tesla username/password | KeePassXC TESLA-OTP |
test-301, test-303 |
| Tesla TOTP | KeePassXC TESLA-OTP (TOTP field) |
test-301, test-303 |
| Stripe test card | KeePassXC STRIPE-TEST/visa-test-card or default 4242... |
test-201, test-303, test-304 |
| PayPal sandbox | KeePassXC via CI secrets | test-202 |
KeePassXC database: bnc-cpt-crs/dat/bnc-cpt-crs.kdbx
Key file: ~/.ssh/.bnc/bnc-cpt-crs.pem
All test suites generate Mochawesome HTML reports:
- Location: bnc-cpt-wui/dat/test-report/report.html
- Screenshots: bnc-cpt-wui/dat/test-report/screenshots/
- Downloads: bnc-cpt-wui/dat/test-report/downloads/
In CI, reports are uploaded as GitHub Actions artifacts.