@@ -99,14 +99,18 @@ jobs:
9999 working-directory : ./smoke-tests/otel-collector
100100 run : bats .
101101 e2e-tests :
102- name : End-to-End Tests
102+ name : E2E Tests - Shard ${{ matrix.shard }}
103103 runs-on : ubuntu-24.04
104104 timeout-minutes : 15
105105 container :
106106 image : mcr.microsoft.com/playwright:v1.57.0-jammy
107107 permissions :
108108 contents : read
109109 pull-requests : write
110+ strategy :
111+ fail-fast : false
112+ matrix :
113+ shard : [1, 2, 3, 4]
110114
111115 steps :
112116 - name : Checkout
@@ -128,60 +132,94 @@ jobs:
128132 - name : Run Playwright tests
129133 run : |
130134 cd packages/app
131- yarn test:e2e
135+ yarn test:e2e --shard=${{ matrix.shard }}/4
132136
133137 - name : Upload Playwright report
134138 uses : actions/upload-artifact@v4
135139 if : always()
136140 with :
137- name : playwright-report
141+ name : playwright-report-${{ matrix.shard }}
138142 path : packages/app/playwright-report/
139143 retention-days : 30
140144
141145 - name : Upload test results
142146 uses : actions/upload-artifact@v4
143147 if : always()
144148 with :
145- name : test-results
149+ name : test-results-${{ matrix.shard }}
146150 path : packages/app/test-results/
147151 retention-days : 30
148152
149- - name : Generate test results message
153+ e2e-report :
154+ name : End-to-End Tests
155+ if : always()
156+ needs : e2e-tests
157+ runs-on : ubuntu-24.04
158+ permissions :
159+ contents : read
160+ pull-requests : write
161+
162+ steps :
163+ - name : Download all test results
164+ uses : actions/download-artifact@v4
165+ with :
166+ pattern : test-results-*
167+ path : all-test-results
168+
169+ - name : Aggregate test results
150170 id : test-results
151- if : always() && github.event_name == 'pull_request'
171+ if : github.event_name == 'pull_request'
152172 uses : actions/github-script@v7
153173 with :
154174 result-encoding : string
155175 script : |
156176 const fs = require('fs');
157177 const path = require('path');
158178
179+ let totalPassed = 0;
180+ let totalFailed = 0;
181+ let totalFlaky = 0;
182+ let totalSkipped = 0;
183+ let totalDuration = 0;
184+ let foundResults = false;
185+
159186 try {
160- const resultsPath = path.join('packages/app/test-results/results.json');
161- if (fs.existsSync(resultsPath)) {
162- const results = JSON.parse(fs.readFileSync(resultsPath, 'utf8'));
163- const { stats } = results;
164-
165- const failed = stats.unexpected || 0;
166- const passed = stats.expected || 0;
167- const flaky = stats.flaky || 0;
168- const skipped = stats.skipped || 0;
169- const duration = Math.round((stats.duration || 0) / 1000);
170-
171- const summary = failed > 0
172- ? `❌ **${failed} test${failed > 1 ? 's' : ''} failed**`
187+ const resultsDir = 'all-test-results';
188+ const shards = fs.readdirSync(resultsDir);
189+
190+ for (const shard of shards) {
191+ const resultsPath = path.join(resultsDir, shard, 'results.json');
192+ if (fs.existsSync(resultsPath)) {
193+ foundResults = true;
194+ const results = JSON.parse(fs.readFileSync(resultsPath, 'utf8'));
195+ const { stats } = results;
196+
197+ totalPassed += stats.expected || 0;
198+ totalFailed += stats.unexpected || 0;
199+ totalFlaky += stats.flaky || 0;
200+ totalSkipped += stats.skipped || 0;
201+ totalDuration += stats.duration || 0;
202+ }
203+ }
204+
205+ if (foundResults) {
206+ const duration = Math.round(totalDuration / 1000);
207+ const summary = totalFailed > 0
208+ ? `❌ **${totalFailed} test${totalFailed > 1 ? 's' : ''} failed**`
173209 : `✅ **All tests passed**`;
174210
175211 return `## E2E Test Results
176212
177- ${summary} • ${passed } passed • ${skipped } skipped • ${duration}s
213+ ${summary} • ${totalPassed } passed • ${totalSkipped } skipped • ${duration}s
178214
179215 | Status | Count |
180216 |--------|-------|
181- | ✅ Passed | ${passed} |
182- | ❌ Failed | ${failed} |
183- | ⚠️ Flaky | ${flaky} |
184- | ⏭️ Skipped | ${skipped} |
217+ | ✅ Passed | ${totalPassed} |
218+ | ❌ Failed | ${totalFailed} |
219+ | ⚠️ Flaky | ${totalFlaky} |
220+ | ⏭️ Skipped | ${totalSkipped} |
221+
222+ Tests ran across ${shards.length} shards in parallel.
185223
186224 [View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
187225 } else {
@@ -195,7 +233,7 @@ jobs:
195233 console.log('Could not parse test results:', error.message);
196234 return `## E2E Test Results
197235
198- ❌ **Error reading test results**
236+ ❌ **Error reading test results**: ${error.message}
199237
200238 [View full report →](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})`;
201239 }
@@ -206,3 +244,31 @@ jobs:
206244 with :
207245 message : ${{ steps.test-results.outputs.result }}
208246 message-id : e2e-test-results
247+
248+ - name : Check test results
249+ uses : actions/github-script@v7
250+ with :
251+ script : |
252+ const fs = require('fs');
253+ const path = require('path');
254+
255+ let totalFailed = 0;
256+
257+ try {
258+ const resultsDir = 'all-test-results';
259+ const shards = fs.readdirSync(resultsDir);
260+
261+ for (const shard of shards) {
262+ const resultsPath = path.join(resultsDir, shard, 'results.json');
263+ if (fs.existsSync(resultsPath)) {
264+ const results = JSON.parse(fs.readFileSync(resultsPath, 'utf8'));
265+ totalFailed += results.stats.unexpected || 0;
266+ }
267+ }
268+
269+ if (totalFailed > 0) {
270+ core.setFailed(`${totalFailed} test(s) failed`);
271+ }
272+ } catch (error) {
273+ core.setFailed(`Failed to read test results: ${error.message}`);
274+ }
0 commit comments