Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# BrowserStack credentails
BROWSER_STACK_USERNAME=
BROWSER_STACK_ACCESS=
# Convert Staging SDK Key
CONVERT_STAGING_SDK_KEY=
CONVERT_STAGING_SDK_KEY2=
CONVERT_STAGING_SDK_KEY2_SECRET=

# Logger
LOG_LEVEL=2
Expand Down
36 changes: 22 additions & 14 deletions .github/workflows/qa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,37 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [18]
node: [22]
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- uses: actions/setup-node@v1
- uses: actions/checkout@v4
with:
# The Node.js version to configure
node-version: ${{ matrix.node }}
fetch-depth: 2

# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Setup Node
uses: actions/setup-node@v4
with:
fetch-depth: 2
- name: Install needed libraries and packages
node-version: ${{ matrix.node }}

- name: Setup Yarn
run: |
corepack enable
corepack prepare yarn@stable --activate

- name: Install Playwright browsers
run: |
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
sudo apt-get update
sudo apt-get install -y google-chrome-stable
cd packages/js-sdk
npx playwright install --with-deps chromium

- name: Runs the SDK QA checks
env:
CONVERT_STAGING_SDK_KEY: ${{ secrets.CONVERT_STAGING_SDK_KEY }}
CONVERT_STAGING_SDK_KEY2: ${{ secrets.CONVERT_STAGING_SDK_KEY2 }}
CONVERT_STAGING_SDK_KEY2_SECRET: ${{ secrets.CONVERT_STAGING_SDK_KEY2_SECRET }}
run: |
yarn set version berry
yarn
cd packages/js-sdk
yarn lint
yarn test
yarn build
yarn test:mocha
yarn test:browser
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ lib/
dist/
docs/
coverage/
test-results/
packages/demo-*
.next
demo/remixjs-server-side/build
Expand Down
199 changes: 199 additions & 0 deletions packages/js-sdk/TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# Testing Guide

This document covers how to run and write tests for the `@convertcom/js-sdk` package.

## Prerequisites

- Node.js >= 22
- Yarn (via corepack: `corepack enable && corepack prepare yarn@stable --activate`)
- Playwright Chromium browser: `npx playwright install --with-deps chromium`
- Built SDK bundles (run `yarn build` before browser/integration tests)

## Test Suites

The SDK has three test suites:

| Suite | Runner | Scope | Command |
|-------|--------|-------|---------|
| **Unit tests** | Mocha + Chai | Core logic, context, feature manager, utilities | `yarn test:mocha` |
| **Browser tests** | Playwright | UMD bundle loaded in Chromium | `yarn test:browser` |
| **Integration tests** | Playwright | Full SDK lifecycle (init, bucket, feature, conversion) | `yarn test:browser` |

### Run everything

```bash
yarn build
yarn test:mocha
yarn test:browser
```

Or use the combined command (includes coverage):

```bash
yarn build
yarn test
```

## Unit Tests (Mocha)

Located in `tests/**/*.tests.ts`. These test SDK internals using Mocha + Chai with `ts-node/register`.

```bash
yarn test:mocha
```

Test files:
- `tests/core.tests.ts` — Core class (init, context creation, events)
- `tests/context.tests.ts` — Context class (runExperience, runFeature, trackConversion)
- `tests/feature-manager.tests.ts` — Feature manager logic
- `tests/utils/*.tests.ts` — Array, object, string, and comparison utilities

These tests use `tests/test-config.json` (fabricated IDs) and do **not** require network access.

## Browser Tests (Playwright)

Located in `tests/browser/`. These verify the built UMD bundle works correctly in a real browser environment.

```bash
yarn build # Must build first — tests serve the built bundles
yarn test:browser
```

**How it works:**
1. Playwright starts a local HTTP server (`tests/browser/test-server.js`) on port 3939
2. The server serves the built UMD bundle (`lib/index.umd.min.js`) and a test HTML page
3. Tests navigate to the page and use `page.evaluate()` to exercise the SDK in browser context

Test file:
- `tests/browser/umd-bundle.spec.ts` — 19 tests covering SDK instantiation, experiences, features, conversions, segments, and invalid visitor handling

These tests use `tests/test-config.json` (fabricated IDs) and do **not** require network access.

## Integration Tests (Playwright)

Located in `tests/integration/`. These run the full SDK lifecycle in Node.js context (not browser), matching the PHP SDK's `FullChainIntegrationTest` pattern.

```bash
yarn build # Must build first — tests import from lib/
yarn test:browser # Integration tests run as part of the Playwright suite
```

Test file:
- `tests/integration/full-chain.spec.ts` — 17 tests per mode covering:
- **Happy path:** init, ready event, experience bucketing, bucketing determinism, bucketing events, typed feature variables, full chain verification
- **Negative path:** unknown feature key, non-qualifying location, audience mismatch
- **Conversion tracking:** basic conversion, conversion events, goal deduplication, revenue tracking, forced multiple transactions, nonexistent goal
- **Complete chain:** init -> context -> bucket -> feature -> conversion -> flush

### Auth Modes

Integration tests run in up to 3 modes, following the PHP SDK pattern:

| Mode | Config source | Env vars required | Always runs? |
|------|--------------|-------------------|-------------|
| `static` | `tests/integration/static-config.json` | None | Yes |
| `live` | CDN fetch (public key) | `CONVERT_STAGING_SDK_KEY` | No |
| `live-secret` | CDN fetch (authenticated) | `CONVERT_STAGING_SDK_KEY2`, `CONVERT_STAGING_SDK_KEY2_SECRET` | No |

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.

### Setting up env vars for live tests

Copy `.env.example` to `.env` and fill in the values:

```bash
# Public SDK key for unauthenticated CDN fetch
CONVERT_STAGING_SDK_KEY=<public-sdk-key>

# SDK key + secret for authenticated CDN fetch
CONVERT_STAGING_SDK_KEY2=<sdk-key>
CONVERT_STAGING_SDK_KEY2_SECRET=<sdk-key-secret>
```

Then run with the env vars loaded:

```bash
export $(grep -v '^#' .env | xargs)
yarn build
yarn test:browser
```

### Staging Project

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.

Key entities:
- **Experience:** `test-experience-ab-fullstack-4` — 50/50 split, pricing-location, no audiences
- **Feature-1:** boolean `enabled`, string `caption`
- **Feature-2:** float `price` (100), integer `button-height` (40), json `additionalData`
- **Goals:** `increase-engagement` (dom_interaction, no rules), `decrease-bounce-rate` (advanced)

**Do not modify or delete this project.** Changes will break integration tests in both the JS and PHP SDKs.

## Playwright Configuration

Config file: `playwright.config.ts`

- **Test server:** Auto-started on port 3939 (configurable via `PORT` env var)
- **Browser:** Chromium only, headless, with `--no-sandbox`
- **Workers:** 1 (sequential execution — tests share SDK state)
- **Timeout:** 60 seconds per test
- **Retries:** 2 on CI, 0 locally
- **Traces:** Retained on failure

## CI

Tests run in GitHub Actions via `.github/workflows/qa.yml`:

```
yarn → build → lint → test:mocha → test:browser
```

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.

## Writing New Tests

### Adding a unit test

Add a `.tests.ts` file under `tests/`. It will be picked up automatically by the mocha glob `tests/**/*.tests.ts`.

```typescript
import 'mocha';
import {expect} from 'chai';

describe('MyFeature', () => {
it('should do something', () => {
expect(true).to.be.true;
});
});
```

### Adding a browser test

Add assertions to `tests/browser/umd-bundle.spec.ts` or create a new `.spec.ts` file under `tests/browser/`.

```typescript
import {test, expect} from '@playwright/test';

test('SDK does something in browser', async ({page}) => {
await page.goto('/');
const result = await page.evaluate(() => {
// ConvertSDK is available as a global from the UMD bundle
return typeof ConvertSDK;
});
expect(result).toBe('function');
});
```

### Adding an integration test

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.

```typescript
test('My new integration test', async () => {
const sdk = createSdk(mode);
await sdk.onReady();
const context = sdk.createContext('my-visitor-id');
// ... exercise SDK and assert
});
```
7 changes: 0 additions & 7 deletions packages/js-sdk/index.browser.cjs.tests.js

This file was deleted.

12 changes: 0 additions & 12 deletions packages/js-sdk/index.browser.umd.tests.js

This file was deleted.

Loading
Loading