feat: add WebdriverIO based E2E test setup (#4561)

This commit is contained in:
Nico Domino 2024-08-02 12:46:56 +02:00 committed by GitHub
parent c177419aee
commit e5498665b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 2595 additions and 87 deletions

View File

@ -1,4 +1,4 @@
name: Playwright Tests
name: E2E Tests
on:
schedule:
- cron: "0 6 * * *"
@ -9,34 +9,38 @@ on:
branches: [master]
jobs:
playwright:
timeout-minutes: 60
test:
name: Run WebdriverIO Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/init-env-node
- name: Get installed Playwright version
id: playwright-version
run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./apps/desktop/package.json').devDependencies['@playwright/test'].substring(1))")" >> $GITHUB_ENV
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
- name: Install Tauri OS dependencies
run: |
sudo apt update && sudo apt install -y \
libgtk-3-dev \
libayatana-appindicator3-dev \
libwebkit2gtk-4.0-dev \
webkit2gtk-driver \
xvfb
- name: Setup rust-toolchain stable
uses: dtolnay/rust-toolchain@stable
- name: Setup node latest
uses: actions/setup-node@v4
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- name: Install Playwright Browsers
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm dlx "playwright@$PLAYWRIGHT_VERSION" install --with-deps chromium
- name: Run Tests
run: cd apps/desktop && pnpm test:e2e
env:
CI: true
- name: Upload Artifacts
uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: apps/desktop/test-results/**/trace.zip
if-no-files-found: ignore
retention-days: 30
node-version: latest
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Install dependencies
shell: bash
run: pnpm install
- name: Build SvelteKit
run: pnpm build:desktop -- --mode development
- name: Build Tauri
run: pnpm build:test
- name: Install tauri-driver
run: cargo install tauri-driver@0.1.3
# Run it through `xvfb-run` to have a fake display server which allows our
# application to run headless without any changes to the code
- name: WebdriverIO
run: xvfb-run pnpm test:wdio

View File

@ -0,0 +1,6 @@
describe('GitButler', () => {
it('should have the root element', async () => {
const element = await $('body.text-base');
expect(element).toExist();
});
});

View File

@ -0,0 +1,9 @@
const DEFAULT_TIMEOUT = 5_000;
export async function findAndClick(selector, timeout) {
const button = await $(selector);
await button.waitForClickable({
timeout: timeout ?? DEFAULT_TIMEOUT
});
await browser.execute('arguments[0].click();', button);
}

View File

@ -6,6 +6,7 @@
"scripts": {
"dev": "vite --clearScreen false",
"test": "vitest run --mode development",
"test:wdio": "wdio run wdio.conf.ts",
"test:watch": "vitest --watch --mode development",
"test:e2e": "playwright test -c ./playwright.config.ts",
"test:e2e:watch": "playwright test -c ./playwright.config.ts --ui",
@ -51,6 +52,12 @@
"@types/git-url-parse": "^9.0.3",
"@types/lscache": "^1.3.4",
"@types/marked": "^5.0.2",
"@wdio/cli": "^8.39.1",
"@wdio/globals": "^8.39.1",
"@wdio/local-runner": "^8.39.1",
"@wdio/mocha-framework": "^8.39.0",
"@wdio/spec-reporter": "^8.39.0",
"@wdio/types": "^8.39.0",
"autoprefixer": "^10.4.19",
"class-transformer": "^0.5.1",
"date-fns": "^2.30.0",
@ -59,6 +66,7 @@
"inter-ui": "^4.0.2",
"lscache": "^1.3.2",
"marked": "^10.0.0",
"mocha": "^10.7.0",
"nanoevents": "^9.0.0",
"postcss": "^8.4.38",
"postcss-load-config": "^5.1.0",
@ -76,6 +84,7 @@
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log#v1",
"tauri-plugin-store-api": "github:tauri-apps/tauri-plugin-store#v1",
"tinykeys": "^2.1.0",
"ts-node": "^10.9.2",
"tslib": "^2.6.3",
"vite": "catalog:",
"vitest": "^0.34.6"

View File

@ -13,5 +13,19 @@
"strict": true,
"experimentalDecorators": true,
"types": ["vitest/importMeta"]
}
},
"include": [
"wdio.conf.ts",
".svelte-kit/ambient.d.ts",
".svelte-kit/non-ambient.d.ts",
".svelte-kit/types/**/$types.d.ts",
"vite.config.js",
"vite.config.ts",
"src/**/*.js",
"src/**/*.ts",
"src/**/*.svelte",
"tests/**/*.js",
"tests/**/*.ts",
"tests/**/*.svelte"
]
}

53
apps/desktop/wdio.conf.ts Normal file
View File

@ -0,0 +1,53 @@
import { browser } from '@wdio/globals';
import { spawn, ChildProcess } from 'node:child_process';
import os from 'node:os';
import path from 'node:path';
import type { Options } from '@wdio/types';
let tauriDriver: ChildProcess;
export const config: Options.WebdriverIO = {
hostname: '127.0.0.1',
port: 4444,
specs: ['./e2e/wdio/**/*.js'],
maxInstances: 1,
capabilities: [
{
// @ts-expect-error custom tauri capabilities
'tauri:options': {
application: '../../target/release/git-butler-dev'
}
}
],
reporters: ['spec'],
framework: 'mocha',
mochaOpts: {
ui: 'bdd',
timeout: 60000
},
autoCompileOpts: {
autoCompile: true,
tsNodeOpts: {
project: './tsconfig.json',
transpileOnly: true
}
},
waitforTimeout: 10000,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,
// ensure we are running `tauri-driver` before the session starts so that we can proxy the webdriver requests
beforeSession: () =>
(tauriDriver = spawn(path.resolve(os.homedir(), '.cargo', 'bin', 'tauri-driver'), [], {
stdio: [null, process.stdout, process.stderr]
})),
afterTest: function ({ error }: { error: Error }) {
if (error) {
browser.takeScreenshot();
}
},
afterSession: () => tauriDriver.kill()
};

View File

@ -0,0 +1,54 @@
{
"build": {
"beforeBuildCommand": "[ $CI = true ] || pnpm build:desktop -- --mode development",
"distDir": "../../apps/desktop/build"
},
"package": {
"productName": "GitButler Dev"
},
"tauri": {
"allowlist": {
"fs": {
"readFile": true,
"scope": ["$APPCACHE/archives/*", "$RESOURCE/_up_/scripts/*"]
},
"shell": {
"open": "^((https://)|(http://)|(mailto:)|(vscode://)|(vscodium://)).+"
},
"dialog": {
"open": true
},
"os": {
"all": true
},
"protocol": {
"asset": true,
"assetScope": ["$APPCACHE/images/*"]
},
"process": {
"relaunch": true
},
"window": {
"startDragging": true,
"maximize": true,
"unmaximize": true
},
"path": {
"all": true
},
"http": {
"all": true,
"request": true,
"scope": [
"https://api.anthropic.com/v1/messages",
"http://127.0.0.1:11434/api/chat",
"http://127.0.0.1:11434/api/generate",
"http://127.0.0.1:11434/api/embeddings"
]
}
},
"bundle": {
"active": false
}
}
}

View File

@ -14,8 +14,10 @@
"dev:internal-tauri": "turbo watch --filter @gitbutler/desktop dev",
"test": "turbo run test --no-daemon",
"test:watch": "pnpm --filter @gitbutler/desktop run test:watch",
"test:wdio": "pnpm --filter @gitbutler/desktop run test:wdio",
"build": "turbo run build --no-daemon",
"build:desktop": "turbo run --filter @gitbutler/desktop build --no-daemon",
"build:test": "pnpm exec tauri build --config crates/gitbutler-tauri/tauri.conf.test.json",
"check": "turbo run check --no-daemon",
"tauri": "tauri",
"lint": "turbo run //#globallint --no-daemon",

View File

@ -14,9 +14,9 @@
"experimentalDecorators": true
},
"include": [
"./svelte-kit/ambient.d.ts",
"./svelte-kit/non-ambient.d.ts",
"./svelte-kit/types/**/$types.d.ts",
".svelte-kit/ambient.d.ts",
".svelte-kit/non-ambient.d.ts",
".svelte-kit/types/**/$types.d.ts",
"vite.config.js",
"vite.config.ts",
"tokens.config.js",

File diff suppressed because it is too large Load Diff