Skip to content
Draft
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 6 additions & 4 deletions .cursor/rules/test-driven-development.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
description: Standards for Test-Driven Development in the Browser SDK project
globs:
tags:
- jasmine
- karma
- vitest
- browser-mode
alwaysApply: true
---

Expand All @@ -29,17 +29,19 @@ touch packages/some-package/src/path/to/feature.spec.ts

**Spec file must exist BEFORE implementation file**

## 3. Spec Structure (Jasmine/Karma)
## 3. Spec Structure (Vitest Browser Mode)

```typescript
import { beforeEach, describe, expect, it, vi } from 'vitest'

describe('FeatureName', () => {
// Setup variables
let feature: FeatureType
let mockDependency: MockType

beforeEach(() => {
// Setup for each test
mockDependency = jasmine.createSpy()
mockDependency = vi.fn()
feature = new FeatureName(mockDependency)

// Use registerCleanupTask for cleanup
Expand Down
28 changes: 7 additions & 21 deletions .cursor/rules/unit-test-best-practices.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ alwaysApply: false

- **Run all unit tests**: `yarn test:unit`
- **Run a specific spec file**: `yarn test:unit --spec <file-path>`
- **Focus on specific tests**: Prepend `f` to `describe` and `it` (e.g., `fdescribe`, `fit`)
- **Focus on specific tests**: Use `describe.only` or `it.only` temporarily

### Examples

Expand All @@ -33,15 +33,15 @@ yarn test:unit --spec "packages/browser-core/**/browser/*.spec.ts"
#### Focus on Specific Tests
```typescript
// Run only this describe block
fdescribe('addEventListener', () => {
describe.only('addEventListener', () => {
// All tests in this block will run
it('should add event listener', () => {})
it('should remove event listener', () => {})
})

// Run only this single test
describe('addEventListener', () => {
fit('should add event listener', () => {
it.only('should add event listener', () => {
// Only this test will run
})

Expand All @@ -64,24 +64,10 @@ describe('addEventListener', () => {
```bash
# 1. Check test output for randomization seed
yarn test:unit
# Look for: "Randomized with seed 65781"

# 2. Set seed in karma configuration
# Edit test/unit/karma.base.conf.js:
module.exports = {
// ... other config
client: {
jasmine: {
// ... other jasmine config
seed: 65781 // Use the seed from step 1
}
}
}

# 3. Run tests with the same order
yarn test:unit
# Look for: Running tests with seed "65781"

# 4. Remove seed after debugging
# 2. Run tests with the same order
yarn test:unit --seed 65781
```

### File Organization
Expand Down Expand Up @@ -169,7 +155,7 @@ beforeEach(() => {
clock = mockClock()
})
it('should handle delayed operations', () => {
const callback = jasmine.createSpy()
const callback = vi.fn()
setTimeout(callback, 1000)

clock.tick(1000) // Instant!
Expand Down
3 changes: 0 additions & 3 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,3 @@ updates:
open-pull-requests-limit: 0
commit-message:
prefix: '👷'
ignore:
# update karma-webpack: RUM-3130
- dependency-name: 'karma-webpack'
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ test/e2e/.pinned-browsers/
*.local.md
.claude/settings.local.json
.claude/worktrees/
**/__screenshots__/
6 changes: 4 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ unit:
junit: test-report/unit/*.xml
script:
- yarn
- yarn playwright install chromium --with-deps
- yarn test:unit
after_script:
- node ./scripts/test/export-test-result.ts unit
Expand Down Expand Up @@ -314,13 +315,14 @@ unit-bs:
interruptible: true
parallel:
matrix:
- BS_BROWSER: [edge, firefox, safari-desktop, chrome-desktop, chrome-mobile]
- BS_BROWSER: [edge, firefox, webkit-desktop, chrome-desktop]
artifacts:
when: always
reports:
junit: test-report/unit-bs/*.xml
script:
- yarn
- node scripts/test/ci-bs.ts test:unit
- FORCE_COLOR=1 node scripts/test/ci-bs.ts test:unit
after_script:
- node ./scripts/test/export-test-result.ts unit-bs

Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ test/
├── apps/ # Test apps for E2E and performance testing
├── e2e/ # Playwright E2E test scenarios
├── performance/ # Performance benchmarking tests
└── unit/ # Karma/Jasmine unit test configuration
└── unit/ # Vitest Browser Mode unit test configuration

scripts/ # Build, deploy, release automation
```
Expand All @@ -97,8 +97,8 @@ For deeper context, see:

### Unit Tests

- Test framework: Jasmine + Karma. Spec files co-located with implementation: `feature.ts` → `feature.spec.ts`
- Focus tests with `fit()` / `fdescribe()`, skip with `xit()` / `xdescribe()`
- Test framework: Vitest Browser Mode. Spec files co-located with implementation: `feature.ts` → `feature.spec.ts`
- Focus tests with `it.only()` / `describe.only()`, skip with `it.skip()` / `describe.skip()`
- Use `registerCleanupTask()` for cleanup, NOT `afterEach()`
- Prefer `collectAsyncCalls(spy, n)` over `waitFor(() => spy.calls.count() > 0)` for waiting on spy calls
- Don't destructure methods from `spy.calls` (e.g., `argsFor`, `mostRecent`) - use `calls.argsFor()` to avoid `@typescript-eslint/unbound-method` errors
Expand Down
19 changes: 6 additions & 13 deletions LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ dev,@angular/core,MIT,Copyright (c) 2010-2024 Google LLC
dev,@angular/platform-browser,MIT,Copyright (c) 2010-2024 Google LLC
dev,@angular/router,MIT,Copyright (c) 2010-2024 Google LLC
dev,@eslint/js,MIT,Copyright OpenJS Foundation and other contributors, <www.openjsf.org>
dev,@jsdevtools/coverage-istanbul-loader,MIT,Copyright (c) 2015 James Messinger
dev,@ngtools/webpack,MIT,Copyright (c) 2017 Google LLC
dev,@playwright/test,Apache-2.0,Copyright Microsoft Corporation
dev,@swc/core,Apache-2.0,Copyright (c) SWC Contributors
Expand All @@ -27,7 +26,6 @@ dev,@types/chrome,MIT,Copyright Microsoft Corporation
dev,@types/busboy,MIT,Copyright Microsoft Corporation
dev,@types/cors,MIT,Copyright Microsoft Corporation
dev,@types/express,MIT,Copyright Microsoft Corporation
dev,@types/jasmine,MIT,Copyright Microsoft Corporation
dev,@types/node,MIT,Copyright Microsoft Corporation
dev,@types/node-forge,MIT,Copyright Microsoft Corporation
dev,@types/ws,MIT,Copyright Microsoft Corporation
Expand All @@ -39,6 +37,10 @@ dev,@wxt-dev/module-react,MIT,Copyright (c) 2023 Aaron
dev,@vitejs/plugin-react,MIT,Copyright (c) 2019-present Evan You & Vite Contributors
dev,@vitejs/plugin-vue,MIT,Copyright (c) 2019-present, Yuxi (Evan) You and Vite contributors
dev,@microsoft/api-extractor,MIT,Copyright (c) Microsoft Corporation. All rights reserved.
dev,@vitest/browser,MIT,Copyright (c) 2021-Present VoidZero Inc. and Vitest contributors
dev,@vitest/browser-playwright,MIT,Copyright (c) 2021-Present VoidZero Inc. and Vitest contributors
dev,@vitest/coverage-istanbul,MIT,Copyright (c) 2021-Present VoidZero Inc. and Vitest contributors
dev,@vitest/eslint-plugin,MIT,Copyright (c) 2022 - PRESENT Verité Mugabo Makuza
dev,@module-federation/enhanced,MIT, Copyright (c) 2020 ScriptedAlchemy LLC (Zack Jackson) Zhou Shaw (zhouxiao)
dev,@vue/compiler-dom,MIT,Copyright (c) 2018-present, Yuxi (Evan) You
dev,@vue/test-utils,MIT,Copyright (c) 2021-present vuejs
Expand All @@ -53,28 +55,18 @@ dev,emoji-name-map,MIT,Copyright 2016-19 Ionică Bizău <bizauionica@gmail.com>
dev,eslint,MIT,Copyright JS Foundation and other contributors
dev,eslint-plugin-import-x,MIT,Copyright (c) 2015 Ben Mosher
dev,eslint-import-resolver-typescript,ISC,Copyright 2021 Alex Gorbatchev <alex.gorbatchev@gmail.com>
dev,eslint-plugin-jasmine,MIT,Copyright (c) 2021 Tom Vincent
dev,eslint-plugin-jsdoc,BSD-3-Clause,Copyright (c) 2018, Gajus Kuizinas (http://gajus.com/)
dev,eslint-plugin-unicorn,MIT,Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
dev,express,MIT,Copyright 2009-2014 TJ Holowaychuk 2013-2014 Roman Shtylman 2014-2015 Douglas Christopher Wilson
dev,globals,MIT,Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
dev,html-webpack-plugin,MIT,Copyright JS Foundation and other contributors
dev,http-server,MIT,Copyright http-party contributors
dev,jasmine-core,MIT,Copyright 2008-2017 Pivotal Labs
dev,json-schema-to-typescript,MIT,
dev,karma,MIT,Copyright 2011-2019 Google Inc.
dev,karma-browserstack-launcher,MIT,Copyright 2011-2013 Google, Inc.
dev,karma-chrome-launcher,MIT,Copyright 2011-2013 Google Inc.
dev,karma-coverage-istanbul-reporter,MIT,Copyright 2017 Matt Lewis
dev,karma-jasmine,MIT,Copyright 2011-2013 Google Inc.
dev,karma-junit-reporter,MIT,Copyright (C) 2011-2013 Google, Inc.
dev,karma-sourcemap-loader,MIT,Copyright 2013 Sergey Todyshev
dev,karma-spec-reporter,MIT,Copyright 2015 Michael Lex
dev,karma-webpack,MIT,Copyright JS Foundation and other contributors
dev,minimatch,ISC,Copyright (c) Isaac Z. Schlueter and Contributors
dev,next,MIT,Copyright (c) 2025 Vercel, Inc.
dev,node-forge,BSD,Copyright (c) 2010, Digital Bazaar, Inc.
dev,pako,MIT,(C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin
dev,playwright,Apache-2.0,Copyright Microsoft Corporation
dev,prettier,MIT,Copyright James Long and contributors
dev,puppeteer,Apache-2.0,Copyright 2017 Google Inc.
dev,react-is,MIT,Copyright (c) Meta Platforms, Inc. and affiliates
Expand All @@ -92,6 +84,7 @@ dev,typescript,Apache-2.0,Copyright Microsoft Corporation
dev,typescript-eslint,MIT,Copyright (c) 2019 typescript-eslint and other contributors
dev,undici,MIT,Copyright (c) Matteo Collina and Undici contributors
dev,vite,MIT,Copyright (c) 2019-present, VoidZero Inc. and Vite contributors
dev,vitest,MIT,Copyright (c) 2021-Present VoidZero Inc. and Vitest contributors
dev,vue,MIT,Copyright (c) 2018-present, Yuxi (Evan) You
dev,nuxt,MIT,Copyright (c) 2016-present Nuxt Team
dev,vue-router,MIT,Copyright (c) 2019-present Eduardo San Martin Morote
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { describe, expect, it } from 'vitest'
import type { RumActionEvent, RumResourceEvent } from '@datadog/browser-rum'
import { FacetRegistry } from '../../../hooks/useEvents'
import type { FacetValuesFilter } from '../../../hooks/useEvents'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { describe, expect, it } from 'vitest'
import type { TelemetryEvent } from '../../../../../../packages/browser-core/src/domain/telemetry'
import type { LogsEvent } from '../../../../../../packages/browser-logs/src/logsEvent.types'
import type { RumEvent } from '../../../../../../packages/browser-rum-core/src/rumEvent.types'
Expand Down
5 changes: 3 additions & 2 deletions developer-extension/src/panel/flushEvents.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { vi, beforeEach, describe, expect, it, type Mock } from 'vitest'
import { registerCleanupTask } from '../../../packages/browser-core/test'
import type { PageMayExitEvent } from '../../../packages/browser-core/src/browser/pageMayExitObservable'
import { createPageMayExitObservable } from '../../../packages/browser-core/src/browser/pageMayExitObservable'
import { flushScript } from './flushEvents'

describe('flushEvents', () => {
let onExitSpy: jasmine.Spy<(event: PageMayExitEvent) => void>
let onExitSpy: Mock<(event: PageMayExitEvent) => void>

beforeEach(() => {
onExitSpy = jasmine.createSpy()
onExitSpy = vi.fn()
registerCleanupTask(createPageMayExitObservable().subscribe(onExitSpy).unsubscribe)
})

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { describe, expect, it } from 'vitest'
import type { RumEvent } from '../../../../../packages/browser-rum-core/src/rumEvent.types'
import type { LogsEvent } from '../../../../../packages/browser-logs/src/logsEvent.types'
import { isSafari } from '../../../../../packages/browser-core/src/tools/utils/browserDetection'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { beforeEach, describe, expect, it } from 'vitest'
import { isChromium } from '../../../../../packages/browser-core/src/tools/utils/browserDetection'
import { getAllFields } from './facetRegistry'

describe('getAllFields', () => {
beforeEach(() => {
beforeEach((ctx) => {
if (!isChromium()) {
pending('Extension only supported in chromium')
ctx.skip(true, 'extension only supported in Chromium')
return
}
})

Expand Down
2 changes: 1 addition & 1 deletion developer-extension/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"moduleResolution": "bundler",
"jsx": "react",
"lib": ["ES2022", "DOM"],
"types": ["chrome", "react", "react-dom", "jasmine"],
"types": ["chrome", "react", "react-dom"],
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"noEmit": true
Expand Down
10 changes: 5 additions & 5 deletions docs/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ Use this strategy to test the integration on Real applications.
## Work with unit tests

1. Write a unit test.
2. Run only your tests by temporarily replacing `describe(...)` with `fdescribe(...)` or `it(...)` with `fit(...)`.
3. Run `yarn test` in the project root. It will launch the tests in watch mode, and also expose [a local URL](http://localhost:9876/) that you can open in any browser.
4. Look at your terminal to see your test results.
5. For deeper investigation, open [the "debug" page](http://localhost:9876/debug.html#) to inspect test execution via the devtools.
2. Run the spec directly with `yarn test:unit --spec packages/path/to/feature.spec.ts`.
3. Use `it.only(...)` or `describe.only(...)` temporarily when you need to focus further. ESLint prevents focused tests from being checked in.
4. Run `yarn test` for Vitest watch mode, or `yarn test:unit` for a single full run.
5. Look at the terminal output; failure screenshots are written next to the failing spec under `__screenshots__`.

## Debug flaky unit tests

Top-level `describe` blocks are run in a random order. Sometimes, an issue can only be reproduced with a given order. To reproduce a test run order:

1. Check the `Randomized with seed XXXX` message from the test output.
1. Check the `Running tests with seed "XXXX"` message from the test output.
2. Run `yarn test:unit --seed XXXX`.

## Work with E2E tests
Expand Down
17 changes: 13 additions & 4 deletions eslint.config.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import eslint from '@eslint/js'
import vitest from '@vitest/eslint-plugin'
import { defineConfig } from 'eslint/config'
import * as tseslint from 'typescript-eslint'
import { importX } from 'eslint-plugin-import-x'
import unicornPlugin from 'eslint-plugin-unicorn'
import jsdocPlugin from 'eslint-plugin-jsdoc'
// @ts-expect-error -- eslint-plugin-jasmine is not typed
import jasmine from 'eslint-plugin-jasmine'
import globals from 'globals'
// eslint-disable-next-line local-rules/disallow-protected-directory-import
import eslintLocalRules from './eslint-local-rules/index.ts'
Expand Down Expand Up @@ -36,6 +35,7 @@ export default defineConfig(
ignores: [
...SCHEMAS.map((schema) => schema.typesPath),
'packages/*/bundle',
'bundle',
'packages/*/cjs',
'packages/*/esm',
'test/**/dist',
Expand Down Expand Up @@ -75,7 +75,7 @@ export default defineConfig(
unicorn: unicornPlugin,
'local-rules': { rules: eslintLocalRules as Record<string, any> },
jsdoc: jsdocPlugin,
jasmine,
vitest,
},

languageOptions: {
Expand Down Expand Up @@ -246,7 +246,6 @@ export default defineConfig(
},
],

'jasmine/no-focused-tests': 'error',
'jsdoc/check-alignment': 'error',
'jsdoc/check-indentation': 'error',
'jsdoc/no-blank-blocks': 'error',
Expand Down Expand Up @@ -475,6 +474,16 @@ export default defineConfig(
},
},

{
files: [SPEC_FILES, 'packages/*/test/**/*.ts'],
rules: {
// vitest is a root devDependency, not listed in each sub-package
'import-x/no-extraneous-dependencies': 'off',
'vitest/no-focused-tests': 'error',
'vitest/no-identical-title': 'error',
},
},

{
files: ['packages/browser-core/src/tools/**/*.ts'],
ignores: [SPEC_FILES],
Expand Down
Loading
Loading