Skip to content

Commit c8882ff

Browse files
authored
test: added unit and e2e tests (#75)
1 parent cc7c19c commit c8882ff

14 files changed

Lines changed: 1029 additions & 192 deletions

‎.github/workflows/on-push.yml‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ jobs:
1414
runs-on: ubuntu-latest
1515

1616
steps:
17-
# Build library
1817
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
1918

2019
- uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
@@ -28,23 +27,24 @@ jobs:
2827
- name: Build
2928
run: yarn build
3029

31-
# Run test and typecheck
3230
- name: Typecheck
3331
run: yarn typecheck
3432

35-
# - name: Run tests
36-
# run: yarn test
33+
- name: Run unit tests
34+
run: yarn test
3735

38-
# Build example app
3936
- name: Install modules
4037
run: yarn install --frozen-lockfile
4138
working-directory: ./example
4239

43-
- name: Build
44-
run: yarn build
40+
- name: Install Playwright browser
41+
run: yarn playwright install --with-deps chromium
42+
working-directory: ./example
43+
44+
- name: Run e2e tests
45+
run: yarn test:e2e
4546
working-directory: ./example
4647

47-
# Check documentation
4848
- name: Generate documentation
4949
run: yarn build:docs
5050

‎CONTRIBUTING.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ We follow the [conventional commits specification](https://www.conventionalcommi
4545

4646
[ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/)
4747

48-
We use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Jest](https://jestjs.io/) for testing.
48+
We use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Vitest](https://vitest.dev/) for testing.
4949

5050
### Sending a pull request
5151

‎example/.gitignore‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ dist
1212
dist-ssr
1313
*.local
1414

15+
# Playwright
16+
/test-results/
17+
/playwright-report/
18+
/playwright/.cache/
19+
1520
# Editor directories and files
1621
.vscode/*
1722
!.vscode/extensions.json

‎example/e2e/tracking.spec.ts‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { test, expect, type Page } from '@playwright/test'
2+
3+
declare global {
4+
interface Window {
5+
_paq?: unknown[][]
6+
}
7+
}
8+
9+
const getPaq = (page: Page) => page.evaluate(() => window._paq ?? [])
10+
11+
const waitForTracking = (page: Page) =>
12+
page.waitForFunction(() => (window._paq?.length ?? 0) > 0)
13+
14+
test('on app load, the built plugin initializes tracking and tags _paq with the "react" source provider', async ({
15+
page
16+
}) => {
17+
await page.goto('/', { waitUntil: 'domcontentloaded' })
18+
await waitForTracking(page)
19+
20+
expect(await getPaq(page)).toContainEqual(
21+
expect.arrayContaining(['setTrackingSourceProvider', 'react'])
22+
)
23+
})
24+
25+
test('clicking the Submit button pushes a "trackEvent" command to _paq', async ({
26+
page
27+
}) => {
28+
await page.goto('/custom-event', { waitUntil: 'domcontentloaded' })
29+
await waitForTracking(page)
30+
const before = await getPaq(page)
31+
expect(before).not.toContainEqual(expect.arrayContaining(['trackEvent']))
32+
33+
await page.getByRole('button', { name: 'Submit' }).click()
34+
35+
expect(await getPaq(page)).toContainEqual(
36+
expect.arrayContaining(['trackEvent'])
37+
)
38+
})

‎example/package.json‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"dev": "vite",
88
"build": "tsc && vite build",
99
"lint": "eslint . --report-unused-disable-directives --max-warnings 0",
10-
"preview": "vite preview"
10+
"preview": "vite preview",
11+
"test:e2e": "playwright test"
1112
},
1213
"dependencies": {
1314
"@emotion/react": "^11.11.1",
@@ -21,16 +22,17 @@
2122
"react-router-dom": "^6.20.1"
2223
},
2324
"devDependencies": {
25+
"@eslint/js": "^9.39.1",
26+
"@playwright/test": "^1.61.1",
2427
"@types/react": "^18.2.43",
2528
"@types/react-dom": "^18.2.17",
26-
"@eslint/js": "^9.39.1",
27-
"typescript-eslint": "^8.46.2",
2829
"@vitejs/plugin-react-swc": "^3.7.0",
2930
"eslint": "^9.39.1",
3031
"eslint-plugin-react-hooks": "^5.2.0",
3132
"eslint-plugin-react-refresh": "^0.4.5",
3233
"prettier": "^3.1.1",
3334
"typescript": "^5.2.2",
35+
"typescript-eslint": "^8.46.2",
3436
"vite": "^6.4.3"
3537
}
3638
}

‎example/playwright.config.ts‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { defineConfig, devices } from '@playwright/test'
2+
3+
const PORT = 4173
4+
const BASE_URL = `http://localhost:${PORT}`
5+
6+
export default defineConfig({
7+
testDir: './e2e',
8+
fullyParallel: true,
9+
forbidOnly: !!process.env.CI,
10+
retries: process.env.CI ? 1 : 0,
11+
reporter: process.env.CI ? 'github' : 'list',
12+
use: {
13+
baseURL: BASE_URL,
14+
trace: 'on-first-retry'
15+
},
16+
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
17+
webServer: {
18+
command: 'yarn build && yarn preview',
19+
url: BASE_URL,
20+
reuseExistingServer: !process.env.CI,
21+
timeout: 180_000
22+
}
23+
})

‎example/src/main.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const cache = createCache({
1818

1919
PiwikPro.initialize(
2020
'957285ba-7867-4c6b-a8be-5e3e6c069b71',
21-
'https://astralprojection.promilci.com',
21+
'https://example.piwik.pro',
2222
{ dataLayerName: 'myDataLayer', nonce }
2323
)
2424

‎example/yarn.lock‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,13 @@
521521
resolved "https://registry.yarnpkg.com/@piwikpro/tracking-base-library/-/tracking-base-library-1.7.1.tgz#716dd45a541f0bfae02fd9fde5df51beb80ed40c"
522522
integrity sha512-vDV8NZ7rYTlhKBHMHL880QqPOPzrXSurZn0sfhodqwGa9v7tmqLJe0IaG2Su1fOtlQm5pb2zobm8ngar45AKmQ==
523523

524+
"@playwright/test@^1.61.1":
525+
version "1.61.1"
526+
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.61.1.tgz#48568dc22af7819e55fa5e8e3bc79b7e6a3e6675"
527+
integrity sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==
528+
dependencies:
529+
playwright "1.61.1"
530+
524531
"@popperjs/core@^2.11.8":
525532
version "2.11.8"
526533
resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz"
@@ -1305,6 +1312,11 @@ flatted@^3.2.9:
13051312
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.4.2.tgz#f5c23c107f0f37de8dbdf24f13722b3b98d52726"
13061313
integrity sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==
13071314

1315+
fsevents@2.3.2:
1316+
version "2.3.2"
1317+
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
1318+
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
1319+
13081320
fsevents@~2.3.2, fsevents@~2.3.3:
13091321
version "2.3.3"
13101322
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
@@ -1594,6 +1606,20 @@ picomatch@^4.0.2, picomatch@^4.0.4:
15941606
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589"
15951607
integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==
15961608

1609+
playwright-core@1.61.1:
1610+
version "1.61.1"
1611+
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.61.1.tgz#3c99841307efbbabc9d724c41a88c914705d15fc"
1612+
integrity sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==
1613+
1614+
playwright@1.61.1:
1615+
version "1.61.1"
1616+
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.61.1.tgz#d8c0c06eb93c28981afc747bace453bdbd5018bc"
1617+
integrity sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==
1618+
dependencies:
1619+
playwright-core "1.61.1"
1620+
optionalDependencies:
1621+
fsevents "2.3.2"
1622+
15971623
postcss@^8.5.3:
15981624
version "8.5.16"
15991625
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.16.tgz#1230ce0b5df354c24c0ea45f99ce5f6a88279d28"

‎package.json‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"lint:fix": "npm run lint -- --fix",
3030
"format": "prettier 'src/**/*.ts' --list-different",
3131
"format:fix": "npm run format -- --write",
32-
"test": "jest",
32+
"test": "vitest run",
33+
"test:coverage": "vitest run --coverage",
3334
"typecheck": "tsc --noEmit"
3435
},
3536
"peerDependencies": {
@@ -38,28 +39,30 @@
3839
},
3940
"devDependencies": {
4041
"@babel/plugin-proposal-unicode-property-regex": "^7.18.6",
42+
"@eslint/js": "^9.39.1",
4143
"@rollup/plugin-typescript": "^11.1.6",
4244
"@testing-library/jest-dom": "^6.2.0",
4345
"@testing-library/react": "^14.1.2",
4446
"@testing-library/user-event": "^14.5.2",
45-
"@types/jest": "^29.5.11",
4647
"@types/node": "^20.10.7",
4748
"@types/react": "^18.2.47",
4849
"@types/react-dom": "^18.2.18",
49-
"@eslint/js": "^9.39.1",
50-
"typescript-eslint": "^8.46.2",
50+
"@vitest/coverage-v8": "^3",
5151
"auto-changelog": "^2.6.0",
5252
"concat-md": "^0.5.1",
5353
"cross-env": "^7.0.3",
5454
"eslint": "^9.39.1",
5555
"gh-pages": "^6.1.1",
56+
"happy-dom": "^20.10.6",
5657
"prettier": "^3.1.1",
5758
"react": "^18.2.0",
5859
"tslib": "^2.6.3",
5960
"typedoc": "^0.28.19",
6061
"typedoc-plugin-markdown": "^4.12.0",
6162
"typescript": "~5.4.5",
62-
"vite": "^6.4.3"
63+
"typescript-eslint": "^8.46.2",
64+
"vite": "^6.4.3",
65+
"vitest": "^3"
6366
},
6467
"files": [
6568
"dist"

‎src/__tests__/initialize.test.ts‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { describe, it, expect, vi, beforeEach, afterEach, type Mock } from 'vitest'
2+
3+
vi.mock('@piwikpro/tracking-base-library', () => ({
4+
__esModule: true,
5+
default: { initialize: vi.fn(), getInitScript: vi.fn() },
6+
Miscellaneous: { setTrackingSourceProvider: vi.fn() }
7+
}))
8+
9+
import PiwikProReact from '../index'
10+
import PiwikProCore, { Miscellaneous } from '@piwikpro/tracking-base-library'
11+
import { version } from '../../package.json'
12+
13+
beforeEach(() => vi.clearAllMocks())
14+
afterEach(() => vi.unstubAllGlobals())
15+
16+
describe('initialize()', () => {
17+
it('sets the source provider before delegating to core', () => {
18+
PiwikProReact.initialize('id', 'https://example.piwik.pro')
19+
20+
expect(Miscellaneous.setTrackingSourceProvider).toHaveBeenCalledWith('react', version)
21+
expect(
22+
(Miscellaneous.setTrackingSourceProvider as Mock).mock.invocationCallOrder[0]
23+
).toBeLessThan((PiwikProCore.initialize as Mock).mock.invocationCallOrder[0])
24+
})
25+
26+
it('forwards all arguments to core initialize', () => {
27+
PiwikProReact.initialize('id', 'https://example.piwik.pro', { nonce: 'abc' })
28+
29+
expect(PiwikProCore.initialize).toHaveBeenCalledWith('id', 'https://example.piwik.pro', {
30+
nonce: 'abc'
31+
})
32+
})
33+
34+
it('skips setting source provider during SSR (no window)', () => {
35+
vi.stubGlobal('window', undefined)
36+
37+
PiwikProReact.initialize('id', 'https://example.piwik.pro')
38+
39+
expect(Miscellaneous.setTrackingSourceProvider).not.toHaveBeenCalled()
40+
expect(PiwikProCore.initialize).toHaveBeenCalledWith('id', 'https://example.piwik.pro')
41+
})
42+
})

0 commit comments

Comments
 (0)