Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
974931a
Playwright POC - migrate TestCafe E2E tests to Playwright
aleksei-semikozov Mar 22, 2026
a74ebdf
Playwright POC - improved scheduler test conversions from AI agents
aleksei-semikozov Mar 22, 2026
ca58243
Playwright POC - agent-improved test conversions
aleksei-semikozov Mar 22, 2026
214f5fc
Playwright POC - editors, navigation, common test improvements
aleksei-semikozov Mar 22, 2026
f4a3f37
Playwright POC - timezone and viewOffset test improvements
aleksei-semikozov Mar 22, 2026
0e3e343
Playwright POC - scheduler layout test improvements
aleksei-semikozov Mar 22, 2026
5eaba67
Playwright POC - dataGrid test improvements
aleksei-semikozov Mar 22, 2026
a4e0d83
Playwright POC - dragDrop, keyboard, cellsSelection improvements
aleksei-semikozov Mar 22, 2026
c763df9
Playwright POC - remaining scheduler tests (virtualScrolling, resize,…
aleksei-semikozov Mar 22, 2026
246bede
Fix CI: exclude playwright files from lint/tsconfig, remove duplicate…
aleksei-semikozov Mar 22, 2026
3a903d8
Fix TS lint: remove unused path import from playwright.config.ts
aleksei-semikozov Mar 22, 2026
5b03e91
Fix Playwright install: use PLAYWRIGHT_BROWSERS_PATH for non-root runner
aleksei-semikozov Mar 22, 2026
8e0c882
Playwright POC - two-pass test: generate baselines then compare
aleksei-semikozov Mar 22, 2026
d758e9a
Playwright POC - fix screenshot naming to match TestCafe baselines, t…
aleksei-semikozov Mar 24, 2026
335c6ce
Playwright POC - narrow CI to scheduler/common/month only
aleksei-semikozov Mar 24, 2026
4c1a9d7
Playwright POC - fix: use npx instead of pnpx to avoid duplicate @pla…
aleksei-semikozov Mar 24, 2026
311cb59
Playwright POC - remove merge-results job (not needed with single mat…
aleksei-semikozov Mar 24, 2026
e73f0a5
Playwright POC - sanitize artifact name to avoid NTFS char issues
aleksei-semikozov Mar 24, 2026
a9f4bd2
Playwright POC - fix TestCafe syntax leftovers across all components
aleksei-semikozov Mar 24, 2026
8a248de
Playwright POC - fix syntax errors in scheduler tests (common.spec.ts…
aleksei-semikozov Mar 24, 2026
bd88ab5
Playwright POC - expand CI to all scheduler tests (common, timezones,…
aleksei-semikozov Mar 24, 2026
00dc864
Playwright POC - add Scheduler page object (port from TestCafe model)
aleksei-semikozov Mar 24, 2026
76fa95a
Playwright POC - fix all syntax errors across dataGrid, editors, navi…
aleksei-semikozov Mar 24, 2026
6c43521
Playwright POC - remove duplicated etalons, read from TestCafe tests/…
aleksei-semikozov Mar 24, 2026
8dc9b7e
Playwright POC - remove baseline generation pass, use TestCafe etalon…
aleksei-semikozov Mar 24, 2026
ebd9ae1
Playwright POC - page objects, accessibility helper, unskip tests acr…
aleksei-semikozov Mar 24, 2026
fa81c1e
Playwright POC - unskip all remaining tests, complete page object cov…
aleksei-semikozov Mar 24, 2026
1e22ac0
Playwright POC - unskip final 32 tests, zero unconditional skips
aleksei-semikozov Mar 25, 2026
ac04a62
Playwright POC - blur focus before screenshots, hide caret and scroll…
aleksei-semikozov Mar 25, 2026
5bdb330
Playwright POC - fix full-page screenshot for tests without element, …
aleksei-semikozov Mar 25, 2026
e7a87a0
Playwright POC - fix createWidget to support callbacks via string ser…
aleksei-semikozov Mar 25, 2026
8276bae
Playwright POC - add scrollbar-width:none, keep viewport at 1200x800
aleksei-semikozov Mar 25, 2026
57218c2
Playwright POC - fix CI: set -o pipefail so test failures are not mas…
aleksei-semikozov Mar 25, 2026
94e36ee
Playwright POC - viewport 1185 to match TestCafe element widths, thre…
aleksei-semikozov Mar 25, 2026
aadcea1
Playwright POC - revert viewport to 1200 (CI etalons are at 1200/1184…
aleksei-semikozov Mar 25, 2026
006476c
Playwright POC - viewport 1185 (matches TestCafe CI etalons at 1169px…
aleksei-semikozov Mar 25, 2026
23e0943
Playwright POC - gitignore playwright-results, playwright-report, pw-…
aleksei-semikozov Mar 25, 2026
f596ab0
Playwright - fix scheduler tests (timezones timezone emulation, viewO…
aleksei-semikozov Mar 26, 2026
00acd22
Playwright - fix all scopes, expand CI to all components
aleksei-semikozov Mar 26, 2026
f8cbab8
Playwright - add canary tests to verify CI catches failures
aleksei-semikozov Mar 26, 2026
7f6e4f8
Playwright - fix editors tests (htmlEditor dialogs, dropDownButton, d…
aleksei-semikozov Mar 26, 2026
f57fb52
Playwright - fix navigation tests (scrollable, tabPanel, helpers)
aleksei-semikozov Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
173 changes: 173 additions & 0 deletions .github/workflows/playwright_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
name: Playwright tests (POC)

concurrency:
group: wf-${{github.event.pull_request.number || github.sha}}-playwright
cancel-in-progress: true

on:
pull_request:
workflow_dispatch:
inputs:
repeat_count:
description: 'Number of times to run tests (for stability check)'
required: false
default: '1'
type: string

env:
NX_SKIP_NX_CACHE: ${{ contains(github.event.pull_request.labels.*.name, 'skip-cache') && 'true' || 'false' }}

jobs:
build:
name: Build DevExtreme
runs-on: devextreme-shr2
timeout-minutes: 15

steps:
- name: Get sources
uses: actions/checkout@v4

- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- uses: pnpm/action-setup@v4
with:
run_install: false

- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- uses: actions/cache@v4
name: Setup 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: Build
shell: bash
env:
NODE_OPTIONS: --max-old-space-size=8192
run: |
pnpx nx build devextreme-scss
pnpx 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@v4
with:
name: devextreme-artifacts
path: ./packages/devextreme/artifacts.zip
retention-days: 1

playwright:
name: ${{ matrix.ARGS.name }}
needs: build
strategy:
fail-fast: false
matrix:
ARGS: [
{ componentFolder: "scheduler/common", name: "scheduler / common (1/3)", shard: "1/3" },
{ componentFolder: "scheduler/common", name: "scheduler / common (2/3)", shard: "2/3" },
{ componentFolder: "scheduler/common", name: "scheduler / common (3/3)", shard: "3/3" },
{ componentFolder: "scheduler/timezones", name: "scheduler / timezones" },
{ componentFolder: "scheduler/viewOffset", name: "scheduler / viewOffset" },
{ componentFolder: "dataGrid/common", name: "dataGrid / common (1/2)", shard: "1/2" },
{ componentFolder: "dataGrid/common", name: "dataGrid / common (2/2)", shard: "2/2" },
{ componentFolder: "dataGrid/sticky", name: "dataGrid / sticky" },
{ componentFolder: "common", name: "common (1/2)", shard: "1/2" },
{ componentFolder: "common", name: "common (2/2)", shard: "2/2" },
{ componentFolder: "editors", name: "editors (1/2)", shard: "1/2" },
{ componentFolder: "editors", name: "editors (2/2)", shard: "2/2" },
{ componentFolder: "navigation", name: "navigation" },
{ componentFolder: "cardView", name: "cardView" },
{ componentFolder: "accessibility", name: "accessibility" },
]
runs-on: devextreme-shr2
timeout-minutes: 30

steps:
- name: Get sources
uses: actions/checkout@v4

- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: devextreme-artifacts
path: ./packages/devextreme

- name: Unpack artifacts
working-directory: ./packages/devextreme
run: 7z x artifacts.zip -aoa

- uses: pnpm/action-setup@v4
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@v4
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: Install Playwright browsers
working-directory: ./e2e/testcafe-devextreme
run: npx playwright install chromium

- name: Run Playwright tests
working-directory: ./e2e/testcafe-devextreme
env:
NODE_OPTIONS: --max-old-space-size=8192
THEME: fluent.blue.light
run: |
REPEAT_COUNT="${{ github.event.inputs.repeat_count || '1' }}"
SHARD_ARG=""
if [ "${{ matrix.ARGS.shard }}" != "" ]; then
SHARD_ARG="--shard=${{ matrix.ARGS.shard }}"
fi

set -o pipefail
for i in $(seq 1 $REPEAT_COUNT); do
echo "=== Run $i / $REPEAT_COUNT ==="
npx playwright test \
--config playwright.config.ts \
playwright-tests/${{ matrix.ARGS.componentFolder }}/ \
$SHARD_ARG \
--reporter=list \
2>&1 | tee -a playwright-output-run-$i.log
echo ""
done

- name: Sanitize job name
if: always()
run: echo "JOB_NAME=$(echo "${{ matrix.ARGS.name }}" | tr '/' '-' | tr ' ' '-')" >> $GITHUB_ENV

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-results-${{ env.JOB_NAME }}
path: |
e2e/testcafe-devextreme/playwright-results/
e2e/testcafe-devextreme/playwright-output-*.log
e2e/testcafe-devextreme/test-results/
if-no-files-found: ignore
187 changes: 187 additions & 0 deletions IMPLEMENTATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Playwright Migration - Implementation Plan

## Goal

Prove that Playwright can fully replace TestCafe for screenshot/e2e tests. Both must run in CI simultaneously until Playwright is proven stable.

## Rules

- **No new screenshots** — Playwright tests must use existing TestCafe etalons from `tests/*/etalons/`
- **No deleted screenshots** — every existing etalon must be referenced
- **No deleted tests** — every TestCafe test must have a Playwright equivalent
- **No changed test logic** — page objects may differ in syntax but must verify the same behavior
- **Threshold adjustments only** — if a test doesn't pass locally due to cross-platform rendering, increase `maxDiffPixelRatio` per-test (not globally)
- **CI must report failures clearly** — if a screenshot doesn't match, the diff must appear in artifacts

## Current State

- **565 Playwright spec files** vs **620 TestCafe test files**
- **7 skipped tests** (all in scheduler/timezones)
- CI workflow exists (`playwright_tests.yml`) but only runs **scheduler** tests (common, timezones, viewOffset)
- CI runs on `devextreme-shr2` self-hosted runners
- Playwright config: viewport 1185x800, `maxDiffPixelRatio: 0.07`, `threshold: 0.2`
- Etalons are read directly from TestCafe `tests/` directory via `snapshotDir: './tests'`

## Missing Work

### 1. Expand CI to all components
Currently CI only runs scheduler tests. Need to add matrix entries for:
- `dataGrid/common`, `dataGrid/sticky`
- `editors/*`
- `navigation/*`
- `common/*` (draggable, filterBuilder, gantt, pivotGrid, treeList, etc.)
- `cardView/*`
- `accessibility/*`

### 2. Fix failing tests per scope (iterative)
Work scope-by-scope. For each scope:
1. Run tests locally: `npx playwright test playwright-tests/<scope>/`
2. Fix failures — adjust page objects, waitFor conditions, thresholds
3. Commit when scope passes locally
4. Push, verify on CI
5. While CI runs, start next scope

**Scope order** (largest/most critical first):
1. `scheduler/` — already in CI, mostly working
2. `dataGrid/` — largest component
3. `common/` — many sub-components
4. `editors/`
5. `navigation/`
6. `cardView/`
7. `accessibility/`

### 3. Verify CI failure reporting
- Intentionally break one etalon and push
- Confirm CI fails with clear error
- Confirm diff artifacts are uploaded and viewable

### 4. Run all tests together
After each scope passes individually, run full suite:
```bash
npx playwright test playwright-tests/ --reporter=list
```
Verify no cross-scope interference.

### 5. Handle stuck tests
If a test cannot be fixed after 5 attempts:
- Mark with `test.skip()` and add comment: `// TODO: Playwright migration - <reason>`
- Log the test path and failure reason in this file under "Stuck Tests" section

## How to Run

### Locally
```bash
cd e2e/testcafe-devextreme

# Single scope
npx playwright test playwright-tests/scheduler/common/ --reporter=list

# All tests
npx playwright test playwright-tests/ --reporter=list

# With UI for debugging
npx playwright test playwright-tests/scheduler/common/ --ui
```

### CI
Push to `playwright-poc` branch — workflow triggers automatically.

### CI Monitoring (gh cli)

```bash
# Check PR checks status
gh pr checks <PR_NUMBER> --repo DevExpress/DevExtreme

# View failed job logs
gh run view <RUN_ID> --repo DevExpress/DevExtreme --log-failed

# Re-run only failed jobs
gh run rerun <RUN_ID> --repo DevExpress/DevExtreme --failed

# List workflow runs for the branch
gh run list --repo DevExpress/DevExtreme --branch playwright-poc --workflow "Playwright tests (POC)"

# Watch a run in real-time
gh run watch <RUN_ID> --repo DevExpress/DevExtreme
```

- CI runs on `devextreme-shr2` self-hosted runners
- Concurrency group with `cancel-in-progress: true` — new push cancels previous run
- Playwright workflow: `.github/workflows/playwright_tests.yml`
- Artifacts: screenshot diffs are uploaded on failure for inspection

## Reporting

After each scope is completed (or if stuck), send a status update to Telegram (chat_id: 253383754) with this format:

```
Playwright Migration Status

Scope: <current scope>
Status: <passing / fixing / stuck>

Tests: <X> passing, <Y> failing, <Z> skipped
CI: <last run status — passing/failing/not started>

Progress:
✅ scheduler/common — <N> tests passing
✅ scheduler/viewOffset — <N> tests passing
🔧 dataGrid/common — fixing (<N> failing)
⬜ editors — not started
...

Stuck tests: <count>
- <test file> — <reason>
```

Send this report:
- After completing each scope
- When all scopes are done
- If stuck on a scope for more than 30 minutes

## Ralph Loop Prompt

```
Working directory: /Users/alekseisemikozov/Projects/DevExtreme/.claude/worktrees/playwright-poc/e2e/testcafe-devextreme

Task: Fix failing Playwright tests scope by scope.

Rules:
- Do NOT add/delete/modify any screenshot etalon files
- Do NOT change test logic — only fix page objects, selectors, waitFor, thresholds
- Do NOT skip tests unless they fail after 5 fix attempts
- For each scope: run tests, fix failures, run again until all pass
- If a test fails 5+ times, mark test.skip() with "// TODO: Playwright migration - <reason>" and move on
- Commit after each scope is fixed with message: "Playwright - fix <scope> tests"

Current scope order:
1. scheduler/common (verify still passes)
2. scheduler/timezones (7 skipped — try to unskip)
3. scheduler/viewOffset
4. dataGrid/common
5. dataGrid/sticky
6. common/* (each subfolder)
7. editors/*
8. navigation/*
9. cardView/*
10. accessibility/*

For each scope:
1. Run: npx playwright test playwright-tests/<scope>/ --reporter=list
2. If failures: read test code + page object, read TestCafe equivalent, fix
3. Re-run. Repeat up to 5 times per failing test.
4. When scope passes: git add + commit
5. Move to next scope

After all scopes done:
- Run full suite: npx playwright test playwright-tests/ --reporter=list
- Report results
```

## Stuck Tests

(Will be filled as tests are discovered that cannot be fixed)

| Test file | Reason | Attempts |
|-----------|--------|----------|
| | | |
4 changes: 3 additions & 1 deletion e2e/testcafe-devextreme/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/screenshots
/artifacts
/artifactsplaywright-results/
playwright-report/
pw-browsers/
4 changes: 4 additions & 0 deletions e2e/testcafe-devextreme/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export default [
{
ignores: [
'node_modules/**',
'playwright-tests/**',
'playwright-helpers/**',
'playwright-results/**',
'playwright-report/**',
],
},
...spellCheckConfig,
Expand Down
Binary file added e2e/testcafe-devextreme/images/test-image-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added e2e/testcafe-devextreme/images/test-image-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading