-
Notifications
You must be signed in to change notification settings - Fork 674
Add the e2e/playwright package with the component test infrastructure #34959
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
aleksei-semikozov
wants to merge
18
commits into
DevExpress:main
Choose a base branch
from
aleksei-semikozov:playwright-components-infra
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
f620a4a
Migrate wrappers e2e tests from TestCafe to Playwright
6213e22
Address review: validate port, read CI versions in docker script, doc…
8c224ab
Keep Chrome scrollbars visible and align the local container with the…
0632420
Upload the Playwright report and traces as separate CI artifacts, add…
8734d88
Shorten the artifact upload comment to the reason only
ca51622
Drop the artifact upload comment
15af875
Rewrite the wrappers static server as an ES module and drop minimist
e62c407
Trim the wrappers README to the three things it needs to answer
f827903
Trim the docker script to its usage line and drop redundant guards
ff9c146
Forward playwright arguments in the docker UI mode
8b908e3
Add the e2e/playwright package with the component test infrastructure
2173e1b
Fall back to the default theme and timezone when the matrix leaves th…
2c84240
Lint the new package in the lint workflow and keep its e2e run out of…
c8772f5
Run a theme job only on the tests that opted into that theme
2ab615b
Match the TestCafe semantics in the runner flags, the request mocks a…
9f0bf21
Name the workflow after Playwright, accept the "1 of 4" shard form an…
db2db0f
Use PivotGrid as the reference component instead of widgets another s…
a968a6f
Keep the Button and CheckBox models: the composite models build on them
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,321 @@ | ||
| name: Playwright tests | ||
|
|
||
| concurrency: | ||
| group: wf-${{github.event.pull_request.number || github.sha}}-${{github.workflow}} | ||
| cancel-in-progress: true | ||
|
|
||
| on: | ||
| pull_request: | ||
| paths-ignore: | ||
| - 'apps/**/*.md' | ||
| merge_group: | ||
| workflow_dispatch: | ||
|
|
||
| env: | ||
| NX_SKIP_NX_CACHE: ${{ contains(github.event.pull_request.labels.*.name, 'skip-cache') && 'true' || 'false' }} | ||
| RUN_TESTS: true | ||
|
|
||
| jobs: | ||
| check-should-run: | ||
| name: Check if tests should run | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| should-run: ${{ steps.check.outputs.should-run }} | ||
| styles-changed: ${{ steps.changes.outputs.styles }} | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - name: Check RUN_TESTS flag | ||
| id: check | ||
| run: echo "should-run=${{ env.RUN_TESTS }}" >> $GITHUB_OUTPUT | ||
|
|
||
| - uses: dorny/paths-filter@v4 | ||
| id: changes | ||
| with: | ||
| filters: | | ||
| styles: | ||
| - 'packages/devextreme-scss/scss/**' | ||
| - 'packages/devextreme-scss/icons/**' | ||
| - 'packages/devextreme-scss/images/**' | ||
| - 'packages/devextreme-scss/fonts/**' | ||
| - 'packages/devextreme/js/**/themes/**' | ||
| - 'e2e/playwright/helpers/accessibility/**' | ||
|
|
||
| build: | ||
| name: Build DevExtreme | ||
| needs: check-should-run | ||
| if: needs.check-should-run.outputs.should-run == 'true' | ||
|
|
||
| runs-on: devextreme-shr2 | ||
| timeout-minutes: 15 | ||
|
|
||
| steps: | ||
| - name: Get sources | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Use Node.js | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version-file: '.node-version' | ||
|
|
||
| - uses: pnpm/action-setup@v6 | ||
| with: | ||
| run_install: false | ||
|
|
||
| - name: Get pnpm store directory | ||
| shell: bash | ||
| run: | | ||
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | ||
|
|
||
| - uses: actions/cache@v5 | ||
| name: Setup pnpm cache | ||
| with: | ||
| path: ${{ env.STORE_PATH }} | ||
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-pnpm-cache | ||
|
|
||
| - uses: actions/cache@v5 | ||
| name: Setup nx cache | ||
| with: | ||
| path: | | ||
| .nx/cache | ||
| .nx/workspace-data/*.db | ||
| .nx/workspace-data/*.db-wal | ||
| .nx/workspace-data/*.db-shm | ||
| key: ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}-${{ github.sha }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}-${{ github.sha }}- | ||
| ${{ runner.os }}-nx-v2-${{ github.workflow }}-${{ github.job }}- | ||
| ${{ runner.os }}-nx-v2- | ||
|
|
||
| - name: Install dependencies | ||
| run: pnpm install --frozen-lockfile | ||
|
|
||
| - name: Build | ||
| shell: bash | ||
| env: | ||
| NODE_OPTIONS: --max-old-space-size=8192 | ||
| run: | | ||
| pnpm exec nx build devextreme-scss | ||
| pnpm exec nx build devextreme -c testing | ||
|
|
||
| - name: Zip artifacts | ||
| working-directory: ./packages/devextreme | ||
| run: | | ||
| 7z a -tzip -mx3 -mmt2 artifacts.zip artifacts ../devextreme-scss/scss/bundles | ||
|
|
||
| - name: Upload build artifacts | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: devextreme-artifacts-playwright | ||
| path: ./packages/devextreme/artifacts.zip | ||
| retention-days: 1 | ||
|
|
||
| determine-playwright-matrix: | ||
| runs-on: ubuntu-latest | ||
| name: Determine Playwright matrix | ||
| needs: check-should-run | ||
| if: needs.check-should-run.outputs.should-run == 'true' | ||
| outputs: | ||
| matrix: ${{ steps.matrix.outputs.matrix }} | ||
|
|
||
| steps: | ||
| - name: Build matrix | ||
| id: matrix | ||
| run: | | ||
| base_matrix_start=$(cat <<'JSON' | ||
| [ | ||
| { "componentFolder": "accessibility", "name": "accessibility", "concurrency": 6 } | ||
| ] | ||
| JSON | ||
| ) | ||
|
|
||
| base_matrix_end=$(cat <<'JSON' | ||
| [ | ||
| { "componentFolder": "common", "name": "common", "concurrency": 3 }, | ||
|
|
||
| { "name": "generic", "theme": "generic.light", "concurrency": 2 }, | ||
| { "name": "material", "theme": "material.blue.light", "concurrency": 2 }, | ||
| { "name": "material - compact", "theme": "material.blue.light.compact", "concurrency": 2 }, | ||
|
|
||
| { "componentFolder": "cardView", "name": "cardView" }, | ||
| { "componentFolder": "dataGrid", "name": "dataGrid (1/4)", "indices": "1/4", "concurrency": 5 }, | ||
| { "componentFolder": "dataGrid", "name": "dataGrid (2/4)", "indices": "2/4", "concurrency": 5 }, | ||
| { "componentFolder": "dataGrid", "name": "dataGrid (3/4)", "indices": "3/4", "concurrency": 5 }, | ||
| { "componentFolder": "dataGrid", "name": "dataGrid (4/4)", "indices": "4/4", "concurrency": 5 }, | ||
|
|
||
| { "componentFolder": "editors", "name": "editors" }, | ||
| { "componentFolder": "navigation", "name": "navigation", "concurrency": 6 }, | ||
|
|
||
| { "componentFolder": "scheduler/common", "name": "scheduler / common (1/3)", "indices": "1/3", "concurrency": 6 }, | ||
| { "componentFolder": "scheduler/common", "name": "scheduler / common (2/3)", "indices": "2/3", "concurrency": 6 }, | ||
| { "componentFolder": "scheduler/common", "name": "scheduler / common (3/3)", "indices": "3/3", "concurrency": 6 }, | ||
| { "componentFolder": "scheduler/viewOffset", "name": "scheduler / viewOffset (1/2)", "indices": "1/2", "concurrency": 4 }, | ||
| { "componentFolder": "scheduler/viewOffset", "name": "scheduler / viewOffset (2/2)", "indices": "2/2", "concurrency": 4 }, | ||
| { "componentFolder": "scheduler/timezones", "name": "scheduler / timezones (Europe/Berlin)", "timezone": "Europe/Berlin" }, | ||
| { "componentFolder": "scheduler/timezones", "name": "scheduler / timezones (America/Los_Angeles)", "timezone": "America/Los_Angeles" } | ||
| ] | ||
| JSON | ||
| ) | ||
|
|
||
| style_dependent_matrix=$(cat <<'JSON' | ||
| [ | ||
| { "componentFolder": "accessibility", "name": "accessibility - fluent.dark", "theme": "fluent.blue.dark", "concurrency": 6 }, | ||
| { "componentFolder": "accessibility", "name": "accessibility - material.light", "theme": "material.blue.light", "concurrency": 6 }, | ||
| { "componentFolder": "accessibility", "name": "accessibility - material.dark", "theme": "material.blue.dark", "concurrency": 6 } | ||
| ] | ||
| JSON | ||
| ) | ||
|
|
||
| matrix=$(jq -c -n \ | ||
| --argjson baseStart "$base_matrix_start" \ | ||
| --argjson baseEnd "$base_matrix_end" \ | ||
| --argjson styleDependent "$style_dependent_matrix" \ | ||
| --arg stylesChanged "${{ needs.check-should-run.outputs.styles-changed }}" \ | ||
| '{ include: ($baseStart + (if $stylesChanged == "true" then $styleDependent else [] end) + $baseEnd) }') | ||
|
|
||
| echo "matrix=$matrix" >> $GITHUB_OUTPUT | ||
|
|
||
| playwright: | ||
| name: ${{ matrix.name }}${{ !matrix.theme && ' - fluent' || '' }} | ||
| if: | | ||
| needs.check-should-run.outputs.should-run == 'true' && | ||
| needs.determine-playwright-matrix.result == 'success' && | ||
| needs.build.result == 'success' | ||
| needs: [check-should-run, build, determine-playwright-matrix] | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: ${{ fromJson(needs.determine-playwright-matrix.outputs.matrix) }} | ||
| runs-on: devextreme-shr2 | ||
| timeout-minutes: 45 | ||
|
|
||
| steps: | ||
| - name: Get sources | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Download artifacts | ||
| uses: actions/download-artifact@v8 | ||
| with: | ||
| name: devextreme-artifacts-playwright | ||
| path: ./packages/devextreme | ||
|
|
||
| - name: Unpack artifacts | ||
| working-directory: ./packages/devextreme | ||
| run: 7z x artifacts.zip -aoa | ||
|
|
||
| - name: Setup Chrome | ||
| uses: ./.github/actions/setup-chrome | ||
| with: | ||
| chrome-version: '150.0.7871.181' | ||
|
|
||
| - name: Use Node.js | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version-file: '.node-version' | ||
|
|
||
| - uses: pnpm/action-setup@v6 | ||
| with: | ||
| run_install: false | ||
|
|
||
| - name: Get pnpm store directory | ||
| shell: bash | ||
| run: | | ||
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | ||
|
|
||
| - uses: actions/cache/restore@v5 | ||
| name: Restore pnpm cache | ||
| with: | ||
| path: ${{ env.STORE_PATH }} | ||
| key: ${{ runner.os }}-pnpm-cache-${{ hashFiles('**/pnpm-lock.yaml') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-pnpm-cache | ||
|
|
||
| - name: Install dependencies | ||
| run: pnpm install --frozen-lockfile | ||
|
|
||
| - name: Run Playwright tests | ||
| working-directory: ./e2e/playwright | ||
| env: | ||
| NODE_OPTIONS: --max-old-space-size=8192 | ||
| # The browser context takes the timezone, so the agent clock is left alone. | ||
| TIMEZONE: ${{ matrix.timezone }} | ||
| run: | | ||
| THEME="--theme ${{ matrix.theme || 'fluent.blue.light' }}" | ||
| [ "${{ matrix.componentFolder }}" != "" ] && COMPONENT_FOLDER="--componentFolder ${{ matrix.componentFolder }}" | ||
| [ "${{ matrix.indices }}" != "" ] && INDICES="--indices ${{ matrix.indices }}" | ||
| [ "${{ matrix.concurrency }}" != "" ] && CONCURRENCY="--concurrency ${{ matrix.concurrency }}" | ||
| all_args="$COMPONENT_FOLDER $CONCURRENCY $INDICES $THEME" | ||
| echo "$all_args" | ||
| pnpm run test $all_args | ||
|
|
||
| - name: Sanitize job name | ||
| if: ${{ always() }} | ||
| run: echo "JOB_NAME=$(echo "${{ matrix.name }}" | tr '/' '-')" >> $GITHUB_ENV | ||
|
|
||
| - name: Upload test report | ||
| if: ${{ failure() }} | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: playwright-report-${{ env.JOB_NAME }} | ||
| path: ${{ github.workspace }}/e2e/playwright/artifacts/playwright-report | ||
| if-no-files-found: ignore | ||
|
|
||
| - name: Upload test traces and screenshot diffs | ||
| if: ${{ failure() }} | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: playwright-traces-${{ env.JOB_NAME }} | ||
| path: ${{ github.workspace }}/e2e/playwright/artifacts/test-results | ||
| if-no-files-found: ignore | ||
|
|
||
| merge-artifacts: | ||
| runs-on: ubuntu-latest | ||
| needs: [playwright] | ||
| if: ${{ always() }} | ||
|
|
||
| steps: | ||
| - name: Detect mergeable artifacts | ||
| id: mergeable-artifacts | ||
| uses: actions/github-script@v9 | ||
| with: | ||
| script: | | ||
| const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| run_id: context.runId, | ||
| per_page: 100, | ||
| }); | ||
|
|
||
| const artifactGroups = { | ||
| reports: /^playwright-report-/, | ||
| traces: /^playwright-traces-/, | ||
| }; | ||
|
|
||
| for (const [outputName, pattern] of Object.entries(artifactGroups)) { | ||
| const names = artifacts | ||
| .map((artifact) => artifact.name) | ||
| .filter((name) => pattern.test(name)); | ||
|
|
||
| core.setOutput(outputName, names.length > 0 ? 'true' : 'false'); | ||
| core.info(`${outputName}: ${names.length ? names.join(', ') : '(none)'}`); | ||
| } | ||
|
|
||
| - name: Merge test reports | ||
| if: steps.mergeable-artifacts.outputs.reports == 'true' | ||
| uses: actions/upload-artifact/merge@v7 | ||
| continue-on-error: true | ||
| with: | ||
| name: playwright-reports | ||
| pattern: playwright-report-* | ||
| separate-directories: true | ||
| delete-merged: true | ||
|
|
||
| - name: Merge test traces | ||
| if: steps.mergeable-artifacts.outputs.traces == 'true' | ||
| uses: actions/upload-artifact/merge@v7 | ||
| continue-on-error: true | ||
| with: | ||
| name: playwright-traces | ||
| pattern: playwright-traces-* | ||
| separate-directories: true | ||
| delete-merged: true | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.