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
10 changes: 10 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,14 @@ module.exports = {
// The built mParticle.js file needs to exist for integration tests
setupFiles: ['./dist/mparticle.js'],
setupFilesAfterEnv: ['jest-expect-message'],
transform: {
'^.+\\.(js)$': 'ts-jest',
},
globals: {
'ts-jest': {
tsconfig: {
allowJs: true,
},
},
},
};
15 changes: 14 additions & 1 deletion src/persistence.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export default function _Persistence(mpInstance) {
mpInstance._Store.isFirstRun = false;
}

if (mpInstance._Store.getPrivacyFlag('SDKState')) {
return;
}

// https://go.mparticle.com/work/SQDSDKS-6045
if (!mpInstance._Store.isLocalStorageAvailable) {
mpInstance._Store.SDKConfig.useCookieStorage = true;
Expand Down Expand Up @@ -142,7 +146,10 @@ export default function _Persistence(mpInstance) {
};

this.update = function() {
if (!mpInstance._Store.webviewBridgeEnabled) {
if (
!mpInstance._Store.webviewBridgeEnabled &&
!mpInstance._Store.getPrivacyFlag('SDKState')
) {
if (mpInstance._Store.SDKConfig.useCookieStorage) {
self.setCookie();
}
Expand Down Expand Up @@ -962,6 +969,9 @@ export default function _Persistence(mpInstance) {

// https://go.mparticle.com/work/SQDSDKS-6021
this.savePersistence = function(persistence) {
if (mpInstance._Store.getPrivacyFlag('SDKState')) {
return;
}
var encodedPersistence = self.encodePersistence(
JSON.stringify(persistence)
),
Expand Down Expand Up @@ -1006,6 +1016,9 @@ export default function _Persistence(mpInstance) {
};

this.getPersistence = function() {
if (mpInstance._Store.getPrivacyFlag('SDKState')) {
return null;
}
var persistence = this.useLocalStorage()
? this.getLocalStorage()
: this.getCookie();
Expand Down
164 changes: 164 additions & 0 deletions test/jest/persistence.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import Store, { IStore } from '../../src/store';
import { IMParticleWebSDKInstance } from '../../src/mp-instance';
import { SDKInitConfig } from '../../src/sdkRuntimeModels';
import Persistence from '../../src/persistence';
import { isObject } from '../../src/utils';

describe('Persistence', () => {
let store: IStore;
let mockMPInstance: IMParticleWebSDKInstance;
let persistence: Persistence;

beforeEach(() => {
store = {} as IStore;
mockMPInstance = {
Comment thread
alexs-mparticle marked this conversation as resolved.
_Helpers: {
createMainStorageName: () => 'mprtcl-v4',
isObject,
},
_NativeSdkHelpers: {
isWebviewEnabled: () => false,
},
_Store: store,
Identity: {
getCurrentUser: jest.fn().mockReturnValue({
getMPID: () => 'test-mpid',
}),
},
Logger: {
verbose: jest.fn(),
error: jest.fn(),
warning: jest.fn(),
},
} as unknown as IMParticleWebSDKInstance;

Store.call(store, {} as SDKInitConfig, mockMPInstance, 'apikey');

store.isLocalStorageAvailable = true;
store.SDKConfig.useCookieStorage = true;
store.webviewBridgeEnabled = false;

persistence = new Persistence(mockMPInstance);
window.localStorage.removeItem(encodeURIComponent(store.storageName));
});

describe('#update', () => {
describe('noFunctional privacy flag set to true', () => {
beforeEach(() => {
store.setNoFunctional(true);
store.webviewBridgeEnabled = false;
});

it('should NOT write to cookie and localStorage when useCookieStorage is true', () => {
store.SDKConfig.useCookieStorage = true;

const setCookieSpy = jest.spyOn(persistence, 'setCookie');
const setLocalStorageSpy = jest.spyOn(persistence, 'setLocalStorage');

persistence.update();

expect(setCookieSpy).not.toHaveBeenCalled();
expect(setLocalStorageSpy).not.toHaveBeenCalled();
expect(window.localStorage.getItem(encodeURIComponent(store.storageName))).toBeNull();
});

it('should NOT write to localStorage when useCookieStorage is false', () => {
store.SDKConfig.useCookieStorage = false;

const setCookieSpy = jest.spyOn(persistence, 'setCookie');
const setLocalStorageSpy = jest.spyOn(persistence, 'setLocalStorage');

persistence.update();

expect(setCookieSpy).not.toHaveBeenCalled();
expect(setLocalStorageSpy).not.toHaveBeenCalled();
expect(window.localStorage.getItem(encodeURIComponent(store.storageName))).toBeNull();
});
});

describe('noFunctional privacy flag set to false', () => {
beforeEach(() => {
store.setNoFunctional(false);
store.webviewBridgeEnabled = false;
});

it('should write to cookie and localStorage when useCookieStorage is true', () => {
store.SDKConfig.useCookieStorage = true;

jest.spyOn(persistence, 'getCookie').mockReturnValue(null);

const setCookieSpy = jest.spyOn(persistence, 'setCookie');
const setLocalStorageSpy = jest.spyOn(persistence, 'setLocalStorage');

persistence.update();

expect(setCookieSpy).toHaveBeenCalled();
expect(setLocalStorageSpy).toHaveBeenCalled();
expect(window.localStorage.getItem(encodeURIComponent(store.storageName))).not.toBeNull();
});

it('should write to localStorage when useCookieStorage is false', () => {
store.SDKConfig.useCookieStorage = false;

const setCookieSpy = jest.spyOn(persistence, 'setCookie');
const setLocalStorageSpy = jest.spyOn(persistence, 'setLocalStorage');

persistence.update();

expect(setCookieSpy).not.toHaveBeenCalled();
expect(setLocalStorageSpy).toHaveBeenCalled();
expect(window.localStorage.getItem(encodeURIComponent(store.storageName))).not.toBeNull();
});
});

describe('noFunctional privacy flag set to false by default', () => {
beforeEach(() => {
// default is false
store.webviewBridgeEnabled = false;
});

it('should write to cookie and localStorage by default when useCookieStorage is true', () => {
Comment thread
alexs-mparticle marked this conversation as resolved.
store.SDKConfig.useCookieStorage = true;

jest.spyOn(persistence, 'getCookie').mockReturnValue(null);

const setCookieSpy = jest.spyOn(persistence, 'setCookie');
const setLocalStorageSpy = jest.spyOn(persistence, 'setLocalStorage');

persistence.update();

expect(setCookieSpy).toHaveBeenCalled();
expect(setLocalStorageSpy).toHaveBeenCalled();
expect(window.localStorage.getItem(encodeURIComponent(store.storageName))).not.toBeNull();
});

it('should write to localStorage by default when useCookieStorage is false', () => {
store.SDKConfig.useCookieStorage = false;

const setCookieSpy = jest.spyOn(persistence, 'setCookie');
const setLocalStorageSpy = jest.spyOn(persistence, 'setLocalStorage');

persistence.update();

expect(setCookieSpy).not.toHaveBeenCalled();
expect(setLocalStorageSpy).toHaveBeenCalled();
expect(window.localStorage.getItem(encodeURIComponent(store.storageName))).not.toBeNull();
});
});

it('should NOT write to storage when webviewBridgeEnabled is true', () => {
store.setNoFunctional(false);
store.webviewBridgeEnabled = true;
store.SDKConfig.useCookieStorage = true;

const setCookieSpy = jest.spyOn(persistence, 'setCookie');
const setLocalStorageSpy = jest.spyOn(persistence, 'setLocalStorage');

persistence.update();

expect(setCookieSpy).not.toHaveBeenCalled();
expect(setLocalStorageSpy).not.toHaveBeenCalled();
expect(window.localStorage.getItem(encodeURIComponent(store.storageName))).toBeNull();
});
});
});
86 changes: 86 additions & 0 deletions test/src/tests-persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1948,4 +1948,90 @@ describe('persistence', () => {
user2.getAllUserAttributes()['ua-list'][1].should.equal('<b>');
user2.getAllUserAttributes()['ua-1'].should.equal('a');
});

describe('noFunctional privacy flag', () => {
beforeEach(() => {
mParticle._resetForTests(MPConfig);
});

describe('set to true', () => {
beforeEach(() => {
mParticle.config.launcherOptions = { noFunctional: true };
});

it('should NOT store cookie when useCookieStorage = true', async () => {
mParticle.config.useCookieStorage = true;

mParticle.init(apiKey, mParticle.config);
await waitForCondition(hasIdentifyReturned);

mParticle.getInstance()._Persistence.update();

expect(findCookie()).to.not.be.ok;
});

it('should NOT write localStorage when useCookieStorage = false', async () => {
mParticle.config.useCookieStorage = false;

mParticle.init(apiKey, mParticle.config);
await waitForCondition(hasIdentifyReturned);

mParticle.getInstance()._Persistence.update();

expect(getLocalStorage()).to.not.be.ok;
});
});

describe('set to false', () => {
beforeEach(() => {
mParticle.config.launcherOptions = { noFunctional: false };
});

it('should store cookie when useCookieStorage = true', async () => {
mParticle.config.useCookieStorage = true;

mParticle.init(apiKey, mParticle.config);
await waitForCondition(hasIdentifyReturned);

mParticle.getInstance()._Persistence.update();

expect(findCookie()).to.be.ok;
});

it('should store localStorage when useCookieStorage = false', async () => {
mParticle.config.useCookieStorage = false;

mParticle.init(apiKey, mParticle.config);
await waitForCondition(hasIdentifyReturned);

mParticle.getInstance()._Persistence.update();

expect(getLocalStorage()).to.be.ok;
});
});

describe('is false by default', () => {
it('should store cookie when useCookieStorage = true', async () => {
mParticle.config.useCookieStorage = true;

mParticle.init(apiKey, mParticle.config);
await waitForCondition(hasIdentifyReturned);

mParticle.getInstance()._Persistence.update();

expect(findCookie()).to.be.ok;
});

it('should store localStorage when useCookieStorage = false', async () => {
mParticle.config.useCookieStorage = false;

mParticle.init(apiKey, mParticle.config);
await waitForCondition(hasIdentifyReturned);

mParticle.getInstance()._Persistence.update();

expect(getLocalStorage()).to.be.ok;
});
});
});
});
Loading