Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions .github/workflows/wrapper_tests_e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,6 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Start server for ${{ matrix.framework }}
working-directory: e2e/wrappers
run: |
pnpm run start:${{ matrix.framework }} &
sleep 10

- name: Run tests for ${{ matrix.framework }}
working-directory: e2e/wrappers
run: pnpm run test:${{ matrix.framework }}
Expand All @@ -185,5 +179,7 @@ jobs:
uses: actions/upload-artifact@v7
with:
name: test-fails-${{matrix.framework}}
path: e2e/wrappers/screenshots
path: |
e2e/wrappers/playwright-report
e2e/wrappers/test-results
if-no-files-found: ignore
1 change: 0 additions & 1 deletion apps/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"webpack-dev-server": "5.2.6"
},
"scripts": {
"test": "node runner.js",
"start": "webpack-dev-server",
"build": "webpack"
},
Expand Down
1 change: 0 additions & 1 deletion apps/react/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
"!{projectRoot}/public/js/app/bundle*",
"{projectRoot}/*.tsx",
"{projectRoot}/*.js",
"!{projectRoot}/test.js",
"{projectRoot}/tsconfig.json",
"{workspaceRoot}/tsconfig.json"
],
Expand Down
17 changes: 0 additions & 17 deletions apps/react/runner.js

This file was deleted.

8 changes: 0 additions & 8 deletions apps/react/test.js

This file was deleted.

1 change: 0 additions & 1 deletion apps/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"webpack-dev-server": "5.2.6"
},
"scripts": {
"test": "node runner.js",
"start": "webpack-dev-server",
"build": "webpack"
}
Expand Down
1 change: 0 additions & 1 deletion apps/vue/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"{projectRoot}/*.ts",
"{projectRoot}/*.vue",
"{projectRoot}/*.js",
"!{projectRoot}/test.js",
"{projectRoot}/tsconfig.json"
],
"outputs": [
Expand Down
17 changes: 0 additions & 17 deletions apps/vue/runner.js

This file was deleted.

8 changes: 0 additions & 8 deletions apps/vue/test.js

This file was deleted.

2 changes: 2 additions & 0 deletions e2e/wrappers/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
playwright-report/
test-results/
73 changes: 73 additions & 0 deletions e2e/wrappers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Wrappers E2E tests

End-to-end tests that check DevExtreme components inside the React, Vue and Angular wrappers.
The tests are written with [Playwright](https://playwright.dev/) and use the system Google Chrome
(`channel: 'chrome'`), so no browser download is needed.

## Layout

| Path | Purpose |
|------------------------|----------------------------------------------------------------------|
| `builders/*` | Host applications that render the examples for each framework |
| `examples/*` | Examples under test, one folder per scenario and framework |
| `tests/*.spec.ts` | Playwright specs |
| `fixtures.ts` | `test`/`expect` with the `framework` option added |
| `playwright.config.ts` | Per-framework port, base URL and dev server |
| `serve.js` | Static server for a built application |
| `docker/` | Container that matches the CI environment |

## Run locally

```bash
pnpm install --frozen-lockfile
pnpm nx all:build-testing workflows

cd e2e/wrappers
pnpm run build:react19 # or build:vue3 / build:angular / build:all

pnpm run test:react19 # or test:vue3 / test:angular
```

`playwright test` starts `serve.js` on its own, so no separate server is needed.
Useful flags: `--headed`, `--debug`, `--ui`, `--reporter=html`.

Examples that exist for a single framework only (Chat, Gantt) are skipped in the other frameworks.

## Run in the CI environment

The container mirrors the OS, Node and Google Chrome the tests get on CI. Dependencies and
application builds are taken from the host:

```bash
cd e2e/wrappers
docker/run.sh react19
```

To drive the run from the browser on your machine, start the UI mode inside the container and
open `http://localhost:9323`:

```bash
docker run --rm --platform linux/amd64 --shm-size=2gb -p 9323:9323 \
-v "$(git rev-parse --show-toplevel):/repo" -w /repo/e2e/wrappers -e FRAMEWORK=react19 \
devextreme-wrappers-e2e \
node_modules/.bin/playwright test --ui-host=0.0.0.0 --ui-port=9323
```

The repository is mounted, so edits made on the host are picked up and the watch mode re-runs
the affected tests. Plain `--ui` is not used on purpose: it opens the interface in the bundled
Chromium, which is deliberately not installed.

Artifacts from a failed CI run are read with the same tooling:

```bash
pnpm exec playwright show-report <unpacked artifact>/playwright-report
pnpm exec playwright show-trace <unpacked artifact>/test-results/<test>/trace.zip --port 0
```

## Rendering

The default Chrome scrollbars must stay visible: they take layout space, so a page rendered
without them differs from what a user sees and from the etalons the TestCafe tests produce.
Playwright hides scrollbars in headless mode by default, so `--hide-scrollbars` is removed in
`playwright.config.ts`. Measured in the CI-like container, the scrollbar is 15px wide both here
and in TestCafe.
19 changes: 19 additions & 0 deletions e2e/wrappers/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Mirrors the environment the tests get on CI: Ubuntu 24.04, Node from .node-version and
# Google Chrome pinned to the version the workflow installs. Keep the font packages in sync
# with the CI runner image — they affect text rendering and, later, screenshot comparison.
FROM ubuntu:24.04

ARG NODE_VERSION
ARG CHROME_VERSION

RUN echo 'APT::Install-Recommends "0";' > /etc/apt/apt.conf.d/dx-no-recommends \
&& apt-get update \
&& apt-get install -y ca-certificates curl fonts-noto-color-emoji \
&& curl -fsSL "https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${CHROME_VERSION}-1_amd64.deb" -o /tmp/chrome.deb \
&& apt-get install -y /tmp/chrome.deb \
&& curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz" -o /tmp/node.tar.gz \
&& tar -xzf /tmp/node.tar.gz -C /usr/local --strip-components=1 \
&& rm /tmp/chrome.deb /tmp/node.tar.gz \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /repo/e2e/wrappers
47 changes: 47 additions & 0 deletions e2e/wrappers/docker/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash
# Runs the wrappers e2e tests in a container that matches the CI environment: Node and Google
# Chrome are taken from .node-version and from the workflow that runs these tests on CI.
# The repository is mounted as is, so dependencies must be installed and
# the app under test built on the host first:
#
# pnpm install --frozen-lockfile
# pnpm nx all:build-testing workflows
# cd e2e/wrappers && pnpm run build:react19
#
# Usage: docker/run.sh [react19|vue3|angular] [extra playwright args]

set -euo pipefail

FRAMEWORK="${1:-react19}"
shift || true

DOCKER_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$DOCKER_DIR/../../.." && pwd)"
WORKFLOW="$REPO_ROOT/.github/workflows/wrapper_tests_e2e.yml"

NODE_VERSION="$(cat "$REPO_ROOT/.node-version")"
CHROME_VERSION="$(grep -m1 'chrome-version:' "$WORKFLOW" | cut -d: -f2 | tr -d " '\"")"

if [ -z "$NODE_VERSION" ] || [ -z "$CHROME_VERSION" ]; then
echo "❌ Cannot read the Node version from .node-version or the Chrome version from $WORKFLOW." >&2
exit 1
fi

echo "Node $NODE_VERSION, Google Chrome $CHROME_VERSION"

# Google Chrome for Linux ships for amd64 only, so the platform is pinned as on CI.
PLATFORM=linux/amd64

docker build --platform "$PLATFORM" \
--build-arg "NODE_VERSION=$NODE_VERSION" \
--build-arg "CHROME_VERSION=$CHROME_VERSION" \
-t devextreme-wrappers-e2e "$DOCKER_DIR"

# Shared memory and seccomp are set as the CI runner container gets them.
docker run --rm --platform "$PLATFORM" --shm-size=2gb --security-opt seccomp=unconfined \
-v "$REPO_ROOT:/repo" \
-w /repo/e2e/wrappers \
-e CI=true \
-e "FRAMEWORK=$FRAMEWORK" \
devextreme-wrappers-e2e \
node_modules/.bin/playwright test "$@"
13 changes: 13 additions & 0 deletions e2e/wrappers/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { test as base } from '@playwright/test';

export type Framework = 'react19' | 'vue3' | 'angular';

export interface TestOptions {
framework: Framework;
}

export const test = base.extend<TestOptions>({
framework: ['react19', { option: true }],
});

export { expect } from '@playwright/test';
9 changes: 5 additions & 4 deletions e2e/wrappers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
"start:vue3": "pnpm run dev:vue3 -- --host",
"start:angular": "cd builders/angular && pnpm run start",
"build:all": "pnpm run build:react19 && pnpm run build:vue3 && pnpm run build:angular",
"test:react19": "node ./runner.js --framework=react",
"test:vue3": "node ./runner.js --framework=vue",
"test:angular": "node ./runner.js --framework=angular"
"test:react19": "cross-env FRAMEWORK=react19 playwright test",
"test:vue3": "cross-env FRAMEWORK=vue3 playwright test",
"test:angular": "cross-env FRAMEWORK=angular playwright test"
},
"dependencies": {
"@angular/common": "catalog:angular",
Expand Down Expand Up @@ -59,11 +59,13 @@
"@angular/cli": "catalog:angular",
"@angular/compiler-cli": "catalog:angular",
"@eslint/js": "catalog:",
"@playwright/test": "catalog:",
"@types/jasmine": "5.1.4",
"@types/react": "19.1.2",
"@types/react-dom": "19.1.3",
"@vitejs/plugin-react": "4.7.0",
"@vitejs/plugin-vue": "5.2.4",
"cross-env": "7.0.3",
"eslint": "9.39.4",
"eslint-plugin-react-hooks": "7.0.1",
"eslint-plugin-react-refresh": "0.5.2",
Expand All @@ -74,7 +76,6 @@
"karma-coverage": "2.2.1",
"karma-jasmine": "5.1.0",
"karma-jasmine-html-reporter": "2.1.0",
"testcafe": "catalog:",
"typescript": "5.8.3",
"vite": "8.0.16"
},
Expand Down
51 changes: 51 additions & 0 deletions e2e/wrappers/playwright.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { defineConfig } from '@playwright/test';

import type { Framework, TestOptions } from './fixtures';

const FRAMEWORK_PORTS: Record<Framework, number> = {
react19: 3030,
angular: 3031,
vue3: 3032,
};

const framework = (process.env.FRAMEWORK ?? 'react19') as Framework;
const port = FRAMEWORK_PORTS[framework];

if(!port) {
throw new Error(`Unsupported framework: ${framework}. Expected one of: ${Object.keys(FRAMEWORK_PORTS).join(', ')}.`);
}

const baseURL = `http://localhost:${port}`;

export default defineConfig<TestOptions>({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
workers: 1,
reporter: process.env.CI
? [['list'], ['html', { open: 'never' }]]
: [['list']],
timeout: 30000,
expect: { timeout: 5000 },
use: {
framework,
baseURL,
channel: 'chrome',
headless: true,
viewport: { width: 1200, height: 800 },
launchOptions: {
args: ['--no-sandbox', '--disable-gpu'],
// Playwright hides scrollbars in headless by default, so the page gets no scrollbar
// gutter and its layout differs from a real browser and from the TestCafe etalons.
ignoreDefaultArgs: ['--hide-scrollbars'],
},
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
},
webServer: {
command: `node ./serve.js --framework=${framework} --port=${port}`,
url: baseURL,
reuseExistingServer: !process.env.CI,
timeout: 30000,
},
});
Loading
Loading