Skip to content

Commit 37ced6c

Browse files
committed
Add E2E tests for ServiceNow IDP app
1 parent 50bf894 commit 37ced6c

25 files changed

+2821
-1
lines changed

.github/workflows/e2e.yml

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
name: ServiceNow IDP App E2E Tests
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [ main ]
7+
pull_request:
8+
branches: [ main ]
9+
10+
# Serialize E2E tests to prevent deployment and UI collisions
11+
concurrency:
12+
group: e2e-tests-${{ github.repository }}
13+
cancel-in-progress: false # Let running tests finish before starting new ones
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
e2e:
20+
runs-on: ubuntu-latest
21+
timeout-minutes: 15
22+
if: github.actor != 'dependabot[bot]'
23+
env:
24+
FOUNDRY_API_CLIENT_ID: ${{ secrets.FOUNDRY_API_CLIENT_ID }}
25+
FOUNDRY_API_CLIENT_SECRET: ${{ secrets.FOUNDRY_API_CLIENT_SECRET }}
26+
FOUNDRY_CID: ${{ secrets.FOUNDRY_CID }}
27+
FOUNDRY_CLOUD_REGION: ${{ secrets.FOUNDRY_CLOUD_REGION }}
28+
steps:
29+
- name: Harden Runner
30+
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
31+
with:
32+
egress-policy: audit
33+
34+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
35+
36+
- name: Set up Homebrew
37+
uses: Homebrew/actions/setup-homebrew@1ccc07ccd8b9519f44d3e5eaa1b41dd90310adf0 # master
38+
39+
- name: Install required tools
40+
run: |
41+
brew tap crowdstrike/foundry-cli
42+
brew install crowdstrike/foundry-cli/foundry yq
43+
44+
- name: Create directory for Foundry CLI
45+
run: mkdir -p ~/.config/foundry
46+
47+
- name: Prepare app manifest
48+
run: |
49+
# Remove IDs from manifest
50+
yq -i 'del(.. | select(has("id")).id) | del(.. | select(has("app_id")).app_id)' manifest.yml
51+
52+
# Generate unique app name with length safety
53+
REPO_NAME="${{ github.event.repository.name }}"
54+
ACTOR="${{ github.actor }}"
55+
SHORT_ACTOR="${ACTOR/dependabot\[bot\]/deps}"
56+
UNIQUE_NAME="${REPO_NAME}-${SHORT_ACTOR}-$(date +"%m%d%H%M")"
57+
58+
# Truncate if too long by removing foundry- prefix
59+
if [ ${#UNIQUE_NAME} -gt 50 ]; then
60+
REPO_BASE="${REPO_NAME#foundry-}"
61+
UNIQUE_NAME="${REPO_BASE}-${SHORT_ACTOR}-$(date +"%m%d%H%M")"
62+
fi
63+
64+
# Export for yq and set the manifest name
65+
export UNIQUE_NAME
66+
yq -i '.name = env(UNIQUE_NAME)' manifest.yml
67+
68+
# Set app name as environment variable
69+
APP_NAME=$(yq '.name' manifest.yml)
70+
echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV
71+
72+
echo "Prepared manifest with app name: $APP_NAME"
73+
74+
- name: Deploy app to Falcon
75+
run: |
76+
foundry apps deploy --change-type=major --change-log="e2e deploy"
77+
echo "App deployment initiated"
78+
79+
- name: Wait for deployment and release app
80+
run: |
81+
echo "Waiting for deployment to complete..."
82+
timeout=300 # 5 minute timeout
83+
elapsed=0
84+
85+
while [ $elapsed -lt $timeout ]; do
86+
if foundry apps list-deployments | grep -i "successful"; then
87+
echo "Deployment successful, releasing app..."
88+
foundry apps release --change-type=major --notes="e2e release"
89+
echo "App released successfully"
90+
91+
# Brief wait for release to complete - E2E tests handle app discovery with retries
92+
echo "Allowing brief time for release to complete..."
93+
sleep 15
94+
95+
# Verify deployment status and get app details
96+
echo "Verifying final deployment status..."
97+
foundry apps list-deployments
98+
99+
echo "Final deployed app name: $APP_NAME"
100+
101+
exit 0
102+
fi
103+
104+
if foundry apps list-deployments | grep -i "failed"; then
105+
echo "Deployment failed"
106+
exit 1
107+
fi
108+
109+
sleep 5
110+
elapsed=$((elapsed + 5))
111+
done
112+
113+
echo "Deployment timeout after ${timeout} seconds"
114+
exit 1
115+
116+
# Parallelize Node setup while deployment happens
117+
- name: Install Node LTS
118+
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
119+
with:
120+
node-version: 22
121+
cache: 'npm'
122+
cache-dependency-path: e2e/package-lock.json
123+
124+
- name: Install dependencies
125+
run: npm ci
126+
working-directory: e2e
127+
128+
- name: Install Playwright browsers
129+
run: npx playwright install chromium --with-deps
130+
working-directory: e2e
131+
132+
- name: Make envfile
133+
uses: SpicyPizza/create-envfile@6da099c0b655bd3abd8273c4e2fe7c59e63fa88a # v2
134+
with:
135+
envkey_FALCON_USERNAME: ${{ secrets.FALCON_USERNAME }}
136+
envkey_FALCON_PASSWORD: ${{ secrets.FALCON_PASSWORD }}
137+
envkey_FALCON_AUTH_SECRET: ${{ secrets.FALCON_AUTH_SECRET }}
138+
envkey_APP_NAME: $APP_NAME
139+
directory: e2e
140+
141+
- name: Run Playwright tests
142+
run: npx dotenvx run --quiet -- npx playwright test
143+
working-directory: e2e
144+
env:
145+
CI: true
146+
147+
- name: Upload Playwright report
148+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
149+
if: ${{ !cancelled() }}
150+
with:
151+
name: playwright-report-${{ env.APP_NAME }}
152+
path: e2e/playwright-report/
153+
retention-days: 7
154+
155+
- name: Upload test results and screenshots
156+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5
157+
if: ${{ !cancelled() }}
158+
with:
159+
name: playwright-test-results-${{ env.APP_NAME }}
160+
path: e2e/test-results/
161+
retention-days: 7
162+
163+
- name: Delete app from Falcon
164+
if: always()
165+
run: |
166+
echo "Deleting app: $APP_NAME"
167+
foundry apps delete -f || echo "App deletion failed, may already be deleted"

e2e/.env.sample

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Falcon Authentication
2+
FALCON_USERNAME=[email protected]
3+
FALCON_PASSWORD=your-password
4+
FALCON_AUTH_SECRET=your-totp-secret
5+
FALCON_BASE_URL=https://falcon.us-2.crowdstrike.com
6+
7+
# App Configuration
8+
APP_NAME=foundry-sample-servicenow-idp

e2e/.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# .dotenvx
2+
.env
3+
.env.keys
4+
5+
# IntelliJ IDEA
6+
.idea
7+
8+
# Playwright
9+
node_modules/
10+
/test-results/
11+
/playwright/
12+
/playwright-report/
13+
/blob-report/
14+
/playwright/.cache/

e2e/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# E2E Tests
2+
3+
End-to-end tests for the ServiceNow IDP Foundry app using Playwright.
4+
5+
## Tests Included
6+
7+
- **Workflow Verification**: Verifies that the app's workflows are deployed and accessible in Fusion SOAR
8+
9+
## About This App
10+
11+
This app synchronizes ServiceNow Configuration Management Database (CMDB) configuration rules with Identity Protection policies. It includes two workflows for synchronizing policy rules and managing checkpoints. The E2E tests verify that both workflows are properly deployed and discoverable.
12+
13+
## Setup
14+
15+
```bash
16+
npm ci
17+
npx playwright install chromium
18+
cp .env.sample .env
19+
# Edit .env with your credentials
20+
```
21+
22+
## Run Tests
23+
24+
```bash
25+
npm test # All tests
26+
npm run test:debug # Debug mode
27+
npm run test:ui # Interactive UI
28+
```
29+
30+
## Environment Variables
31+
32+
```env
33+
APP_NAME=foundry-sample-servicenow-idp
34+
FALCON_BASE_URL=https://falcon.us-2.crowdstrike.com
35+
FALCON_USERNAME=your-username
36+
FALCON_PASSWORD=your-password
37+
FALCON_AUTH_SECRET=your-mfa-secret
38+
```
39+
40+
**Important:** The `APP_NAME` must exactly match the app name as deployed in Falcon.
41+
42+
## Test Flow
43+
44+
1. **Setup**: Authenticates and installs the app
45+
2. **Workflow Verification**:
46+
- Searches for both workflows
47+
- Verifies both workflows are discoverable in Fusion SOAR
48+
3. **Teardown**: Uninstalls the app
49+
50+
## CI/CD
51+
52+
Tests run automatically in GitHub Actions on push/PR to main. The workflow deploys the app, runs tests, and cleans up.

e2e/constants/AuthFile.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const AuthFile = 'playwright/.auth/user.json';

0 commit comments

Comments
 (0)