Skip to content

Commit 498f3f0

Browse files
authored
Merge pull request #19 from linuxfoundation/feat/playwright-tests
test: add comprehensive E2E testing with Playwright and CI workflows
2 parents 1383cf6 + 15c967c commit 498f3f0

31 files changed

+3161
-1599
lines changed

.github/workflows/e2e-tests.yml

Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
# Copyright The Linux Foundation and each contributor to LFX.
2+
# SPDX-License-Identifier: MIT
3+
4+
name: E2E Tests
5+
6+
permissions:
7+
id-token: write
8+
contents: read
9+
issues: write
10+
pull-requests: write
11+
12+
on:
13+
workflow_call:
14+
inputs:
15+
node-version:
16+
description: 'Node.js version to use'
17+
required: false
18+
default: '22'
19+
type: string
20+
test-command:
21+
description: 'Test command to run'
22+
required: false
23+
default: 'e2e'
24+
type: string
25+
browser:
26+
description: 'Browser to test (chromium, firefox, mobile-chrome, or all)'
27+
required: false
28+
default: 'all'
29+
type: string
30+
base-url:
31+
description: 'Base URL for testing'
32+
required: false
33+
default: 'http://localhost:4200'
34+
type: string
35+
skip-build:
36+
description: 'Skip building the application (use existing build)'
37+
required: false
38+
default: false
39+
type: boolean
40+
secrets:
41+
TEST_USERNAME:
42+
description: 'Username for test authentication'
43+
required: false
44+
TEST_PASSWORD:
45+
description: 'Password for test authentication'
46+
required: false
47+
outputs:
48+
test-results:
49+
description: 'Test results summary'
50+
value: ${{ jobs.e2e-tests.outputs.test-results }}
51+
report-url:
52+
description: 'URL to the test report artifact'
53+
value: ${{ jobs.e2e-tests.outputs.report-url }}
54+
55+
jobs:
56+
e2e-tests:
57+
name: Playwright E2E Tests
58+
runs-on: ubuntu-latest
59+
timeout-minutes: 30
60+
61+
outputs:
62+
test-results: ${{ steps.test-results.outputs.results }}
63+
report-url: ${{ steps.upload-report.outputs.artifact-url }}
64+
65+
steps:
66+
- name: Checkout code
67+
uses: actions/checkout@v4
68+
with:
69+
fetch-depth: 0
70+
71+
- name: Enable Corepack
72+
run: corepack enable
73+
74+
- name: Setup Node.js
75+
uses: actions/setup-node@v4
76+
with:
77+
node-version: ${{ inputs.node-version }}
78+
cache: 'yarn'
79+
80+
- name: Install dependencies
81+
run: yarn install --immutable
82+
83+
- name: OIDC Auth
84+
uses: aws-actions/configure-aws-credentials@v4
85+
id: oidc-auth
86+
with:
87+
audience: sts.amazonaws.com
88+
role-to-assume: arn:aws:iam::788942260905:role/github-actions-deploy
89+
aws-region: us-west-2
90+
91+
- name: Read secrets from AWS Secrets Manager into environment variables
92+
id: get_secrets
93+
uses: aws-actions/aws-secretsmanager-get-secrets@v2
94+
with:
95+
secret-ids: |
96+
SUPABASE, /cloudops/managed-secrets/cloud/supabase/api_key
97+
AUTH0, /cloudops/managed-secrets/auth0/LFX_V2_PCC
98+
99+
- name: Setup Turborepo cache
100+
uses: actions/cache@v4
101+
with:
102+
path: |
103+
.turbo
104+
node_modules/.cache/turbo
105+
key: ${{ runner.os }}-turbo-${{ hashFiles('**/yarn.lock') }}-${{ hashFiles('**/*', '!**/node_modules/**', '!**/.turbo/**') }}
106+
restore-keys: |
107+
${{ runner.os }}-turbo-${{ hashFiles('**/yarn.lock') }}-
108+
${{ runner.os }}-turbo-
109+
110+
- name: Validate required secrets for E2E testing
111+
id: validate-secrets
112+
run: |
113+
missing_secrets=""
114+
115+
# Check AWS Secrets Manager secrets (masked environment variables)
116+
if [ -z "$AUTH0" ]; then
117+
missing_secrets="$missing_secrets AUTH0 (from AWS Secrets Manager)"
118+
fi
119+
if [ -z "$SUPABASE" ]; then
120+
missing_secrets="$missing_secrets SUPABASE (from AWS Secrets Manager)"
121+
fi
122+
123+
# Check GitHub secrets (fallback)
124+
if [ -z "${{ secrets.TEST_USERNAME }}" ]; then
125+
missing_secrets="$missing_secrets TEST_USERNAME"
126+
fi
127+
if [ -z "${{ secrets.TEST_PASSWORD }}" ]; then
128+
missing_secrets="$missing_secrets TEST_PASSWORD"
129+
fi
130+
131+
if [ -n "$missing_secrets" ]; then
132+
echo "❌ Missing required secrets for E2E testing:$missing_secrets"
133+
echo "Please configure these secrets to enable E2E tests."
134+
echo "can_run_tests=false" >> $GITHUB_OUTPUT
135+
else
136+
echo "✅ All required secrets are configured"
137+
echo "can_run_tests=true" >> $GITHUB_OUTPUT
138+
fi
139+
140+
- name: Set up non-sensitive environment variables
141+
if: steps.validate-secrets.outputs.can_run_tests == 'true'
142+
run: |
143+
echo "ENV=development" >> $GITHUB_ENV
144+
echo "PCC_BASE_URL=http://localhost:4200" >> $GITHUB_ENV
145+
echo "PCC_AUTH0_ISSUER_BASE_URL=https://linuxfoundation-dev.auth0.com/" >> $GITHUB_ENV
146+
echo "PCC_AUTH0_AUDIENCE=https://api-gw.dev.platform.linuxfoundation.org/" >> $GITHUB_ENV
147+
echo "CI=true" >> $GITHUB_ENV
148+
149+
- name: Set up sensitive environment variables
150+
if: steps.validate-secrets.outputs.can_run_tests == 'true'
151+
run: |
152+
# Parse and set AUTH0 secrets with explicit masking
153+
if [ -n "$AUTH0" ]; then
154+
AUTH0_CLIENT_ID=$(echo "$AUTH0" | jq -r '.client_id // empty')
155+
AUTH0_CLIENT_SECRET=$(echo "$AUTH0" | jq -r '.client_secret // empty')
156+
157+
# Explicitly mask the values
158+
echo "::add-mask::$AUTH0_CLIENT_ID"
159+
echo "::add-mask::$AUTH0_CLIENT_SECRET"
160+
161+
# Set as environment variables
162+
echo "PCC_AUTH0_CLIENT_ID=$AUTH0_CLIENT_ID" >> $GITHUB_ENV
163+
echo "PCC_AUTH0_CLIENT_SECRET=$AUTH0_CLIENT_SECRET" >> $GITHUB_ENV
164+
echo "✅ AUTH0 secrets set as masked environment variables"
165+
fi
166+
167+
# Parse and set SUPABASE secrets
168+
if [ -n "$SUPABASE" ]; then
169+
SUPABASE_URL=$(echo "$SUPABASE" | jq -r '.url // empty')
170+
SUPABASE_API_KEY=$(echo "$SUPABASE" | jq -r '.api_key // empty')
171+
172+
# Explicitly mask the values
173+
echo "::add-mask::$SUPABASE_URL"
174+
echo "::add-mask::$SUPABASE_API_KEY"
175+
176+
# Set as environment variables
177+
echo "SUPABASE_URL=$SUPABASE_URL" >> $GITHUB_ENV
178+
echo "POSTGRES_API_KEY=$SUPABASE_API_KEY" >> $GITHUB_ENV
179+
echo "✅ SUPABASE secrets set as masked environment variables"
180+
fi
181+
182+
# Set test credentials
183+
echo "::add-mask::${{ secrets.TEST_USERNAME }}"
184+
echo "::add-mask::${{ secrets.TEST_PASSWORD }}"
185+
echo "TEST_USERNAME=${{ secrets.TEST_USERNAME }}" >> $GITHUB_ENV
186+
echo "TEST_PASSWORD=${{ secrets.TEST_PASSWORD }}" >> $GITHUB_ENV
187+
188+
- name: Install Playwright browsers
189+
if: steps.validate-secrets.outputs.can_run_tests == 'true'
190+
working-directory: apps/lfx-pcc
191+
run: npx playwright install --with-deps
192+
193+
- name: Create Playwright auth directory
194+
if: steps.validate-secrets.outputs.can_run_tests == 'true'
195+
working-directory: apps/lfx-pcc
196+
run: mkdir -p playwright/.auth
197+
198+
- name: Build the application
199+
if: steps.validate-secrets.outputs.can_run_tests == 'true'
200+
run: yarn build
201+
202+
- name: Run E2E tests (All browsers)
203+
if: ${{ inputs.browser == 'all' && steps.validate-secrets.outputs.can_run_tests == 'true' }}
204+
working-directory: apps/lfx-pcc
205+
run: |
206+
if [ -n "$TEST_USERNAME" ] && [ -n "$TEST_PASSWORD" ]; then
207+
echo "🔐 Running authenticated E2E tests on all browsers"
208+
echo "🚀 Playwright will automatically start the dev server on localhost:4200"
209+
echo "📋 Using secrets from AWS Secrets Manager"
210+
yarn ${{ inputs.test-command }} --reporter=list
211+
else
212+
echo "⚠️ No test credentials provided. Skipping E2E tests."
213+
echo "Set TEST_USERNAME and TEST_PASSWORD secrets to enable E2E tests."
214+
exit 0
215+
fi
216+
217+
- name: Run E2E tests (Specific browser)
218+
if: ${{ inputs.browser != 'all' && steps.validate-secrets.outputs.can_run_tests == 'true' }}
219+
working-directory: apps/lfx-pcc
220+
run: |
221+
if [ -n "$TEST_USERNAME" ] && [ -n "$TEST_PASSWORD" ]; then
222+
echo "🔐 Running authenticated E2E tests on ${{ inputs.browser }}"
223+
echo "🚀 Playwright will automatically start the dev server on localhost:4200"
224+
echo "📋 Using secrets from AWS Secrets Manager"
225+
yarn ${{ inputs.test-command }} --project=${{ inputs.browser }} --reporter=list
226+
else
227+
echo "⚠️ No test credentials provided. Skipping E2E tests."
228+
echo "Set TEST_USERNAME and TEST_PASSWORD secrets to enable E2E tests."
229+
exit 0
230+
fi
231+
232+
- name: E2E tests skipped
233+
if: ${{ steps.validate-secrets.outputs.can_run_tests == 'false' }}
234+
run: |
235+
echo "⏭️ E2E tests skipped due to missing required secrets"
236+
echo "Configure the following secrets to enable E2E testing:"
237+
echo ""
238+
echo "AWS Secrets Manager (required):"
239+
echo " - /cloudops/managed-secrets/auth0/LFX_V2_PCC (AUTH0 configuration)"
240+
echo " - /cloudops/managed-secrets/cloud/supabase/api_key (SUPABASE configuration)"
241+
echo ""
242+
echo "GitHub Secrets (required for authenticated tests):"
243+
echo " - TEST_USERNAME"
244+
echo " - TEST_PASSWORD"
245+
246+
- name: Generate test results summary
247+
id: test-results
248+
if: always()
249+
working-directory: apps/lfx-pcc
250+
run: |
251+
if [ "${{ steps.validate-secrets.outputs.can_run_tests }}" == "false" ]; then
252+
echo "⏭️ E2E tests skipped (missing required secrets)"
253+
echo "results=skipped" >> $GITHUB_OUTPUT
254+
elif [ -z "$TEST_USERNAME" ] || [ -z "$TEST_PASSWORD" ]; then
255+
echo "⏭️ E2E tests skipped (no test credentials)"
256+
echo "results=skipped" >> $GITHUB_OUTPUT
257+
elif [ -f "test-results/.last-run.json" ]; then
258+
echo "✅ E2E tests completed successfully"
259+
echo "results=success" >> $GITHUB_OUTPUT
260+
else
261+
echo "❌ E2E tests failed"
262+
echo "results=failure" >> $GITHUB_OUTPUT
263+
fi
264+
265+
- name: Upload Playwright report
266+
id: upload-report
267+
uses: actions/upload-artifact@v4
268+
if: always()
269+
with:
270+
name: playwright-report-${{ inputs.browser }}-${{ github.run_id }}
271+
path: |
272+
apps/lfx-pcc/playwright-report/
273+
retention-days: 7
274+
275+
- name: Comment test results on PR
276+
if: github.event_name == 'pull_request' && always()
277+
uses: actions/github-script@v7
278+
with:
279+
script: |
280+
const results = '${{ steps.test-results.outputs.results }}';
281+
const browser = '${{ inputs.browser }}';
282+
const runId = '${{ github.run_id }}';
283+
284+
let emoji, status, details;
285+
286+
if (results === 'success') {
287+
emoji = '✅';
288+
status = 'passed';
289+
details = 'All E2E tests passed successfully.';
290+
} else if (results === 'failure') {
291+
emoji = '❌';
292+
status = 'failed';
293+
details = 'Some E2E tests failed. Check the [test report](https://github.com/${{ github.repository }}/actions/runs/' + runId + ') for details.';
294+
} else {
295+
emoji = '⏭️';
296+
status = 'skipped';
297+
details = 'E2E tests were skipped (no test credentials provided).';
298+
}
299+
300+
const comment = `## ${emoji} E2E Tests ${status.charAt(0).toUpperCase() + status.slice(1)}
301+
302+
**Browser:** ${browser}
303+
**Status:** ${status}
304+
305+
${details}
306+
307+
<details>
308+
<summary>Test Configuration</summary>
309+
310+
- **Node.js:** ${{ inputs.node-version }}
311+
- **Command:** \`${{ inputs.test-command }}\`
312+
- **Browser:** ${browser}
313+
- **Base URL:** ${{ inputs.base-url }}
314+
315+
</details>`;
316+
317+
// Look for existing E2E test comment by this bot
318+
const existingComments = await github.rest.issues.listComments({
319+
issue_number: context.issue.number,
320+
owner: context.repo.owner,
321+
repo: context.repo.repo
322+
});
323+
324+
const botComment = existingComments.data.find(comment =>
325+
comment.user.login === 'github-actions[bot]' &&
326+
comment.body.includes('## ') &&
327+
comment.body.includes('E2E Tests')
328+
);
329+
330+
if (botComment) {
331+
// Update existing comment
332+
await github.rest.issues.updateComment({
333+
comment_id: botComment.id,
334+
owner: context.repo.owner,
335+
repo: context.repo.repo,
336+
body: comment
337+
});
338+
console.log('Updated existing E2E test comment');
339+
} else {
340+
// Create new comment
341+
await github.rest.issues.createComment({
342+
issue_number: context.issue.number,
343+
owner: context.repo.owner,
344+
repo: context.repo.repo,
345+
body: comment
346+
});
347+
console.log('Created new E2E test comment');
348+
}

.github/workflows/quality-check.yml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,17 @@ jobs:
7070
with:
7171
name: turbo-cache-summary
7272
path: .turbo/
73-
retention-days: 1
73+
retention-days: 1
74+
75+
e2e-tests:
76+
name: E2E Tests
77+
needs: quality-checks
78+
uses: ./.github/workflows/e2e-tests.yml
79+
with:
80+
node-version: '22'
81+
test-command: 'e2e'
82+
browser: 'chromium' # Use only Chromium for PR testing for faster feedback
83+
skip-build: false
84+
secrets:
85+
TEST_USERNAME: ${{ secrets.TEST_USERNAME }}
86+
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

0 commit comments

Comments
 (0)