Skip to content

Commit 913bc00

Browse files
yusintoLaunchDarklyReleaseBot
andauthored
fix: Add more rn sdk unit tests. (#339)
* Added more coverage for rn sdk. * Added separate tsconfig.json for tests. * Improved jest config. * Removed release-as from release please config. --------- Co-authored-by: LaunchDarklyReleaseBot <[email protected]>
1 parent df1dae4 commit 913bc00

File tree

12 files changed

+179
-34
lines changed

12 files changed

+179
-34
lines changed

packages/sdk/react-native/example/app.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111
"resizeMode": "contain",
1212
"backgroundColor": "#ffffff"
1313
},
14-
"assetBundlePatterns": [
15-
"**/*"
16-
],
14+
"assetBundlePatterns": ["**/*"],
1715
"ios": {
1816
"supportsTablet": true,
1917
"bundleIdentifier": "com.anonymous.reactnativeexample"

packages/sdk/react-native/jest.config.json

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { JestConfigWithTsJest } from 'ts-jest';
2+
3+
const jestConfig: JestConfigWithTsJest = {
4+
preset: 'ts-jest',
5+
testEnvironment: 'jsdom',
6+
transform: {
7+
'^.+\\.tsx?$': [
8+
'ts-jest',
9+
{
10+
tsconfig: 'tsconfig.test.json',
11+
},
12+
],
13+
},
14+
testPathIgnorePatterns: ['node_modules', 'example', 'dist'],
15+
};
16+
17+
export default jestConfig;

packages/sdk/react-native/package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
"start": "rimraf dist && yarn tsw",
3333
"lint": "eslint . --ext .ts",
3434
"prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore",
35-
"test": "NODE_OPTIONS=\"--experimental-vm-modules --no-warnings\" jest --ci --runInBand",
35+
"test": "jest",
3636
"coverage": "yarn test --coverage",
3737
"check": "yarn prettier && yarn lint && yarn build && yarn test",
3838
"link-dev": "./link-dev.sh",
@@ -50,8 +50,9 @@
5050
"event-target-shim": "^6.0.2"
5151
},
5252
"devDependencies": {
53+
"@testing-library/react": "^14.1.2",
5354
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
54-
"@types/jest": "^29.5.0",
55+
"@types/jest": "^29.5.11",
5556
"@types/react": "^18.2.31",
5657
"@typescript-eslint/eslint-plugin": "^6.1.0",
5758
"@typescript-eslint/parser": "^6.1.0",
@@ -61,13 +62,15 @@
6162
"eslint-config-prettier": "^8.8.0",
6263
"eslint-plugin-import": "^2.27.5",
6364
"eslint-plugin-prettier": "^5.0.0",
64-
"jest": "^29.5.0",
65+
"jest": "^29.7.0",
6566
"launchdarkly-js-test-helpers": "^2.2.0",
6667
"prettier": "^3.0.0",
6768
"react": "^18.2.0",
69+
"react-dom": "^18.2.0",
6870
"react-native": "^0.73.1",
6971
"rimraf": "^5.0.5",
70-
"ts-jest": "^29.1.0",
72+
"ts-jest": "^29.1.1",
73+
"ts-node": "^10.9.2",
7174
"typedoc": "0.25.0",
7275
"typescript": "5.1.6"
7376
},

packages/sdk/react-native/src/ReactNativeLDClient.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ describe('ReactNativeLDClient', () => {
66
let ldc: ReactNativeLDClient;
77

88
beforeEach(() => {
9-
ldc = new ReactNativeLDClient('mob-test', { sendEvents: false });
9+
ldc = new ReactNativeLDClient('mobile-key', { sendEvents: false });
1010
});
1111

1212
test('constructing a new client', () => {
13-
expect(ldc.sdkKey).toEqual('mob-test');
13+
expect(ldc.sdkKey).toEqual('mobile-key');
1414
expect(ldc.config.serviceEndpoints).toEqual({
1515
analyticsEventPath: '/mobile',
1616
diagnosticEventPath: '/mobile/events/diagnostic',
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { render } from '@testing-library/react';
2+
3+
import type { LDContext, LDOptions } from '@launchdarkly/js-client-sdk-common';
4+
5+
import { useLDClient } from '../hooks';
6+
import ReactNativeLDClient from '../ReactNativeLDClient';
7+
import LDProvider from './LDProvider';
8+
import setupListeners from './setupListeners';
9+
10+
jest.mock('./setupListeners');
11+
jest.mock('../ReactNativeLDClient');
12+
13+
const TestApp = () => {
14+
const ldClient = useLDClient();
15+
return (
16+
<>
17+
<p>ldClient {ldClient ? 'defined' : 'undefined'}</p>
18+
<p>mobileKey {ldClient.sdkKey ? ldClient.sdkKey : 'undefined'}</p>
19+
<p>context {ldClient.getContext() ? 'defined' : 'undefined'}</p>
20+
</>
21+
);
22+
};
23+
describe('LDProvider', () => {
24+
let ldc: ReactNativeLDClient;
25+
let context: LDContext;
26+
let mockSetupListeners = setupListeners as jest.Mock;
27+
28+
beforeEach(() => {
29+
jest.useFakeTimers();
30+
(ReactNativeLDClient as jest.Mock).mockImplementation(
31+
(mobileKey: string, _options?: LDOptions) => {
32+
let context: LDContext;
33+
34+
return {
35+
sdkKey: mobileKey,
36+
identify: jest.fn((c: LDContext) => {
37+
context = c;
38+
return Promise.resolve();
39+
}),
40+
getContext: jest.fn(() => context),
41+
on: jest.fn(),
42+
logger: {
43+
debug: jest.fn(),
44+
},
45+
};
46+
},
47+
);
48+
mockSetupListeners.mockImplementation((client: ReactNativeLDClient, setState: any) => {
49+
setState({ client });
50+
});
51+
ldc = new ReactNativeLDClient('mobile-key');
52+
context = { kind: 'user', key: 'test-user-key-1' };
53+
});
54+
55+
afterEach(() => {
56+
jest.resetAllMocks();
57+
});
58+
59+
test('client is correctly set', () => {
60+
const { getByText } = render(
61+
<LDProvider client={ldc}>
62+
<TestApp />
63+
</LDProvider>,
64+
);
65+
66+
expect(getByText(/ldclient defined/i)).toBeTruthy();
67+
expect(getByText(/mobilekey mobile-key/i)).toBeTruthy();
68+
expect(getByText(/context undefined/i)).toBeTruthy();
69+
});
70+
71+
test('specified context is identified', async () => {
72+
const { getByText } = render(
73+
<LDProvider client={ldc} context={context}>
74+
<TestApp />
75+
</LDProvider>,
76+
);
77+
78+
expect(mockSetupListeners).toHaveBeenCalledWith(ldc, expect.any(Function));
79+
expect(ldc.identify).toHaveBeenCalledWith(context);
80+
expect(ldc.getContext()).toEqual(context);
81+
expect(getByText(/context defined/i)).toBeTruthy();
82+
});
83+
84+
test('identify errors are caught', async () => {
85+
(ldc.identify as jest.Mock).mockImplementation(() => {
86+
return Promise.reject('faking error when identifying');
87+
});
88+
const { getByText } = render(
89+
<LDProvider client={ldc} context={context}>
90+
<TestApp />
91+
</LDProvider>,
92+
);
93+
await jest.runAllTimersAsync();
94+
95+
expect(ldc.logger.debug).toHaveBeenCalledWith(expect.stringMatching(/identify error/));
96+
});
97+
});

packages/sdk/react-native/src/provider/LDProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PropsWithChildren, useEffect, useState } from 'react';
1+
import React, { PropsWithChildren, useEffect, useState } from 'react';
22

33
import { type LDContext } from '@launchdarkly/js-client-sdk-common';
44

packages/sdk/react-native/src/provider/reactContext.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { createContext } from 'react';
22

3-
import { LDClient } from '@launchdarkly/js-client-sdk-common';
3+
import type ReactNativeLDClient from '../ReactNativeLDClient';
44

55
export type ReactContext = {
6-
client: LDClient;
6+
client: ReactNativeLDClient;
77
};
88

99
export const context = createContext<ReactContext>({
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import ReactNativeLDClient from '../ReactNativeLDClient';
2+
import setupListeners from './setupListeners';
3+
4+
import resetAllMocks = jest.resetAllMocks;
5+
6+
jest.mock('../ReactNativeLDClient');
7+
8+
describe('setupListeners', () => {
9+
let ldc: ReactNativeLDClient;
10+
let mockSetState: jest.Mock;
11+
12+
beforeEach(() => {
13+
mockSetState = jest.fn();
14+
ldc = new ReactNativeLDClient('mob-test-key');
15+
});
16+
17+
afterEach(() => resetAllMocks());
18+
19+
test('change listener is setup', () => {
20+
setupListeners(ldc, mockSetState);
21+
expect(ldc.on).toHaveBeenCalledWith('change', expect.any(Function));
22+
});
23+
24+
test('client is set on change event', () => {
25+
setupListeners(ldc, mockSetState);
26+
27+
const changeHandler = (ldc.on as jest.Mock).mock.calls[0][1];
28+
changeHandler();
29+
30+
expect(mockSetState).toHaveBeenCalledWith({ client: ldc });
31+
});
32+
});

packages/sdk/react-native/tsconfig.json

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
"allowSyntheticDefaultImports": true,
44
"declaration": true,
55
"declarationMap": true,
6-
"jsx": "react-native",
7-
"lib": [
8-
"es6",
9-
"dom"
10-
],
6+
"jsx": "react-jsx",
7+
"lib": ["es6", "dom"],
118
"module": "ES6",
129
"moduleResolution": "node",
1310
"noImplicitOverride": true,
@@ -21,7 +18,7 @@
2118
"strict": true,
2219
"stripInternal": true,
2320
"target": "ES2017",
24-
"types": ["jest", "node"]
21+
"types": ["node"]
2522
},
26-
"exclude": ["**/*.test.ts", "dist", "node_modules", "__tests__", "example"]
23+
"exclude": ["**/*.test.ts*", "dist", "node_modules", "__tests__", "example"]
2724
}

0 commit comments

Comments
 (0)