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
8 changes: 4 additions & 4 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -286,12 +286,12 @@ PODS:
- React
- RNGestureHandler (2.3.0):
- React-Core
- segment-analytics-react-native (2.1.12):
- segment-analytics-react-native (2.2.0):
- React-Core
- sovran-react-native
- segment-analytics-react-native-plugin-idfa (0.2.1):
- React-Core
- sovran-react-native (0.2.7):
- sovran-react-native (0.2.8):
- React-Core
- Yoga (1.14.0)

Expand Down Expand Up @@ -459,9 +459,9 @@ SPEC CHECKSUMS:
RNCAsyncStorage: b49b4e38a1548d03b74b30e558a1d18465b94be7
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNGestureHandler: 77d59828d40838c9fabb76a12d2d0a80c006906f
segment-analytics-react-native: 5287504fa5aa60e64dbb497bee5c7eb6f94e5e49
segment-analytics-react-native: d0b24d7b7e6e6968a3558a2c41f61e94420b6797
segment-analytics-react-native-plugin-idfa: 80e5d610f537156833eabea12a1804523355de95
sovran-react-native: 8d549886ad24ab51f8d471a7db83d1a3ace36358
sovran-react-native: e4064b633fd8232055d003460d5816dff87ba8cc
Yoga: 90dcd029e45d8a7c1ff059e8b3c6612ff409061a

PODFILE CHECKSUM: 0c7eb82d495ca56953c50916b7b49e7512632eb6
Expand Down
2 changes: 1 addition & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@react-native-community/masked-view": "^0.1.11",
"@react-navigation/native": "^6.0.2",
"@react-navigation/stack": "^6.0.7",
"@segment/sovran-react-native": "^0.2.7",
"@segment/sovran-react-native": "^0.2.8",
"react": "17.0.2",
"react-native": "0.67.3",
"react-native-bootsplash": "^3.2.4",
Expand Down
8 changes: 4 additions & 4 deletions example/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1575,10 +1575,10 @@
color "^3.1.3"
warn-once "^0.1.0"

"@segment/sovran-react-native@^0.2.7":
version "0.2.7"
resolved "https://registry.yarnpkg.com/@segment/sovran-react-native/-/sovran-react-native-0.2.7.tgz#5df47d00a862481ab1f3f07bcc4b8e0a737930ae"
integrity sha512-P4pv3yIbUMv1X54TGioZb+8m4DiDCyKBRuyheqbFEblZeZSckI+WuRp/pooQeyHoGBMQbOY/j0yKksY3Yydkvg==
"@segment/sovran-react-native@^0.2.8":
version "0.2.8"
resolved "https://registry.yarnpkg.com/@segment/sovran-react-native/-/sovran-react-native-0.2.8.tgz#76a3c29011f9726a0fa2ac3942fb1d7715816d7e"
integrity sha512-b3a2vfEj2+jb8w/o+rNrJESWUhHEtrRZgydRNg1PEmMDlLeh42T3mDAap4mtGFICRDHU57w2zPeuw+wfs/sk7g==
dependencies:
"@react-native-async-storage/async-storage" "^1.15.15"
ansi-regex "5.0.1"
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"homepage": "https://github.com/segmentio/analytics-react-native#readme",
"dependencies": {
"@react-native-async-storage/async-storage": "^1.15.17",
"@segment/sovran-react-native": "^0.2.7",
"@segment/sovran-react-native": "^0.2.8",
"deepmerge": "^4.2.2",
"js-base64": "^3.7.2",
"nanoid": "^3.1.25"
Expand Down
34 changes: 6 additions & 28 deletions packages/core/src/__tests__/__helpers__/mockSegmentStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
SegmentEvent,
UserInfoState,
} from '../../types';
import { createCallbackManager } from './utils';

type Data = {
isReady: boolean;
Expand Down Expand Up @@ -51,35 +52,12 @@ export class MockSegmentStore implements Storage {
);
}

// Callbacks
private createCallbackManager = <V, R = void>() => {
type Callback = (value: V) => R;
const callbacks: Callback[] = [];

const deregister = (callback: Callback) => {
callbacks.splice(callbacks.indexOf(callback), 1);
};

const register = (callback: Callback) => {
callbacks.push(callback);
return () => {
deregister(callback);
};
};

const run = (value: V) => {
callbacks.forEach((callback) => callback(value));
};

return { register, deregister, run };
};

private callbacks = {
context: this.createCallbackManager<DeepPartial<Context> | undefined>(),
settings: this.createCallbackManager<SegmentAPIIntegrations>(),
events: this.createCallbackManager<SegmentEvent[]>(),
userInfo: this.createCallbackManager<UserInfoState>(),
deepLinkData: this.createCallbackManager<DeepLinkData>(),
context: createCallbackManager<DeepPartial<Context> | undefined>(),
settings: createCallbackManager<SegmentAPIIntegrations>(),
events: createCallbackManager<SegmentEvent[]>(),
userInfo: createCallbackManager<UserInfoState>(),
deepLinkData: createCallbackManager<DeepLinkData>(),
};

readonly isReady = {
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/__tests__/__helpers__/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const createCallbackManager = <V, R = void>() => {
type Callback = (value: V) => R;
const callbacks: Callback[] = [];

const deregister = (callback: Callback) => {
callbacks.splice(callbacks.indexOf(callback), 1);
};

const register = (callback: Callback) => {
callbacks.push(callback);
return () => {
deregister(callback);
};
};

const run = (value: V) => {
for (const callback of [...callbacks]) {
callback(value);
}
};

return { register, deregister, run };
};
102 changes: 102 additions & 0 deletions packages/core/src/storage/__tests__/sovranStorage.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import deepmerge from 'deepmerge';
import { createCallbackManager } from '../../__tests__/__helpers__/utils';
import { SovranStorage } from '../sovranStorage';

jest.mock('@segment/sovran-react-native', () => ({
registerBridgeStore: jest.fn(),
createStore: <T extends {}>(initialState: T) => {
const callbackManager = createCallbackManager<T>();

let store = {
...initialState,
};

return {
subscribe: jest
.fn()
.mockImplementation((callback: (state: T) => void) => {
callbackManager.register(callback);
return () => callbackManager.deregister(callback);
}),
dispatch: jest
.fn()
.mockImplementation(
async (action: (state: T) => T | Promise<T>): Promise<T> => {
store = await action(store);
callbackManager.run(store);
return store;
}
),
getState: jest.fn().mockImplementation(() => ({ ...store })),
};
},
}));

describe('sovranStorage', () => {
it('works', async () => {
// First test that the constructor works correctly
const sovran = new SovranStorage('test');
expect(sovran.isReady.get()).toBe(false);

// Setup a listener for context changes
const contextListener = jest.fn();
sovran.context.onChange(contextListener);

// A basic test that sets up the context data in the store and checks that the listener is called
const appContext = {
app: {
name: 'test',
namespace: 'com.segment',
version: '1.0.0',
},
device: {
manufacturer: 'Apple',
model: 'iPhone X',
name: 'iPhone',
type: 'mobile',
},
};

const newContext = await sovran.context.set(appContext);
expect(newContext).toEqual(appContext);
expect(sovran.context.get()).toEqual(appContext);
expect(contextListener).toHaveBeenCalledWith(appContext);

// Context should be deeply merged to preserve values set by other plugins
const deviceToken = {
device: {
token: '123',
},
};

const expected = deepmerge(appContext, deviceToken);
const updated = await sovran.context.set(deviceToken);
expect(updated).toEqual(expected);
expect(sovran.context.get()).toEqual(expected);
expect(contextListener).toHaveBeenCalledWith(expected);

// Now lets test the settings, settings are not deeply merged, only merged at the top level
const settings = {
segment: {
apiKey: '123',
},
};

const newSettings = await sovran.settings.set(settings);
expect(newSettings).toEqual(settings);
expect(sovran.settings.get()).toEqual(settings);

const settingsUpdate = {
segment: {
key: '123',
},
braze: {
key: '123',
},
};

const updatedSettings = await sovran.settings.set(settingsUpdate);
expect(updatedSettings).toEqual(settingsUpdate);
expect(sovran.settings.get()).toEqual(settingsUpdate);
});
});
3 changes: 2 additions & 1 deletion packages/core/src/storage/sovranStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
registerBridgeStore,
Store,
} from '@segment/sovran-react-native';
import deepmerge from 'deepmerge';
import type {
SegmentAPIIntegrations,
IntegrationSettings,
Expand Down Expand Up @@ -162,7 +163,7 @@ export class SovranStorage implements Storage {
this.contextStore.subscribe((store) => callback(store.context)),
set: async (value: DeepPartial<Context>) => {
const { context } = await this.contextStore.dispatch((state) => {
return { context: { ...state.context, ...value } };
return { context: deepmerge(state.context, value) };
});
return context;
},
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2141,10 +2141,10 @@
conventional-recommended-bump "^6.1.0"
prepend-file "^2.0.0"

"@segment/sovran-react-native@^0.2.7":
version "0.2.7"
resolved "https://registry.yarnpkg.com/@segment/sovran-react-native/-/sovran-react-native-0.2.7.tgz#5df47d00a862481ab1f3f07bcc4b8e0a737930ae"
integrity sha512-P4pv3yIbUMv1X54TGioZb+8m4DiDCyKBRuyheqbFEblZeZSckI+WuRp/pooQeyHoGBMQbOY/j0yKksY3Yydkvg==
"@segment/sovran-react-native@^0.2.8":
version "0.2.8"
resolved "https://registry.yarnpkg.com/@segment/sovran-react-native/-/sovran-react-native-0.2.8.tgz#76a3c29011f9726a0fa2ac3942fb1d7715816d7e"
integrity sha512-b3a2vfEj2+jb8w/o+rNrJESWUhHEtrRZgydRNg1PEmMDlLeh42T3mDAap4mtGFICRDHU57w2zPeuw+wfs/sk7g==
dependencies:
"@react-native-async-storage/async-storage" "^1.15.15"
ansi-regex "5.0.1"
Expand Down