Skip to content

fix: add support for the React Native environment. #223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions e2e/BKTClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -12,14 +12,14 @@ 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
let user: BKTUser

afterEach(() => {
destroyBKTClient()
localStorage.clear()
})

suite('get string variation using user attribute when initializing', () => {
Expand All @@ -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({
Expand All @@ -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({
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -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({
Expand Down
19 changes: 19 additions & 0 deletions e2e/environment.ts
Original file line number Diff line number Diff line change
@@ -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,
}
6 changes: 3 additions & 3 deletions e2e/evaluations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -15,6 +15,7 @@ import {
USER_ID,
} from './constants'
import './assertions'
import { fetchLike } from './environment'

suite('e2e/evaluations', () => {
let config: BKTConfig
Expand All @@ -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({
Expand All @@ -38,7 +39,6 @@ suite('e2e/evaluations', () => {

afterEach(() => {
destroyBKTClient()
localStorage.clear()
})

suite('stringVariation', () => {
Expand Down
63 changes: 32 additions & 31 deletions e2e/events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -23,6 +21,7 @@ import './assertions'
import { EventType } from '../src/internal/model/Event'
import { ForbiddenException, TimeoutException } from '../src/BKTExceptions'
import { ApiId, MetricsEventType } from '../src/internal/model/MetricsEventData'
import { fetchLike, isNodeEnvironment } from './environment'

function getDefaultComponent(client: BKTClient): DefaultComponent {
return (client as BKTClientImpl).component as DefaultComponent
Expand All @@ -38,7 +37,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.
Expand All @@ -55,7 +54,6 @@ suite('e2e/events', () => {

afterEach(() => {
destroyBKTClient()
localStorage.clear()
})

test('goal event', async () => {
Expand Down Expand Up @@ -174,14 +172,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({
Expand Down Expand Up @@ -224,7 +221,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)
Expand All @@ -234,37 +231,43 @@ suite('e2e/events', () => {
const component2 = getDefaultComponent(client)

const events3 = component2.dataModule.eventStorage().getAll()
// 2 events - latency and response size
expect(events3).toHaveLength(2)
// ForbiddenError should not exist
expect(
events.some((e) => {
return (
e.type === EventType.METRICS &&
e.event.event['@type'] === MetricsEventType.ForbiddenError &&
e.event.event.apiId === ApiId.GET_EVALUATIONS
)
}),
).toBe(false)

await client2.flush()

const events4 = component2.dataModule.eventStorage().getAll()

// error from /register_events does not get stored
expect(events4).toHaveLength(0)
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(
events.some((e) => {
return (
e.type === EventType.METRICS &&
e.event.event['@type'] === MetricsEventType.ForbiddenError &&
e.event.event.apiId === ApiId.GET_EVALUATIONS
)
}),
).toBe(false)

await client2.flush()

const events4 = component2.dataModule.eventStorage().getAll()

// 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({
Expand All @@ -276,16 +279,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({
Expand Down
5 changes: 5 additions & 0 deletions e2e/module.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export {
destroyBKTClient,
getBKTClient,
initializeBKTClient,
} from '../src/main.browser'
5 changes: 5 additions & 0 deletions e2e/module.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export {
destroyBKTClient,
getBKTClient,
initializeBKTClient,
} from '../src/main'
5 changes: 5 additions & 0 deletions e2e/module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export {
destroyBKTClient,
getBKTClient,
initializeBKTClient,
} from '../src/main'
9 changes: 9 additions & 0 deletions e2e/setup.browser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import { afterEach } from 'vitest'
import { setFetchProvider } from './environment'

setFetchProvider(window.fetch)

afterEach(() => {
localStorage.clear()
})
5 changes: 5 additions & 0 deletions e2e/setup.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { setFetchProvider, setIsNodeEnvironment } from './environment'

setFetchProvider(fetch)

setIsNodeEnvironment(true)
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,19 @@
"module": "./dist/main.mjs",
"browser": "./dist/main.browser.mjs",
"types": "./dist/main.d.ts",
"react-native": "./dist/main.native.cjs",
"exports": {
".": {
"node": {
"import": "./dist/main.mjs",
"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",
Expand All @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions src/BKTConfig.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IllegalArgumentException } from './BKTExceptions'
import { BKTStorage, createBKTStorage } from './BKTStorage'
import { IdGenerator } from './internal/IdGenerator'
import { FetchLike } from './internal/remote/fetch'
import { SDK_VERSION } from './internal/version'

Expand Down Expand Up @@ -30,6 +31,7 @@ interface RawBKTConfig {
userAgent?: string
fetch?: FetchLike
storageFactory?: <T>(key: string) => BKTStorage<T>
idGenerator?: IdGenerator
}

export interface BKTConfig extends RawBKTConfig {
Expand Down
14 changes: 14 additions & 0 deletions src/internal/di/PlatformModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Loading