Skip to content

Commit 776e66f

Browse files
authored
Merge pull request #151 from humanspeak/feature-initial
feat: add expected patterns, pnpm migration, docs & CI overhaul
2 parents a01d3c6 + cd3157a commit 776e66f

5 files changed

Lines changed: 159 additions & 14 deletions

File tree

.github/workflows/run-tests.yml

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
name: Run tests
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
workflow_call:
8+
pull_request:
9+
branches:
10+
- main
11+
- '!dependabot/**'
12+
paths:
13+
- src/**
14+
- tests/**
15+
- '!docs/**'
16+
- package.json
17+
- package-lock.json
18+
- svelte.config.*
19+
- vite.config.*
20+
- playwright.config.*
21+
- tsconfig*.json
22+
- .github/workflows/run-tests.yml
23+
24+
concurrency:
25+
group: run-tests-${{ github.ref }}
26+
cancel-in-progress: true
27+
28+
jobs:
29+
unit-tests:
30+
runs-on: blacksmith-2vcpu-ubuntu-2404 # trunk-ignore(actionlint/runner-label)
31+
timeout-minutes: 10
32+
steps:
33+
- name: Checkout
34+
uses: actions/checkout@v6 # zizmor: ignore[unpinned-uses]
35+
with:
36+
persist-credentials: false
37+
fetch-depth: 1
38+
39+
- uses: pnpm/action-setup@v4 # zizmor: ignore[unpinned-uses]
40+
with:
41+
version: 10
42+
43+
- name: Use Node.js - 24
44+
uses: actions/setup-node@v6 # zizmor: ignore[unpinned-uses]
45+
with:
46+
node-version: 24
47+
48+
- name: Cache build artifacts
49+
uses: actions/cache@v5 # zizmor: ignore[unpinned-uses]
50+
with:
51+
path: |
52+
.svelte-kit
53+
dist
54+
key: ${{ runner.os }}-build-${{ hashFiles('src/**/*', 'pnpm-lock.yaml') }}
55+
restore-keys: |
56+
${{ runner.os }}-build-
57+
58+
- name: Cache vitest artifacts
59+
uses: actions/cache@v5 # zizmor: ignore[unpinned-uses]
60+
with:
61+
path: |
62+
node_modules/.vitest
63+
test-results
64+
key: ${{ runner.os }}-vitest-${{ hashFiles('pnpm-lock.yaml', 'src/**/*.{test,spec}.{js,ts}', 'tests/**/*.{test,spec}.{js,ts}', 'vitest.config.ts') }}
65+
restore-keys: |
66+
${{ runner.os }}-vitest-
67+
68+
- name: Install dependencies
69+
run: pnpm install --frozen-lockfile
70+
71+
- name: Run unit tests
72+
run: |
73+
pnpm build
74+
pnpm test
75+
76+
- name: Upload unit test results
77+
if: always()
78+
uses: actions/upload-artifact@v4 # zizmor: ignore[unpinned-uses]
79+
with:
80+
name: unit-test-results
81+
path: |
82+
coverage/**
83+
test-results/**
84+
if-no-files-found: ignore
85+
retention-days: 7
86+
87+
e2e-tests:
88+
needs: unit-tests
89+
runs-on: blacksmith-2vcpu-ubuntu-2404 # trunk-ignore(actionlint/runner-label)
90+
timeout-minutes: 25
91+
strategy:
92+
fail-fast: false
93+
matrix:
94+
include:
95+
- shard: 1/2
96+
shard_name: 1-2
97+
- shard: 2/2
98+
shard_name: 2-2
99+
steps:
100+
- name: Checkout
101+
uses: actions/checkout@v6 # zizmor: ignore[unpinned-uses]
102+
with:
103+
persist-credentials: false
104+
fetch-depth: 1
105+
106+
- uses: pnpm/action-setup@v4 # zizmor: ignore[unpinned-uses]
107+
with:
108+
version: 10
109+
110+
- name: Use Node.js - 24
111+
uses: actions/setup-node@v6 # zizmor: ignore[unpinned-uses]
112+
with:
113+
node-version: 24
114+
115+
- name: Install dependencies
116+
run: pnpm install --frozen-lockfile
117+
118+
- name: Cache Playwright browsers
119+
uses: actions/cache@v5 # zizmor: ignore[unpinned-uses]
120+
with:
121+
path: ~/.cache/ms-playwright
122+
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
123+
restore-keys: |
124+
${{ runner.os }}-playwright-
125+
126+
- name: Install Playwright browsers
127+
run: pnpm exec playwright install --with-deps
128+
129+
- name: Sanity check - list discovered tests
130+
run: pnpm exec playwright test --list | head -n 50 | cat
131+
132+
- name: Run e2e tests (sharded)
133+
env:
134+
CI: true
135+
run: pnpm exec playwright test --config=playwright.config.ts --shard=${{ matrix.shard }} --reporter=line
136+
137+
- name: Upload Playwright artifacts
138+
if: always()
139+
uses: actions/upload-artifact@v4 # zizmor: ignore[unpinned-uses]
140+
with:
141+
name: playwright-artifacts-${{ matrix.shard_name }}
142+
path: |
143+
playwright-report/**
144+
test-results/**
145+
blob-report/**
146+
if-no-files-found: ignore
147+
retention-days: 7

.trunk/trunk.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ lint:
2424
- linters: [markdownlint]
2525
paths:
2626
- .changeset/**
27+
- linters: [eslint]
28+
paths:
29+
- '**/*.svelte.ts'
2730
definitions:
2831
- name: prettier
2932
files:

tests/default.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ test.describe('SvelteDiffMatchPatch', () => {
66
})
77

88
test('renders a visible diff', async ({ page }) => {
9-
await page.fill('[data-testid="text1"]', 'hello world')
10-
await page.fill('[data-testid="text2"]', 'hello brave world')
9+
await page.getByTestId('text1').fill('hello world')
10+
await page.getByTestId('text2').fill('hello brave world')
1111
await expect(page.getByTestId('diff-result')).toContainText('brave')
1212
await expect(page.getByTestId('diff-result')).toContainText('hello')
1313
await expect(page.getByTestId('diff-result')).toContainText('world')
1414
})
1515

1616
test('applies custom rendererClasses', async ({ page }) => {
17-
await page.fill('[data-testid="text1"]', 'foo shoo')
18-
await page.fill('[data-testid="text2"]', 'bar shoo')
17+
await page.getByTestId('text1').fill('foo shoo')
18+
await page.getByTestId('text2').fill('bar shoo')
1919
await expect(page.getByTestId('diff-result').locator('.diff-remove')).toBeVisible()
2020
await expect(page.getByTestId('diff-result').locator('.diff-insert')).toBeVisible()
2121
await expect(page.getByTestId('diff-result').locator('.diff-equal')).toBeVisible()

tests/expected-patterns.test.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,10 @@ test.describe('Expected Patterns', () => {
1717
})
1818

1919
test('non-captured deviations still show as insert/remove', async ({ page }) => {
20-
// Use a simple template where we can have both expected captures and deviations
21-
await page.getByTestId('text1').fill('Hello (?<name>.+) end')
22-
await page.getByTestId('text2').fill('Goodbye World end')
23-
// "World" is captured as expected, but "Hello" vs "Goodbye" is a real deviation
24-
// Actually regex won't match because "Hello" != "Goodbye" literal...
25-
// Use: template matches but has surrounding diffs from diff algorithm
26-
await page.getByTestId('text1').fill('(?<name>.+) likes coding')
20+
// Use \w+ instead of .+ so the capture is constrained to "Jason" only,
21+
// leaving "coding" vs "hacking" as a real deviation for insert/remove
22+
await page.getByTestId('text1').fill('(?<name>\\w+) likes coding')
2723
await page.getByTestId('text2').fill('Jason likes hacking')
28-
// "Jason" is captured, "coding" vs "hacking" is a real deviation
2924
await expect(
3025
page.getByTestId('diff-result').locator('.diff-expected').first()
3126
).toBeVisible()

tests/snippets.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ test.describe('SvelteDiffMatchPatch', () => {
1616
})
1717

1818
test('applies custom rendererClasses', async ({ page }) => {
19-
await page.fill('[data-testid="text1"]', 'foo shoo')
20-
await page.fill('[data-testid="text2"]', 'bar shoo')
19+
await page.getByTestId('text1').fill('foo shoo')
20+
await page.getByTestId('text2').fill('bar shoo')
2121
await expect(page.getByTestId('diff-result').locator('.diff-remove')).toBeVisible()
2222
await expect(page.getByTestId('diff-result').locator('.diff-insert')).toBeVisible()
2323
await expect(page.getByTestId('diff-result').locator('.diff-equal')).toBeVisible()

0 commit comments

Comments
 (0)