diff --git a/e2e/BKTClient.spec.ts b/e2e/BKTClient.spec.ts index a4728b0b..56c5e360 100644 --- a/e2e/BKTClient.spec.ts +++ b/e2e/BKTClient.spec.ts @@ -3,7 +3,7 @@ import { destroyBKTClient, getBKTClient, initializeBKTClient, -} from '../src/main.browser' +} from './module' import { BKTConfig, defineBKTConfig } from '../src/BKTConfig' import { BKTUser, defineBKTUser } from '../src/BKTUser' import { FEATURE_ID_STRING, USER_ID } from './constants' @@ -12,6 +12,7 @@ import { BKTClient, BKTClientImpl } from '../src/BKTClient' import { DefaultComponent } from '../src/internal/di/Component' import { EvaluationStorageImpl } from '../src/internal/evaluation/EvaluationStorage' import { evaluation1 } from '../test/mocks/evaluations' +import { fetchLike } from './environment' suite('e2e/BKTClientTest', () => { let config: BKTConfig @@ -19,7 +20,6 @@ suite('e2e/BKTClientTest', () => { afterEach(() => { destroyBKTClient() - localStorage.clear() }) suite('get string variation using user attribute when initializing', () => { @@ -29,7 +29,7 @@ suite('e2e/BKTClientTest', () => { apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) user = defineBKTUser({ @@ -54,7 +54,7 @@ suite('e2e/BKTClientTest', () => { apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) user = defineBKTUser({ @@ -99,7 +99,7 @@ suite('e2e/BKTClientTest', () => { apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) user = defineBKTUser({ @@ -201,7 +201,7 @@ suite('e2e/BKTClientTest', () => { apiEndpoint: import.meta.env.VITE_BKT_API_ENDPOINT, apiKey: import.meta.env.VITE_BKT_API_KEY, appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) user = defineBKTUser({ diff --git a/e2e/environment.ts b/e2e/environment.ts new file mode 100644 index 00000000..51645baa --- /dev/null +++ b/e2e/environment.ts @@ -0,0 +1,19 @@ +import { FetchLike } from '../src/internal/remote/fetch' + +let fetchLike: FetchLike +let isNodeEnvironment = false + +function setFetchProvider(fetch: FetchLike) { + fetchLike = fetch +} + +function setIsNodeEnvironment(isNode: boolean) { + isNodeEnvironment = isNode +} + +export { + setFetchProvider, + setIsNodeEnvironment, + fetchLike, + isNodeEnvironment, +} diff --git a/e2e/evaluations.spec.ts b/e2e/evaluations.spec.ts index 93527af9..e8560250 100644 --- a/e2e/evaluations.spec.ts +++ b/e2e/evaluations.spec.ts @@ -3,7 +3,7 @@ import { destroyBKTClient, getBKTClient, initializeBKTClient, -} from '../src/main.browser' +} from './module' import { BKTConfig, defineBKTConfig } from '../src/BKTConfig' import { BKTUser, defineBKTUser } from '../src/BKTUser' import { @@ -15,6 +15,7 @@ import { USER_ID, } from './constants' import './assertions' +import { fetchLike } from './environment' suite('e2e/evaluations', () => { let config: BKTConfig @@ -26,7 +27,7 @@ suite('e2e/evaluations', () => { apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) user = defineBKTUser({ @@ -38,7 +39,6 @@ suite('e2e/evaluations', () => { afterEach(() => { destroyBKTClient() - localStorage.clear() }) suite('stringVariation', () => { diff --git a/e2e/events.spec.ts b/e2e/events.spec.ts index 6622580c..0c6d8045 100644 --- a/e2e/events.spec.ts +++ b/e2e/events.spec.ts @@ -2,10 +2,8 @@ import { suite, test, expect, beforeEach, afterEach, assert } from 'vitest' import { BKTClient, BKTClientImpl, - destroyBKTClient, - getBKTClient, } from '../src/BKTClient' -import { initializeBKTClient } from '../src/main.browser' +import { initializeBKTClient, getBKTClient, destroyBKTClient } from './module' import { BKTConfig, defineBKTConfig } from '../src/BKTConfig' import { BKTUser, defineBKTUser } from '../src/BKTUser' import { DefaultComponent } from '../src/internal/di/Component' @@ -25,6 +23,7 @@ import { ForbiddenException, TimeoutException } from '../src/BKTExceptions' import { ApiId, MetricsEventType } from '../src/internal/model/MetricsEventData' import { SDK_VERSION } from '../src/internal/version' import { SourceId } from '../src/internal/model/SourceId' +import { fetchLike, isNodeEnvironment } from './environment' function getDefaultComponent(client: BKTClient): DefaultComponent { return (client as BKTClientImpl).component as DefaultComponent @@ -40,7 +39,7 @@ suite('e2e/events', () => { apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, // DO NOT remove this line // Because the tests are asynchronous and share the same local storage, // It might fail randomly, having more or fewer events in the storage when checking the test. @@ -57,7 +56,6 @@ suite('e2e/events', () => { afterEach(() => { destroyBKTClient() - localStorage.clear() }) test('goal event', async () => { @@ -187,14 +185,13 @@ suite('e2e/events', () => { test('Using a random string in the api key setting should throw Forbidden', async () => { destroyBKTClient() - localStorage.clear() config = defineBKTConfig({ apiEndpoint: import.meta.env.VITE_BKT_API_ENDPOINT, apiKey: 'some-random-string', featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) user = defineBKTUser({ @@ -239,7 +236,7 @@ suite('e2e/events', () => { apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) await initializeBKTClient(config, user) @@ -249,39 +246,45 @@ suite('e2e/events', () => { const component2 = getDefaultComponent(client) const events3 = await component2.dataModule.eventStorage().getAll() - // 2 events - latency and response size - expect(events3).toHaveLength(2) - // ForbiddenError should not exist - expect( - events.some((e) => { - return ( + + if (isNodeEnvironment) { + // on the node environment, no events should be stored after destroying the client + // because it's using in-memory storage + expect(events3).toHaveLength(0) + } else { + // on the browser environment, we should have 2 events - latency and response size + expect(events3).toHaveLength(2) + // ForbiddenError should not exist + expect( + events3.some((e) => { + return ( e.type === EventType.METRICS && e.event.event['@type'] === MetricsEventType.ForbiddenError && e.event.event.apiId === ApiId.GET_EVALUATIONS && e.event.sdkVersion === SDK_VERSION && e.event.sourceId === SourceId.JAVASCRIPT - ) - }), - ).toBe(false) + ) + }), + ).toBe(false) - await client2.flush() + await client2.flush() - const events4 = await component2.dataModule.eventStorage().getAll() + const events4 = await component2.dataModule.eventStorage().getAll() - // error from /register_events does not get stored - expect(events4).toHaveLength(0) + // error from /register_events does not get stored + expect(events4).toHaveLength(0) + } }) test('Using a random string in the featureTag setting should not affect api request', async () => { destroyBKTClient() - localStorage.clear() config = defineBKTConfig({ apiEndpoint: import.meta.env.VITE_BKT_API_ENDPOINT, apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'some-random-feature-tag', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) user = defineBKTUser({ @@ -293,16 +296,14 @@ suite('e2e/events', () => { test('Timeout', async () => { // setting a very low value for the timeout - destroyBKTClient() - localStorage.clear() config = defineBKTConfig({ apiEndpoint: import.meta.env.VITE_BKT_API_ENDPOINT, apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, }) user = defineBKTUser({ diff --git a/e2e/module.browser.ts b/e2e/module.browser.ts new file mode 100644 index 00000000..95d036b4 --- /dev/null +++ b/e2e/module.browser.ts @@ -0,0 +1,5 @@ +export { + destroyBKTClient, + getBKTClient, + initializeBKTClient, +} from '../src/main.browser' diff --git a/e2e/module.node.ts b/e2e/module.node.ts new file mode 100644 index 00000000..84f131b1 --- /dev/null +++ b/e2e/module.node.ts @@ -0,0 +1,5 @@ +export { + destroyBKTClient, + getBKTClient, + initializeBKTClient, +} from '../src/main' diff --git a/e2e/module.ts b/e2e/module.ts new file mode 100644 index 00000000..84f131b1 --- /dev/null +++ b/e2e/module.ts @@ -0,0 +1,5 @@ +export { + destroyBKTClient, + getBKTClient, + initializeBKTClient, +} from '../src/main' diff --git a/e2e/setup.browser.ts b/e2e/setup.browser.ts new file mode 100644 index 00000000..a917bfb3 --- /dev/null +++ b/e2e/setup.browser.ts @@ -0,0 +1,9 @@ + +import { afterEach } from 'vitest' +import { setFetchProvider } from './environment' + +setFetchProvider(window.fetch) + +afterEach(() => { + localStorage.clear() +}) diff --git a/e2e/setup.node.ts b/e2e/setup.node.ts new file mode 100644 index 00000000..be0fed65 --- /dev/null +++ b/e2e/setup.node.ts @@ -0,0 +1,5 @@ +import { setFetchProvider, setIsNodeEnvironment } from './environment' + +setFetchProvider(fetch) + +setIsNodeEnvironment(true) diff --git a/e2e/wrapperSdkSourceId.spec.ts b/e2e/wrapperSdkSourceId.spec.ts index 6d802ac1..f0b37d43 100644 --- a/e2e/wrapperSdkSourceId.spec.ts +++ b/e2e/wrapperSdkSourceId.spec.ts @@ -24,6 +24,7 @@ import { EventType } from '../src/internal/model/Event' import { TimeoutException } from '../src/BKTExceptions' import { ApiId, MetricsEventType } from '../src/internal/model/MetricsEventData' import { SourceId } from '../src/internal/model/SourceId' +import { fetchLike } from './environment' function getDefaultComponent(client: BKTClient): DefaultComponent { return (client as BKTClientImpl).component as DefaultComponent @@ -39,7 +40,7 @@ suite('e2e/wrapper-sdk-source-id-and-version', () => { apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, // DO NOT remove this line // Because the tests are asynchronous and share the same local storage, // It might fail randomly, having more or fewer events in the storage when checking the test. @@ -58,7 +59,6 @@ suite('e2e/wrapper-sdk-source-id-and-version', () => { afterEach(() => { destroyBKTClient() - localStorage.clear() }) test('goal event', async () => { @@ -123,14 +123,13 @@ suite('e2e/wrapper-sdk-source-id-and-version', () => { // setting a very low value for the timeout destroyBKTClient() - localStorage.clear() config = defineBKTConfig({ apiEndpoint: import.meta.env.VITE_BKT_API_ENDPOINT, apiKey: import.meta.env.VITE_BKT_API_KEY, featureTag: 'javascript', appVersion: '1.2.3', - fetch: window.fetch, + fetch: fetchLike, wrapperSdkSourceId: SourceId.OPEN_FEATURE_JAVASCRIPT, wrapperSdkVersion: '2.2.3', }) diff --git a/package.json b/package.json index 23b5ad98..45379b03 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "module": "./dist/main.mjs", "browser": "./dist/main.browser.mjs", "types": "./dist/main.d.ts", + "react-native": "./dist/main.native.cjs", "exports": { ".": { "node": { @@ -21,6 +22,11 @@ "require": "./dist/main.cjs", "types": "./dist/main.d.ts" }, + "react-native": { + "import": "./dist/main.native.mjs", + "require": "./dist/main.native.cjs", + "types": "./dist/main.d.ts" + }, "default": { "import": "./dist/main.browser.mjs", "require": "./dist/main.browser.cjs", @@ -35,7 +41,9 @@ "test": "pnpm test:browser --run ; pnpm test:node --run", "test:browser": "vitest --config ./vitest-browser.config.ts --dir test", "test:node": "vitest --config ./vitest-node.config.ts --dir test", - "test:e2e": "vitest --config ./vitest-e2e.config.ts --dir e2e", + "test:e2e": "pnpm test:e2e:browser --run ; pnpm test:e2e:node --run", + "test:e2e:browser": "cp -f ./e2e/module.browser.ts ./e2e/module.ts ; vitest --config ./vitest-e2e.config.ts --dir e2e", + "test:e2e:node": "cp -f ./e2e/module.node.ts ./e2e/module.ts ; vitest --config ./vitest-e2e-node.config.ts --dir e2e", "lint": "eslint .", "lint:fix": "eslint --fix .", "example:serve": "pnpm exec unbuild && pnpm --filter example serve" diff --git a/src/BKTConfig.ts b/src/BKTConfig.ts index 5f8a9c4e..0333a094 100644 --- a/src/BKTConfig.ts +++ b/src/BKTConfig.ts @@ -5,6 +5,7 @@ import { resolveSDKVersion, resolveSourceId, } from './internal/InternalConfig' +import { IdGenerator } from './internal/IdGenerator' import { FetchLike } from './internal/remote/fetch' import { SDK_VERSION } from './internal/version' @@ -23,7 +24,7 @@ const isValidUrl = (url: string): boolean => { } } -interface RawBKTConfig { +export interface RawBKTConfig { apiKey: string apiEndpoint: string featureTag?: string @@ -48,6 +49,7 @@ interface RawBKTConfig { // In such cases, set this value to the sourceID of the proxy SDK. // The sourceID is used to identify the origin of the request. wrapperSdkSourceId?: number + idGenerator?: IdGenerator } export interface BKTConfig extends RawBKTConfig { @@ -61,10 +63,14 @@ export interface BKTConfig extends RawBKTConfig { } const defaultUserAgent = () => { - if (typeof window === 'undefined') { - return `Bucketeer JavaScript SDK(${SDK_VERSION})` - } else { + if ( + typeof window !== 'undefined' && + window.navigator && + typeof window.navigator.userAgent === 'string' + ) { return window.navigator.userAgent + } else { + return `Bucketeer JavaScript SDK(${SDK_VERSION})` } } diff --git a/src/internal/di/PlatformModule.ts b/src/internal/di/PlatformModule.ts index fa25b66f..e9d347ce 100644 --- a/src/internal/di/PlatformModule.ts +++ b/src/internal/di/PlatformModule.ts @@ -3,3 +3,17 @@ import { IdGenerator } from '../IdGenerator' export interface PlatformModule { idGenerator(): IdGenerator } + +// BasePlatformModule serves as a base implementation of the PlatformModule interface. +// It relies on the BKTConfig to inject an instance of IdGenerator, which must be set before use. +export class BasePlatformModule implements PlatformModule { + protected _idGenerator: IdGenerator + + constructor(params: { idGenerator: IdGenerator }) { + this._idGenerator = params.idGenerator + } + + idGenerator() { + return this._idGenerator + } +} diff --git a/src/main.browser.ts b/src/main.browser.ts index ced1a96c..72d805fc 100644 --- a/src/main.browser.ts +++ b/src/main.browser.ts @@ -9,7 +9,7 @@ import { requiredInternalConfig } from './internal/InternalConfig' import { User } from './internal/model/User' import { toUser } from './internal/UserHolder' -export type { BKTConfig } from './BKTConfig' +export type { BKTConfig, RawBKTConfig } from './BKTConfig' export { defineBKTConfig } from './BKTConfig' export type { BKTUser } from './BKTUser' export { defineBKTUser } from './BKTUser' diff --git a/src/main.native.ts b/src/main.native.ts new file mode 100644 index 00000000..25576c3e --- /dev/null +++ b/src/main.native.ts @@ -0,0 +1,78 @@ +import { initializeBKTClientInternal } from './BKTClient' +import { BKTConfig, RawBKTConfig } from './BKTConfig' +import { BKTUser } from './BKTUser' +import { Component, DefaultComponent } from './internal/di/Component' +import { DataModule } from './internal/di/DataModule' +import { InteractorModule } from './internal/di/InteractorModule' +import { BasePlatformModule } from './internal/di/PlatformModule' +import { User } from './internal/model/User' +import { toUser } from './internal/UserHolder' +import { IdGenerator } from './internal/IdGenerator' +import { requiredInternalConfig } from './internal/InternalConfig' +import { defineBKTConfig as _defineBKTConfig } from './BKTConfig' +import { IllegalArgumentException } from './BKTExceptions' + +export type { BKTConfig, RawBKTConfig } from './BKTConfig' +export type { BKTUser } from './BKTUser' +export { defineBKTUser } from './BKTUser' +export type { BKTClient } from './BKTClient' +export { getBKTClient, destroyBKTClient } from './BKTClient' +export type { + BKTStorage, + BrowserLocalStorage, + InMemoryStorage, +} from './BKTStorage' +export type { + BKTValue, + BKTJsonArray, + BKTJsonObject, + BKTJsonPrimitive, +} from './BKTValue' +export type { BKTEvaluationDetails } from './BKTEvaluationDetails' + +// This endpoint is intended for use in React Native - Expo environments. +const createComponent = (config: BKTConfig, user: User): Component => { + // Validates idGenerator exists and provides type safety for TypeScript + // Even though defineBKTConfig already validates this, we need the type guard + // to narrow the type from IdGenerator | undefined to IdGenerator + const idGenerator = requiredIdGenerator(config) + return new DefaultComponent( + new BasePlatformModule({ idGenerator }), + new DataModule(user, requiredInternalConfig(config)), + new InteractorModule(), + ) +} + +/** + * React Native specific configuration factory that wraps the base defineBKTConfig + * to validate the presence of idGenerator and enforce React Native environment requirements. + * + * This wrapper ensures that idGenerator is provided and validated at configuration time, + * providing immediate feedback to developers rather than failing later during client initialization. + * + * @param config - Raw configuration object + * @returns Validated BKTConfig with required React Native dependencies + * @throws IllegalArgumentException if idGenerator is missing (required in React Native environment) + */ +export const defineBKTConfig = (config: RawBKTConfig): BKTConfig => { + const bktConfig = _defineBKTConfig(config) + requiredIdGenerator(bktConfig) + return bktConfig +} + +export const initializeBKTClient = async ( + config: BKTConfig, + user: BKTUser, + timeoutMillis = 5_000, +): Promise => { + // idGenerator is required in the React Native environment + const component = createComponent(config, toUser(user)) + return initializeBKTClientInternal(component, timeoutMillis) +} + +function requiredIdGenerator(config: BKTConfig): IdGenerator { + if (!config.idGenerator) { + throw new IllegalArgumentException('idGenerator is required in the React Native environment') + } + return config.idGenerator +} diff --git a/src/main.ts b/src/main.ts index d29271de..4c82ac1c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,12 +4,13 @@ import { BKTUser } from './BKTUser' import { Component, DefaultComponent } from './internal/di/Component' import { DataModule } from './internal/di/DataModule' import { InteractorModule } from './internal/di/InteractorModule' +import { BasePlatformModule } from './internal/di/PlatformModule' import { NodePlatformModule } from './internal/di/PlatformModule.node' import { User } from './internal/model/User' import { toUser } from './internal/UserHolder' import { requiredInternalConfig } from './internal/InternalConfig' -export type { BKTConfig } from './BKTConfig' +export type { BKTConfig, RawBKTConfig } from './BKTConfig' export { defineBKTConfig } from './BKTConfig' export type { BKTUser } from './BKTUser' export { defineBKTUser } from './BKTUser' @@ -30,7 +31,9 @@ export type { BKTEvaluationDetails } from './BKTEvaluationDetails' const createNodeComponent = (config: BKTConfig, user: User): Component => { return new DefaultComponent( - new NodePlatformModule(), + config.idGenerator + ? new BasePlatformModule({ idGenerator: config.idGenerator }) + : new NodePlatformModule(), new DataModule(user, requiredInternalConfig(config)), new InteractorModule(), ) diff --git a/test/main.native.spec.ts b/test/main.native.spec.ts new file mode 100644 index 00000000..77679d9a --- /dev/null +++ b/test/main.native.spec.ts @@ -0,0 +1,98 @@ +import { describe, it, expect } from 'vitest' +import { defineBKTConfig } from '../src/main.native' +import { defineBKTConfig as baseDefineBKTConfig } from '../src/BKTConfig' +import { IdGenerator } from '../src/internal/IdGenerator' +import { IllegalArgumentException } from '../src/BKTExceptions' + +describe('defineBKTConfig - React (Native) required idGenerator', () => { + const validRawConfig = { + apiKey: 'api-key', + apiEndpoint: 'https://api.bucketeer.io', + featureTag: 'tag', + appVersion: '1.0.0', + } + + it('should validate idGenerator and return processed config', () => { + const mockIdGenerator: IdGenerator = { + newId: () => 'test-id', + } + const config = { + ...validRawConfig, + idGenerator: mockIdGenerator, + } + + const result = defineBKTConfig(config) + + // Should be fully processed BKTConfig with all required properties + expect(result).toBeDefined() + expect(result.idGenerator).toBe(mockIdGenerator) + expect(result.apiKey).toBe(config.apiKey) + expect(result.apiEndpoint).toBe(config.apiEndpoint) + expect(result.fetch).toBeDefined() + expect(result.storageFactory).toBeDefined() + }) + + it('should throw error when idGenerator is missing', () => { + const config = { ...validRawConfig } + // idGenerator is missing + + expect(() => { + defineBKTConfig(config) + }).toThrowError( + new IllegalArgumentException( + 'idGenerator is required in the React Native environment', + ), + ) + }) + + it('should throw error when idGenerator is undefined', () => { + const config = { + ...validRawConfig, + idGenerator: undefined, + } + + expect(() => { + defineBKTConfig(config) + }).toThrowError( + new IllegalArgumentException( + 'idGenerator is required in the React Native environment', + ), + ) + }) + + it('should throw error when idGenerator is null', () => { + const config = { + ...validRawConfig, + idGenerator: null as unknown as IdGenerator, + } + + expect(() => { + defineBKTConfig(config) + }).toThrowError( + new IllegalArgumentException( + 'idGenerator is required in the React Native environment', + ), + ) + }) + + it('should not change the result from original baseDefineBKTConfig except for validation', () => { + const mockIdGenerator: IdGenerator = { + newId: () => 'test-id', + } + const config = { + ...validRawConfig, + idGenerator: mockIdGenerator, + } + + const result = defineBKTConfig(config) + const originalResult = baseDefineBKTConfig(config) + + // Should have the same properties as the original + expect(result.apiKey).toBe(originalResult.apiKey) + expect(result.apiEndpoint).toBe(originalResult.apiEndpoint) + expect(result.featureTag).toBe(originalResult.featureTag) + expect(result.fetch).toBe(originalResult.fetch) + expect(result.storageFactory).toBe(originalResult.storageFactory) + expect(result.idGenerator).toBe(originalResult.idGenerator) + }) +}) diff --git a/vitest-e2e-node.config.ts b/vitest-e2e-node.config.ts new file mode 100644 index 00000000..37278662 --- /dev/null +++ b/vitest-e2e-node.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config' +import packageJson from './package.json' + +export default defineConfig({ + define: { + __BKT_SDK_VERSION__: JSON.stringify(packageJson.version), + }, + test: { + setupFiles: ['e2e/setup.node.ts'], + environment: 'node', + }, +}) diff --git a/vitest-e2e.config.ts b/vitest-e2e.config.ts index ff15224c..891cb70a 100644 --- a/vitest-e2e.config.ts +++ b/vitest-e2e.config.ts @@ -6,7 +6,7 @@ export default defineConfig({ __BKT_SDK_VERSION__: JSON.stringify(packageJson.version), }, test: { - setupFiles: [], + setupFiles: ['e2e/setup.browser.ts'], environment: 'happy-dom', browser: { provider: 'webdriverio',