Skip to content

Commit 41018d0

Browse files
committed
add ui e2e tests
1 parent 81ceef6 commit 41018d0

12 files changed

Lines changed: 1503 additions & 16 deletions

File tree

Makefile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,27 @@ helm-diff: pre-check helm-dependency-update create-namespaces
257257
.PHONY: deploy-local
258258
deploy-local: helm-dependency-update create-namespaces
259259
TEST_MODE=true ./scripts/deploy/helm.sh deploy-local $(shell make tag) local
260+
261+
## Run UI E2E tests against local deployment
262+
.PHONY: test-e2e
263+
test-e2e:
264+
@echo "test-e2e starting..." >&2
265+
@echo "Waiting for infra-server to be ready..." >&2
266+
@kubectl wait --for=condition=ready pod -l app=infra-server -n infra --timeout=3m >&2 || \
267+
(echo "ERROR: infra-server pods did not become ready" >&2 && exit 1)
268+
@echo "Starting port-forward and running E2E tests..." >&2
269+
@kubectl port-forward -n infra svc/infra-server-service 8443:8443 >/dev/null 2>&1 & \
270+
PF_PID=$$!; \
271+
cleanup() { \
272+
echo "" >&2; \
273+
echo "Cleaning up port-forward (PID: $$PF_PID)..." >&2; \
274+
kill $$PF_PID 2>/dev/null || true; \
275+
}; \
276+
trap cleanup EXIT; \
277+
sleep 5; \
278+
echo "Running Cypress E2E tests..." >&2; \
279+
cd ui && BROWSER=none PORT=3001 INFRA_API_ENDPOINT=http://localhost:8443 npm run test:e2e
280+
260281
## Bounce pods
261282
.PHONY: bounce-infra-pods
262283
bounce-infra-pods:

chart/infra-server/configuration/local-values.yaml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
environment: local
22

3-
# Disable Auth0 for local development - allow anonymous access
4-
auth0:
5-
clientID: ""
6-
tenant: ""
7-
83
# Set local deploy mode to true for local development
94
localDeploy: true
105

scripts/deploy/helm.sh

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,32 @@ deploy-local() {
134134

135135
if [[ ! -f "${cert_file}" ]] || [[ ! -f "${key_file}" ]]; then
136136
echo "Generating self-signed certificate for local development..." >&2
137+
# Create a temporary config file for SAN extension
138+
local san_config=$(mktemp)
139+
cat > "${san_config}" <<EOF
140+
[req]
141+
distinguished_name = req_distinguished_name
142+
x509_extensions = v3_req
143+
prompt = no
144+
145+
[req_distinguished_name]
146+
CN = localhost
147+
148+
[v3_req]
149+
keyUsage = keyEncipherment, dataEncipherment
150+
extendedKeyUsage = serverAuth
151+
subjectAltName = @alt_names
152+
153+
[alt_names]
154+
DNS.1 = localhost
155+
IP.1 = 127.0.0.1
156+
EOF
137157
openssl req -x509 -newkey rsa:2048 -nodes \
138158
-keyout "${key_file}" \
139159
-out "${cert_file}" \
140160
-days 36500 \
141-
-subj "/CN=localhost" >&2
161+
-config "${san_config}" >&2
162+
rm -f "${san_config}"
142163
echo "Certificate generated: ${cert_file}" >&2
143164
else
144165
echo "Using existing self-signed certificate: ${cert_file}" >&2

ui/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
# testing
99
/coverage
1010

11+
# cypress
12+
cypress/videos
13+
cypress/screenshots
14+
cypress/downloads
15+
cypress.env.json
16+
1117
# production
1218
/build
1319

ui/TESTING.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Cypress E2E Testing
2+
3+
This directory contains Cypress E2E tests for the StackRox Infra UI.
4+
5+
## Quick Start - Running E2E Tests Against Local Backend
6+
7+
### Prerequisites
8+
9+
1. **Deploy the local backend** (with authentication disabled):
10+
11+
```bash
12+
# From the repository root
13+
make deploy-local
14+
```
15+
16+
This deploys the infra-server to your local Kubernetes cluster with
17+
`LOCAL_DEPLOY=true`, which disables authentication for local development.
18+
19+
2. **Start port-forwarding** to access the backend:
20+
21+
```bash
22+
kubectl port-forward -n infra svc/infra-server-service 8443:8443
23+
```
24+
25+
Keep this running in a separate terminal.
26+
27+
3. **Configure the UI to connect to local backend**:
28+
29+
```bash
30+
cd ui
31+
cp .env.example .env.local
32+
```
33+
34+
This creates a `.env.local` file. Note: The file contains
35+
`INFRA_API_ENDPOINT` but the environment variable must also be set when
36+
starting the dev server (see next step).
37+
38+
4. **Start the UI dev server** (in a separate terminal):
39+
40+
```bash
41+
cd ui
42+
BROWSER=none PORT=3001 INFRA_API_ENDPOINT=http://localhost:8443 npm start
43+
```
44+
45+
**Important:** The `INFRA_API_ENDPOINT` environment variable must be set when
46+
starting the dev server (not just in `.env.local`) because the proxy
47+
middleware reads it at startup.
48+
49+
Keep this running. The dev server will:
50+
51+
- Run on http://localhost:3001
52+
- Proxy API requests to http://localhost:8443 (your local backend)
53+
- Hot-reload when you make changes to the UI code
54+
55+
5. **Run the E2E tests** (in another terminal):
56+
57+
```bash
58+
cd ui
59+
npm run cypress:run:e2e
60+
```
61+
62+
That's it! The tests will run against the UI dev server at
63+
http://localhost:3001, which proxies API requests to your local backend at
64+
`https://localhost:8443`.
65+
66+
### Test Results
67+
68+
After the tests complete:
69+
70+
- **Videos** are saved to `ui/cypress/videos/` (one per test file)
71+
- **Screenshots** (on failures only) are saved to `ui/cypress/screenshots/`
72+
73+
Review the videos to verify the tests are properly accessing the backend.
74+
75+
## Interactive Mode
76+
77+
To run tests interactively with the Cypress UI (useful for debugging):
78+
79+
**Prerequisites:** Make sure the UI dev server is running (step 4 above).
80+
81+
```bash
82+
cd ui
83+
npm run cypress:open
84+
```
85+
86+
Then:
87+
88+
1. Select "E2E Testing"
89+
2. Choose a browser
90+
3. Click on any test file to run it
91+
92+
Interactive mode lets you see the tests run in real-time, inspect the DOM, and
93+
debug failures.
94+
95+
## Test Structure
96+
97+
- `cypress/e2e/home.cy.ts` - Basic home page tests
98+
- `cypress/e2e/flavor-selection.cy.ts` - Tests for flavor API integration
99+
100+
## Configuration
101+
102+
Tests are configured in `cypress.config.ts` to:
103+
104+
- Run against the UI dev server at `http://localhost:3001` (which proxies to the
105+
backend)
106+
- Accept self-signed certificates (`chromeWebSecurity: false`)
107+
- Capture videos of all test runs
108+
- Capture screenshots on failures only
109+
- Retry failed tests 2 times in CI mode (run mode), 0 times in interactive mode
110+
111+
The UI dev server (configured via `ui/.env.local`) proxies API requests to your
112+
local backend at `https://localhost:8443`.
113+
114+
## Adding More Tests
115+
116+
To add new E2E tests:
117+
118+
1. Create a new file in `cypress/e2e/` with the pattern `*.cy.ts`
119+
2. Follow the existing test patterns for consistency
120+
3. Run the tests locally before committing
121+
122+
## Troubleshooting
123+
124+
### Tests fail with "Cypress failed to verify that your server is running"
125+
126+
**Solution:** Make sure the UI dev server is running on port 3001 before running
127+
tests:
128+
129+
```bash
130+
cd ui
131+
BROWSER=none PORT=3001 npm start
132+
```
133+
134+
### Tests show "access denied" or authentication errors
135+
136+
**Solution:** Verify that:
137+
138+
1. The backend was deployed with `LOCAL_DEPLOY=true` (via `make deploy-local`)
139+
2. Port-forwarding is active:
140+
`kubectl port-forward -n infra svc/infra-server-service 8443:8443`
141+
3. The `.env.local` file points to the correct backend:
142+
`INFRA_API_ENDPOINT=https://localhost:8443`
143+
144+
You can check if LOCAL_DEPLOY is enabled:
145+
146+
```bash
147+
kubectl get deployment -n infra infra-server-deployment -o jsonpath='{.spec.template.spec.containers[0].env}' | grep LOCAL_DEPLOY
148+
```
149+
150+
### Port 3001 or 8443 already in use
151+
152+
**Solution:**
153+
154+
- Find and kill the process using the port: `lsof -i :3001` or `lsof -i :8443`
155+
- Or use different ports by modifying `cypress.config.ts` and `.env.local`
156+
157+
## Documentation
158+
159+
- Full Cypress documentation: https://docs.cypress.io/
160+
- Cypress Best Practices:
161+
https://docs.cypress.io/guides/references/best-practices

ui/cypress.config.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// eslint-disable-next-line import/no-extraneous-dependencies
2+
import { defineConfig } from 'cypress';
3+
import * as crypto from 'crypto';
4+
5+
export default defineConfig({
6+
e2e: {
7+
// UI dev server runs on :3001
8+
// API calls are proxied to backend at :8443 (configured via INFRA_API_ENDPOINT in setupProxy.js)
9+
// Routes proxied: /v1, /login, /callback, /logout, /downloads/infractl-*
10+
baseUrl: 'http://localhost:3001',
11+
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}',
12+
supportFile: 'cypress/support/e2e.ts',
13+
fixturesFolder: 'cypress/fixtures',
14+
screenshotsFolder: 'cypress/screenshots',
15+
videosFolder: 'cypress/videos',
16+
viewportWidth: 1280,
17+
viewportHeight: 720,
18+
video: true,
19+
screenshotOnRunFailure: true,
20+
chromeWebSecurity: false, // Allow self-signed certificates for local dev
21+
setupNodeEvents(on, config) {
22+
// Task to generate JWT tokens for local dev authentication
23+
on('task', {
24+
generateJWT({ payload, secret }: { payload: any; secret: string }) {
25+
// Create JWT header
26+
const header = {
27+
alg: 'HS256',
28+
typ: 'JWT',
29+
};
30+
31+
// Base64url encode header and payload
32+
const base64UrlEncode = (obj: any) =>
33+
Buffer.from(JSON.stringify(obj))
34+
.toString('base64')
35+
.replace(/\+/g, '-')
36+
.replace(/\//g, '_')
37+
.replace(/=/g, '');
38+
39+
const encodedHeader = base64UrlEncode(header);
40+
const encodedPayload = base64UrlEncode(payload);
41+
42+
// Create signature
43+
const signatureInput = `${encodedHeader}.${encodedPayload}`;
44+
const signature = crypto
45+
.createHmac('sha256', secret)
46+
.update(signatureInput)
47+
.digest('base64')
48+
.replace(/\+/g, '-')
49+
.replace(/\//g, '_')
50+
.replace(/=/g, '');
51+
52+
// Return complete JWT
53+
return `${encodedHeader}.${encodedPayload}.${signature}`;
54+
},
55+
});
56+
57+
return config;
58+
},
59+
env: {
60+
// Default environment variables for tests
61+
// Can be overridden via CLI or cypress.env.json
62+
API_URL: 'https://localhost:8000',
63+
},
64+
},
65+
component: {
66+
devServer: {
67+
framework: 'react',
68+
bundler: 'vite',
69+
},
70+
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
71+
supportFile: 'cypress/support/component.ts',
72+
},
73+
retries: {
74+
runMode: 2, // Retry failed tests in CI
75+
openMode: 0, // Don't retry in interactive mode
76+
},
77+
defaultCommandTimeout: 10000,
78+
requestTimeout: 10000,
79+
responseTimeout: 10000,
80+
});

0 commit comments

Comments
 (0)