This document provides comprehensive guidance for running tests in Stratos and troubleshooting test failures across different environments.
# Run all unit tests
make test
# Run specific package tests
bun run test:core
bun run test:store
bun run test:cloud-foundry
bun run test:kubernetes
# Run E2E tests
make test-e2e
# Run with UI (interactive)
bun run test:ui
# Run with coverage
bun run test:coverage- Node.js:
24.xor higher - Bun:
1.2.0or higher (including 1.3.x)
Bun 1.3.x Compatibility:
- Bun 1.3.x changed test discovery behavior
- Our configuration (
bunfig.toml) disables Bun's built-in test runner - All tests run through Vitest via
bun run test(NOTbun test) - The workspace configuration explicitly excludes E2E tests from Vitest
# Install asdf first: https://asdf-vm.com/
asdf plugin add nodejs
asdf plugin add bun
# Install from .tool-versions
asdf install# Node.js 24
nvm install 24
nvm use 24
# Bun (latest)
bun upgrade
# Verify versions
node --version # Should show v24.x.x or higher
bun --version # Should show 1.2.0 or higher# Use latest Bun environment
docker run -it --rm \
-v $(pwd):/workspace \
-w /workspace \
oven/bun:latest \
/bin/bash
# Inside container
bun run testA pre-test hook automatically validates versions:
bun run test
# Output:
# ✓ Node.js v25.2.1 ✓
# ✓ Bun 1.3.2 ✓
# ✅ All version checks passed!If versions are incorrect, you'll see:
✗ ERROR: Node.js version v23.1.0 detected. Required: 24.x or higher
✗ ERROR: Bun version 1.1.0 detected. Required: 1.2.0 or higher- Location:
src/frontend/packages/*/src/**/*.spec.ts - Runner: Vitest 3.1.1
- Environment: happy-dom
- Framework: Angular 20 TestBed
- Location:
e2e/**/*.spec.ts - Runner: Playwright 1.49+
- Browsers: Chromium, Firefox, WebKit
- Note:
⚠️ E2E tests MUST NOT be run by Vitest!
Most e2e specs are self-contained and can run in any order, in parallel,
across any subset of groups. e2e/tests/dependent/ is the exception: it
holds specs that mutate shared state other specs rely on — today, that's
the endpoint registry (clearAllEndpoints / removeEndpoint). A spec in
this group leaves that shared state in a different condition than it
found it, so it must run after everything else, not alongside it.
scripts/e2e-run.mjs enforces this automatically: whenever a selection
(tier or group — including the impact scan a tier computes internally)
includes both dependent/ and non-dependent/ specs, the runner splits
it into two passes — everything else first, dependent/ last —
regardless of how the selection was built. A selection touching only
one side still runs as a single pass.
This exists because of a measured failure: in a full run, a failed
endpoint-registry restore in endpoints.spec.ts cascaded into roughly
200 downstream failures ("No CF endpoint found") in specs that assumed a
registered CF endpoint. Running dependent/ last, in its own pass,
contains that blast radius instead of poisoning the rest of the suite.
New specs belong in dependent/ if they mutate state other specs
depend on (endpoint registrations, shared orgs/spaces, etc.) and don't
clean up reliably enough to run interleaved with the parallel pool.
Everything else stays in its existing group directory.
This ordering is enforced only by the tiered runner (make test e2e TIER=… / make test e2e GROUP=…, which delegates to
scripts/e2e-run.mjs). A bare npx playwright test or make test e2e
(with no TIER/GROUP set) runs the plain Playwright test-runner
directly — dependent/ is not ordered last and can interleave with the
parallel pool, reintroducing the blast-radius risk above.
make check e2e also bypasses the tiered runner: it scopes directly to
npx playwright test e2e/tests/core/, so it no longer covers the
endpoint lifecycle spec at all — endpoints.spec.ts lives in
dependent/, outside that path.
SESSION_STORE_EXPIRY in playwright.config.ts's webServer config only
takes effect when the backend is actually spawned by Playwright. With
reuseExistingServer: true, an already-running jetstream keeps whatever
value it booted with until its next real boot — a stale process can be
running with a stale expiry regardless of what the config file currently
says. The BACKEND BOOT MARKER line printed by global-setup.ts at the
start of each run reports fresh boot vs. reused, so check it there rather
than assuming the config's value is live.
# All tests
make test # Runs unit tests only
# Specific test types
make test-unit # Unit tests (Vitest)
make test-e2e # E2E tests (Playwright)
# Linting
make lint # ESLint# Run all unit tests with explicit projects
bun run test
# Individual packages
bun run test:core
bun run test:store
bun run test:cloud-foundry
bun run test:kubernetes
bun run test:cf-autoscaler
bun run test:git
bun run test:shared
bun run test:extension
# Interactive/Debug modes
bun run test:ui # Vitest UI (browser-based)
bun run test:watch # Watch mode
bun run test:coverage # Coverage report
# E2E tests
bun run e2e # Run all E2E tests
bun run e2e:ui # Playwright UI
bun run e2e:debug # Debug mode
bun run e2e:headed # Show browser# Vitest CLI
bunx vitest run src/frontend/packages/core/src/core/utils.service.spec.ts
# With watch mode
bunx vitest src/frontend/packages/core/src/core/utils.service.spec.tsSymptoms:
error: Playwright Test did not expect test.describe() to be called here.
Cause: E2E test files are being discovered and run by Vitest instead of Playwright.
Fix:
- Ensure you're using
bun run test(NOTbun test) - Verify
bunfig.tomlexists and disables Bun's test runner - Check
.vitestignorefile exists - Verify exclusions in
vitest.workspace.ts
Symptoms:
error: Need to call TestBed.initTestEnvironment() first
Cause: Setup files not loading in correct order or at all.
Fix:
- Verify setup file order in
vitest.config.ts:setupFiles: [ join(__dirname, '../../vitest.workspace.setup.ts'), // MUST be first join(__dirname, 'src/test-setup.ts'), ]
- Check
vitest.workspace.setup.tsexists - Ensure using
bun run testnotbun test
Symptoms:
SyntaxError: export 'PermissionValues' not found in './selectors/current-user-role.selectors'
Cause: Module resolution timing issues or cache corruption.
Fix:
- Clear build cache:
rm -rf node_modules dist-devkit coverage bun install
- Ensure
bunfig.tomlexists and is configured properly
Cause: Version mismatch (most common), environment differences, or caching issues.
Fix:
- Verify versions on both machines:
node --version # Should be 24.x or higher bun --version # Should be 1.2.0 or higher
- Ensure same Bun version:
bun upgrade # Get latest - Clean install:
rm -rf node_modules dist-devkit coverage bun install
- Verify configuration files exist:
ls -la bunfig.toml .vitestignore vitest.workspace.ts
Symptoms:
Error: Test timeout of 15000ms exceeded
Fix:
- Increase timeout in
vitest.config.ts:testTimeout: 30000, hookTimeout: 30000,
- Check for race conditions in tests
- Ensure test isolation:
afterEach(() => { TestBed.resetTestingModule(); });
# Vitest debug
NODE_OPTIONS='--inspect-brk' bun run test:watch
# View detailed logs
bun run test -- --reporter=verbose
# Run single test file
bunx vitest run src/frontend/packages/core/src/core/utils.service.spec.ts --reporter=verboseOur CI pipeline (.github/workflows/pr.yml) ensures consistent testing:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [24.x]
bun-version: [1.3.x]
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- uses: oven-sh/setup-bun@v2
with:
bun-version: ${{ matrix.bun-version }}
- run: bun install
- run: bun run testKey Points:
- Uses latest Bun 1.3.x
- Node 24.x or higher
- Clean environment every run
- Parallel test execution by package
Tests are organized in a monorepo workspace:
vitest.workspace.ts
├── core (8 projects)
├── store
├── cloud-foundry
├── kubernetes
├── cf-autoscaler
├── git
├── shared
└── extension
Each project has:
- Own
vitest.config.ts - Own
test-setup.ts - Path aliases for imports
- Coverage configuration
Pool Configuration:
pool: 'forks',
poolOptions: {
forks: {
singleFork: true, // One process, TestBed stability
isolate: false, // Share environment for speed
},
},Why singleFork: true?
- Ensures TestBed state is properly reset between test files
- Prevents cross-test contamination
- Required for Angular 20 zoneless change detection
-
Workspace Setup (
vitest.workspace.setup.ts):- Initializes Angular TestBed platform
- Configures browser environment (happy-dom)
- Sets up global test utilities
-
Package Setup (
src/test-setup.ts):- Package-specific mocks
- Custom matchers
- Test helpers
Vitest uses these patterns:
Include:
src/**/*.spec.ts(unit tests)
Exclude:
e2e/**(Playwright tests)**/e2e/****/*.e2e.spec.ts**/*.e2e-spec.tsnode_modules/**dist/**
Path aliases (from vitest.config.ts):
'@stratosui/core' → '../core/src/public-api.ts'
'@stratosui/store' → '../store/src/public-api.ts'
'@test-framework' → '../core/test-framework'These must match tsconfig.json paths for IDE support.
# ✅ Good (uses bun run script → vitest)
bun run test
bun run test:core
# ❌ Bad (uses Bun's built-in test runner directly)
bun testrm -rf node_modules dist-devkit coverage
bun install
bun run test# Faster iteration
bun run test:core -- --watchbun run test:ui
# Opens browser at http://localhost:51204/__vitest__/node --version && bun --version
# Should be: v24.x.x and 1.2.13E2E specs bind to components through data-test hooks and element
selectors. When you change a component's template or DOM structure:
# See which specs cover the files you changed
git diff --name-only develop...HEAD | node scripts/e2e-impact.mjs
# Or grep directly for the component's hooks / selector
grep -rn 'data-test-value-or-selector' e2e/Run the specs the script names (it prints a scoped playwright test
command), and fix any spec your change breaks in the same PR — or file a
follow-up issue if the fix is substantial. Never leave a spec silently
binding to DOM that no longer exists; the lint guards
(bun run lint) catch dead selectors and orphaned hooks, and CI posts
the same impact report on every PR as an advisory job summary.
- ✅ Verify versions:
node --version && bun --version - ✅ Clean install:
rm -rf node_modules && bun install - ✅ Check setup files exist
- ✅ Review error message type (E2E discovery, TestBed, or module error)
If tests still fail, include:
# Environment info
node --version
bun --version
uname -a
# Test command
bun run test:core 2>&1 | head -50
# Config check
ls -la vitest.workspace.ts src/frontend/packages/core/vitest.config.tsKey Takeaways:
- Use Bun 1.2.0+ (including 1.3.x) - latest is recommended
- ALWAYS use bun run test (NOT
bun testdirectly) - this is critical! - E2E tests are separate - run with
bun run e2e - Clean install after version changes
- Version check runs automatically before tests
- bunfig.toml disables Bun's test runner - do not modify this file
Following these guidelines ensures tests run consistently across all development machines and CI environments.