Skip to content

Commit e2b62b7

Browse files
committed
feat: replace Karma with Playwright and add full-chain integration tests
- Replace Karma + BrowserStack browser tests with Playwright - Port all UMD bundle browser tests (19 tests) - Add full-chain integration tests matching PHP SDK pattern (17 tests per mode) - Support 3 auth modes: static, live (public key), live-secret (key+secret) - Upgrade CI to Node 22, corepack, actions v4 - Remove Karma, BrowserStack, and Puppeteer dependencies - Add TESTING.md documentation
1 parent 53feea4 commit e2b62b7

18 files changed

Lines changed: 1422 additions & 1636 deletions

.env.example

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
# BrowserStack credentails
2-
BROWSER_STACK_USERNAME=
3-
BROWSER_STACK_ACCESS=
1+
# Convert Staging SDK Key
2+
CONVERT_STAGING_SDK_KEY=
3+
CONVERT_STAGING_SDK_KEY2=
4+
CONVERT_STAGING_SDK_KEY2_SECRET=
45

56
# Logger
67
LOG_LEVEL=2

.github/workflows/qa.yml

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,37 @@ jobs:
1717
runs-on: ubuntu-latest
1818
strategy:
1919
matrix:
20-
node: [18]
20+
node: [22]
2121
# Steps represent a sequence of tasks that will be executed as part of the job
2222
steps:
23-
- uses: actions/setup-node@v1
23+
- uses: actions/checkout@v4
2424
with:
25-
# The Node.js version to configure
26-
node-version: ${{ matrix.node }}
25+
fetch-depth: 2
2726

28-
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
29-
- uses: actions/checkout@v2
27+
- name: Setup Node
28+
uses: actions/setup-node@v4
3029
with:
31-
fetch-depth: 2
32-
- name: Install needed libraries and packages
30+
node-version: ${{ matrix.node }}
31+
32+
- name: Setup Yarn
33+
run: |
34+
corepack enable
35+
corepack prepare yarn@stable --activate
36+
37+
- name: Install Playwright browsers
3338
run: |
34-
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
35-
sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
36-
sudo apt-get update
37-
sudo apt-get install -y google-chrome-stable
39+
cd packages/js-sdk
40+
npx playwright install --with-deps chromium
3841
3942
- name: Runs the SDK QA checks
43+
env:
44+
CONVERT_STAGING_SDK_KEY: ${{ secrets.CONVERT_STAGING_SDK_KEY }}
45+
CONVERT_STAGING_SDK_KEY2: ${{ secrets.CONVERT_STAGING_SDK_KEY2 }}
46+
CONVERT_STAGING_SDK_KEY2_SECRET: ${{ secrets.CONVERT_STAGING_SDK_KEY2_SECRET }}
4047
run: |
41-
yarn set version berry
4248
yarn
4349
cd packages/js-sdk
4450
yarn lint
45-
yarn test
51+
yarn build
52+
yarn test:mocha
53+
yarn test:browser

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ lib/
1212
dist/
1313
docs/
1414
coverage/
15+
test-results/
1516
packages/demo-*
1617
.next
1718
demo/remixjs-server-side/build

packages/js-sdk/TESTING.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Testing Guide
2+
3+
This document covers how to run and write tests for the `@convertcom/js-sdk` package.
4+
5+
## Prerequisites
6+
7+
- Node.js >= 22
8+
- Yarn (via corepack: `corepack enable && corepack prepare yarn@stable --activate`)
9+
- Playwright Chromium browser: `npx playwright install --with-deps chromium`
10+
- Built SDK bundles (run `yarn build` before browser/integration tests)
11+
12+
## Test Suites
13+
14+
The SDK has three test suites:
15+
16+
| Suite | Runner | Scope | Command |
17+
|-------|--------|-------|---------|
18+
| **Unit tests** | Mocha + Chai | Core logic, context, feature manager, utilities | `yarn test:mocha` |
19+
| **Browser tests** | Playwright | UMD bundle loaded in Chromium | `yarn test:browser` |
20+
| **Integration tests** | Playwright | Full SDK lifecycle (init, bucket, feature, conversion) | `yarn test:browser` |
21+
22+
### Run everything
23+
24+
```bash
25+
yarn build
26+
yarn test:mocha
27+
yarn test:browser
28+
```
29+
30+
Or use the combined command (includes coverage):
31+
32+
```bash
33+
yarn build
34+
yarn test
35+
```
36+
37+
## Unit Tests (Mocha)
38+
39+
Located in `tests/**/*.tests.ts`. These test SDK internals using Mocha + Chai with `ts-node/register`.
40+
41+
```bash
42+
yarn test:mocha
43+
```
44+
45+
Test files:
46+
- `tests/core.tests.ts` — Core class (init, context creation, events)
47+
- `tests/context.tests.ts` — Context class (runExperience, runFeature, trackConversion)
48+
- `tests/feature-manager.tests.ts` — Feature manager logic
49+
- `tests/utils/*.tests.ts` — Array, object, string, and comparison utilities
50+
51+
These tests use `tests/test-config.json` (fabricated IDs) and do **not** require network access.
52+
53+
## Browser Tests (Playwright)
54+
55+
Located in `tests/browser/`. These verify the built UMD bundle works correctly in a real browser environment.
56+
57+
```bash
58+
yarn build # Must build first — tests serve the built bundles
59+
yarn test:browser
60+
```
61+
62+
**How it works:**
63+
1. Playwright starts a local HTTP server (`tests/browser/test-server.js`) on port 3939
64+
2. The server serves the built UMD bundle (`lib/index.umd.min.js`) and a test HTML page
65+
3. Tests navigate to the page and use `page.evaluate()` to exercise the SDK in browser context
66+
67+
Test file:
68+
- `tests/browser/umd-bundle.spec.ts` — 19 tests covering SDK instantiation, experiences, features, conversions, segments, and invalid visitor handling
69+
70+
These tests use `tests/test-config.json` (fabricated IDs) and do **not** require network access.
71+
72+
## Integration Tests (Playwright)
73+
74+
Located in `tests/integration/`. These run the full SDK lifecycle in Node.js context (not browser), matching the PHP SDK's `FullChainIntegrationTest` pattern.
75+
76+
```bash
77+
yarn build # Must build first — tests import from lib/
78+
yarn test:browser # Integration tests run as part of the Playwright suite
79+
```
80+
81+
Test file:
82+
- `tests/integration/full-chain.spec.ts` — 17 tests per mode covering:
83+
- **Happy path:** init, ready event, experience bucketing, bucketing determinism, bucketing events, typed feature variables, full chain verification
84+
- **Negative path:** unknown feature key, non-qualifying location, audience mismatch
85+
- **Conversion tracking:** basic conversion, conversion events, goal deduplication, revenue tracking, forced multiple transactions, nonexistent goal
86+
- **Complete chain:** init -> context -> bucket -> feature -> conversion -> flush
87+
88+
### Auth Modes
89+
90+
Integration tests run in up to 3 modes, following the PHP SDK pattern:
91+
92+
| Mode | Config source | Env vars required | Always runs? |
93+
|------|--------------|-------------------|-------------|
94+
| `static` | `tests/integration/static-config.json` | None | Yes |
95+
| `live` | CDN fetch (public key) | `CONVERT_STAGING_SDK_KEY` | No |
96+
| `live-secret` | CDN fetch (authenticated) | `CONVERT_STAGING_SDK_KEY2`, `CONVERT_STAGING_SDK_KEY2_SECRET` | No |
97+
98+
The `static` mode always runs using a snapshot of the staging project config. The `live` and `live-secret` modes are skipped when the corresponding env vars are not set.
99+
100+
### Setting up env vars for live tests
101+
102+
Copy `.env.example` to `.env` and fill in the values:
103+
104+
```bash
105+
# Public SDK key for unauthenticated CDN fetch
106+
CONVERT_STAGING_SDK_KEY=<public-sdk-key>
107+
108+
# SDK key + secret for authenticated CDN fetch
109+
CONVERT_STAGING_SDK_KEY2=<sdk-key>
110+
CONVERT_STAGING_SDK_KEY2_SECRET=<sdk-key-secret>
111+
```
112+
113+
Then run with the env vars loaded:
114+
115+
```bash
116+
export $(grep -v '^#' .env | xargs)
117+
yarn build
118+
yarn test:browser
119+
```
120+
121+
### Staging Project
122+
123+
All integration tests use the shared staging project **"FS-Test-Proj - DO NOT DELETE"** (account `10035569`, project `10034190`). This is the same project used by the PHP SDK's integration tests.
124+
125+
Key entities:
126+
- **Experience:** `test-experience-ab-fullstack-4` — 50/50 split, pricing-location, no audiences
127+
- **Feature-1:** boolean `enabled`, string `caption`
128+
- **Feature-2:** float `price` (100), integer `button-height` (40), json `additionalData`
129+
- **Goals:** `increase-engagement` (dom_interaction, no rules), `decrease-bounce-rate` (advanced)
130+
131+
**Do not modify or delete this project.** Changes will break integration tests in both the JS and PHP SDKs.
132+
133+
## Playwright Configuration
134+
135+
Config file: `playwright.config.ts`
136+
137+
- **Test server:** Auto-started on port 3939 (configurable via `PORT` env var)
138+
- **Browser:** Chromium only, headless, with `--no-sandbox`
139+
- **Workers:** 1 (sequential execution — tests share SDK state)
140+
- **Timeout:** 60 seconds per test
141+
- **Retries:** 2 on CI, 0 locally
142+
- **Traces:** Retained on failure
143+
144+
## CI
145+
146+
Tests run in GitHub Actions via `.github/workflows/qa.yml`:
147+
148+
```
149+
yarn → build → lint → test:mocha → test:browser
150+
```
151+
152+
Live integration tests run in CI when the `CONVERT_STAGING_SDK_KEY`, `CONVERT_STAGING_SDK_KEY2`, and `CONVERT_STAGING_SDK_KEY2_SECRET` secrets are configured in the repository.
153+
154+
## Writing New Tests
155+
156+
### Adding a unit test
157+
158+
Add a `.tests.ts` file under `tests/`. It will be picked up automatically by the mocha glob `tests/**/*.tests.ts`.
159+
160+
```typescript
161+
import 'mocha';
162+
import {expect} from 'chai';
163+
164+
describe('MyFeature', () => {
165+
it('should do something', () => {
166+
expect(true).to.be.true;
167+
});
168+
});
169+
```
170+
171+
### Adding a browser test
172+
173+
Add assertions to `tests/browser/umd-bundle.spec.ts` or create a new `.spec.ts` file under `tests/browser/`.
174+
175+
```typescript
176+
import {test, expect} from '@playwright/test';
177+
178+
test('SDK does something in browser', async ({page}) => {
179+
await page.goto('/');
180+
const result = await page.evaluate(() => {
181+
// ConvertSDK is available as a global from the UMD bundle
182+
return typeof ConvertSDK;
183+
});
184+
expect(result).toBe('function');
185+
});
186+
```
187+
188+
### Adding an integration test
189+
190+
Add tests inside the `for (const mode of modes)` loop in `tests/integration/full-chain.spec.ts` to ensure they run in all auth modes.
191+
192+
```typescript
193+
test('My new integration test', async () => {
194+
const sdk = createSdk(mode);
195+
await sdk.onReady();
196+
const context = sdk.createContext('my-visitor-id');
197+
// ... exercise SDK and assert
198+
});
199+
```

packages/js-sdk/index.browser.cjs.tests.js

Lines changed: 0 additions & 7 deletions
This file was deleted.

packages/js-sdk/index.browser.umd.tests.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)