Skip to content

Commit 8abe5b1

Browse files
authored
Merge pull request #152 from serveri/dev
e2e tests, code quality checks and fixes
2 parents 70a884a + 9f859d4 commit 8abe5b1

15 files changed

Lines changed: 2734 additions & 2482 deletions

File tree

.actrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
--container-architecture linux/amd64
2+
-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest

.github/workflows/playwright.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Playwright Tests (v3)
2+
on:
3+
workflow_dispatch:
4+
push:
5+
branches: [ main, master ]
6+
pull_request:
7+
branches: [ main, master ]
8+
jobs:
9+
test:
10+
timeout-minutes: 60
11+
runs-on: ubuntu-latest
12+
container:
13+
image: mcr.microsoft.com/playwright:v1.58.2-noble
14+
env:
15+
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
16+
defaults:
17+
run:
18+
working-directory: ./app
19+
steps:
20+
- uses: actions/checkout@v4
21+
- name: Install pnpm
22+
uses: pnpm/action-setup@v3
23+
with:
24+
version: 9
25+
- uses: actions/setup-node@v4
26+
with:
27+
node-version: 20
28+
cache: pnpm
29+
cache-dependency-path: app/pnpm-lock.yaml
30+
- name: CI diagnostics
31+
run: |
32+
echo "ref=${GITHUB_REF}"
33+
echo "sha=${GITHUB_SHA}"
34+
node --version
35+
pnpm --version
36+
- name: Install dependencies
37+
run: |
38+
echo "workflow-revision=v3-container-cache"
39+
pnpm install --frozen-lockfile
40+
node -e "require.resolve('@oxc-parser/binding-linux-x64-gnu')"
41+
- name: Run Playwright tests
42+
run: pnpm test:e2e
43+
- uses: actions/upload-artifact@v4
44+
if: failure()
45+
with:
46+
name: playwright-debug-artifacts
47+
path: |
48+
app/playwright-report/
49+
app/test-results/
50+
if-no-files-found: ignore
51+
retention-days: 7

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,26 @@ requests to us.
6868
1. Navigate to build repositary and run `git pull`
6969
2. Reload docker with `docker compose -f docker-compose.prod.yml up -d --build`
7070

71+
## Testing GitHub Actions locally (act)
72+
73+
This repository includes `.actrc` to hard-code the local runner mapping so `act` does not ask interactive image-size questions.
74+
75+
### Prerequisites
76+
77+
1. Docker Desktop running
78+
2. `act` installed, for example:
79+
- Windows: `winget install nektos.act`
80+
- macOS: `brew install act`
81+
- Linux: `brew install act` (via Homebrew on Linux) or see https://github.com/nektos/act#installation
82+
83+
### Run the Playwright workflow locally
84+
85+
From repository root:
86+
87+
1. `act -l`
88+
2. `act workflow_dispatch -j test -v`
89+
90+
7191
### Other
7292

7393
- Go inside container - `docker exec -it {{name}} bash`

app/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules
22
.nuxt
33
.env
44
test-results
5+
.husky

app/.husky/pre-commit

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env sh
2+
. "$(dirname -- "$0")/_/husky.sh"
3+
4+
cd app && pnpm lint-staged

app/.stylelintrc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
{
22
"extends": ["stylelint-config-recommended", "stylelint-config-standard"],
3+
"overrides": [
4+
{
5+
"files": ["**/*.vue"],
6+
"customSyntax": "postcss-html"
7+
}
8+
],
39
"rules": {
410
"at-rule-no-unknown": null
511
}
6-
}
12+
}

app/eslint.config.mjs

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,42 @@
1-
import { defineConfig } from 'eslint/config';
2-
import security from 'eslint-plugin-security';
3-
import jsxA11Y from 'eslint-plugin-jsx-a11y';
4-
import prettier from 'eslint-plugin-prettier';
1+
import pluginVue from 'eslint-plugin-vue';
2+
import pluginSecurity from 'eslint-plugin-security';
3+
import pluginJsxA11y from 'eslint-plugin-jsx-a11y';
4+
import pluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
55
import globals from 'globals';
6-
import path from 'node:path';
7-
import { fileURLToPath } from 'node:url';
86
import js from '@eslint/js';
9-
import { FlatCompat } from '@eslint/eslintrc';
7+
import tsParser from '@typescript-eslint/parser';
108

11-
const __filename = fileURLToPath(import.meta.url);
12-
const __dirname = path.dirname(__filename);
13-
const compat = new FlatCompat({
14-
baseDirectory: __dirname,
15-
recommendedConfig: js.configs.recommended,
16-
allConfig: js.configs.all,
17-
});
18-
19-
export default defineConfig([
9+
export default [
10+
js.configs.recommended,
11+
...pluginVue.configs['flat/recommended'],
12+
pluginPrettierRecommended,
2013
{
21-
// Extend Vue, jsx-a11y and Prettier configurations.
22-
extends: compat.extends('plugin:vue/recommended', 'plugin:jsx-a11y/recommended', 'plugin:prettier/recommended'),
23-
2414
plugins: {
25-
security,
26-
'jsx-a11y': jsxA11Y,
27-
prettier,
15+
security: pluginSecurity,
16+
'jsx-a11y': pluginJsxA11y,
2817
},
29-
3018
languageOptions: {
3119
globals: {
3220
...globals.browser,
3321
...globals.node,
3422
},
3523
ecmaVersion: 2021,
36-
sourceType: 'commonjs',
24+
sourceType: 'module',
3725
parserOptions: {
38-
project: './tsconfig.json',
39-
parser: '@typescript-eslint/parser',
26+
parser: tsParser,
4027
extraFileExtensions: ['.vue'],
4128
},
4229
},
43-
4430
rules: {
4531
'vue/prop-name-casing': 'off',
4632
'vue/multi-word-component-names': 'off',
47-
'prettier/prettier': 'error',
33+
'security/detect-object-injection': 'off',
4834
},
4935
},
5036
{
5137
files: ['src/pages/**/*.vue', 'src/pages/*.vue', 'src/*.vue'],
5238
rules: {
53-
'vue/multi-word-component-names': 0,
39+
'vue/multi-word-component-names': 'off',
5440
},
5541
},
56-
]);
42+
];

app/package.json

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"start": "nuxt start",
77
"generate": "nuxt generate",
88
"preview": "nuxt preview",
9+
"prepare": "cd ../ && husky app/.husky",
910
"postinstall": "nuxt prepare",
1011
"lint:script": "eslint --ext .ts,vue --ignore-path .gitignore .",
1112
"lint:style": "stylelint src/**/*.{css,scss,vue}",
@@ -17,57 +18,58 @@
1718
"test:e2e:ui": "playwright test --ui"
1819
},
1920
"dependencies": {
20-
"@eslint/eslintrc": "^3.3.3",
21-
"@eslint/js": "^9.39.2",
22-
"@fortawesome/fontawesome-svg-core": "^7.1.0",
23-
"@fortawesome/free-brands-svg-icons": "^7.1.0",
24-
"@fortawesome/free-regular-svg-icons": "^7.1.0",
25-
"@fortawesome/free-solid-svg-icons": "^7.1.0",
21+
"@fortawesome/fontawesome-svg-core": "^7.2.0",
22+
"@fortawesome/free-brands-svg-icons": "^7.2.0",
23+
"@fortawesome/free-regular-svg-icons": "^7.2.0",
24+
"@fortawesome/free-solid-svg-icons": "^7.2.0",
2625
"@fortawesome/vue-fontawesome": "^3.1.3",
2726
"@headlessui/vue": "^1.7.23",
2827
"@heroicons/vue": "^2.2.0",
29-
"@nuxtjs/i18n": "^10.2.1",
30-
"@playwright/test": "^1.58.1",
31-
"@vueuse/core": "^14.2.0",
32-
"globals": "^16.5.0",
33-
"nuxt": "^4.3.0",
34-
"nuxt-delay-hydration": "^1.3.8",
35-
"tailwindcss": "^4.1.18",
36-
"vue": "^3.5.27",
28+
"@nuxtjs/i18n": "^10.2.3",
29+
"@playwright/test": "^1.58.2",
30+
"@vueuse/core": "^14.2.1",
31+
"globals": "^17.3.0",
32+
"nuxt": "^4.3.1",
33+
"tailwindcss": "^4.2.0",
34+
"vue": "^3.5.28",
3735
"vue-markdown-render": "^2.3.0",
3836
"vue-router": "^4.6.4"
3937
},
4038
"devDependencies": {
41-
"@tailwindcss/postcss": "^4.1.18",
42-
"@types/node": "^24.10.10",
43-
"@typescript-eslint/eslint-plugin": "^8.54.0",
44-
"@typescript-eslint/parser": "^8.54.0",
45-
"@vue/eslint-config-prettier": "^10.2.0",
46-
"@vue/eslint-config-typescript": "^14.6.0",
39+
"@eslint/eslintrc": "^3.3.3",
40+
"@eslint/js": "^9.39.2",
41+
"@nuxt/types": "^2.18.1",
42+
"@tailwindcss/postcss": "^4.2.0",
43+
"@types/node": "^25.3.0",
44+
"@typescript-eslint/eslint-plugin": "^8.56.0",
45+
"@typescript-eslint/parser": "^8.56.0",
4746
"autoprefixer": "^10.4.24",
4847
"eslint": "^9.39.2",
4948
"eslint-plugin-jsx-a11y": "^6.10.2",
5049
"eslint-plugin-prettier": "^5.5.5",
51-
"eslint-plugin-security": "^3.0.1",
52-
"eslint-plugin-vue": "^10.7.0",
50+
"eslint-plugin-security": "^4.0.0",
51+
"eslint-plugin-vue": "^10.8.0",
5352
"husky": "^9.1.7",
5453
"lint-staged": "^16.2.7",
55-
"npm-check-updates": "^19.3.2",
56-
"playwright": "^1.58.1",
54+
"npm-check-updates": "^19.4.1",
55+
"playwright": "^1.58.2",
5756
"postcss": "^8.5.6",
57+
"postcss-html": "^1.8.1",
5858
"prettier": "^3.8.1",
59-
"stylelint": "^16.26.1",
60-
"stylelint-config-recommended": "^17.0.0",
61-
"stylelint-config-standard": "^39.0.1"
59+
"stylelint": "^17.3.0",
60+
"stylelint-config-recommended": "^18.0.0",
61+
"stylelint-config-standard": "^40.0.0"
6262
},
63-
"husky": {
64-
"hooks": {
65-
"pre-commit": "lint-staged"
66-
}
63+
"optionalDependencies": {
64+
"@oxc-parser/binding-linux-x64-gnu": "0.114.0"
6765
},
6866
"lint-staged": {
69-
"*.{ts,tsx}": "eslint --fix",
70-
"*.{css,scss,vue}": "stylelint --fix",
71-
"*": "prettier -w -u"
67+
"*.{ts,tsx,js,jsx}": "eslint --fix",
68+
"*.{css,scss}": "stylelint --fix",
69+
"*.vue": [
70+
"eslint --fix",
71+
"stylelint --fix"
72+
],
73+
"*.{json,md,html}": "prettier --write"
7274
}
7375
}

app/playwright.config.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import { defineConfig } from '@playwright/test';
22
import os from 'os';
33

4+
const isCI = !!process.env.CI;
5+
46
export default defineConfig({
57
testDir: './tests',
68
timeout: 30_000,
79
retries: 0,
810
use: {
911
baseURL: process.env.BASE_URL || 'http://localhost:3000',
1012
trace: 'retain-on-failure',
13+
screenshot: 'only-on-failure',
14+
video: 'retain-on-failure',
1115
headless: true,
1216
},
13-
reporter: [['list']],
17+
reporter: isCI ? [['list'], ['html', { outputFolder: 'playwright-report', open: 'never' }]] : [['list']],
1418
webServer: {
1519
command: 'npm run dev',
1620
url: 'http://localhost:3000',

0 commit comments

Comments
 (0)