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
34 changes: 28 additions & 6 deletions src/integrationTests/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,8 @@ describe('SDK bootstraps itself if init has already been completed', () => {
const makeIdentity = mocks.makeIdentityV2;
const email = 'test@test.com';
const emailHash = 'lz3+Rj7IV4X1+Vr1ujkG7tstkxwk5pgkqJ6mXbpOgTs=';
const phone = '+12345678901';
const phoneHash = 'EObwtHBUqDNZR33LNSMdtt5cafsYFuGmuY4ZLenlue4=';

beforeEach(() => {
sdkWindow.__uid2 = new UID2();
Expand All @@ -1066,10 +1068,16 @@ describe('SDK bootstraps itself if init has already been completed', () => {
expect(uid2.getAdvertisingToken()).toBe(identity.advertising_token);
expect(uid2.getIdentity()).toStrictEqual(identity);
expect(async () => {
await uid2.setIdentityFromEmail(email, mocks.makeCstgOption());
await uid2.setIdentityFromEmail(email, mocks.makeUid2CstgOption());
}).not.toThrow();
expect(async () => {
uid2.setIdentityFromEmailHash(emailHash, mocks.makeCstgOption());
uid2.setIdentityFromEmailHash(emailHash, mocks.makeUid2CstgOption());
}).not.toThrow();
expect(async () => {
await uid2.setIdentityFromPhone(phone, mocks.makeUid2CstgOption());
}).not.toThrow();
expect(async () => {
uid2.setIdentityFromPhoneHash(phoneHash, mocks.makeUid2CstgOption());
}).not.toThrow();
});

Expand All @@ -1078,10 +1086,16 @@ describe('SDK bootstraps itself if init has already been completed', () => {
expect(uid2.getAdvertisingToken()).toBe(undefined);
expect(uid2.getIdentity()).toStrictEqual(null);
expect(async () => {
await uid2.setIdentityFromEmail(email, mocks.makeCstgOption());
await uid2.setIdentityFromEmail(email, mocks.makeUid2CstgOption());
}).rejects.toThrow();
expect(async () => {
await uid2.setIdentityFromEmailHash(emailHash, mocks.makeUid2CstgOption());
}).rejects.toThrow();
expect(async () => {
await uid2.setIdentityFromEmailHash(emailHash, mocks.makeCstgOption());
await uid2.setIdentityFromPhone(phone, mocks.makeUid2CstgOption());
}).rejects.toThrow();
expect(async () => {
await uid2.setIdentityFromPhoneHash(phoneHash, mocks.makeUid2CstgOption());
}).rejects.toThrow();
});
});
Expand All @@ -1090,6 +1104,8 @@ describe('Token retrieval and related public functions working without init', ()
const makeIdentity = mocks.makeIdentityV2;
const email = 'test@test.com';
const emailHash = 'lz3+Rj7IV4X1+Vr1ujkG7tstkxwk5pgkqJ6mXbpOgTs=';
const phone = '+12345678901';
const phoneHash = 'EObwtHBUqDNZR33LNSMdtt5cafsYFuGmuY4ZLenlue4=';

test('should be able to find identity set without init', async () => {
const identity = { ...makeIdentity(), refresh_from: Date.now() + 100 };
Expand All @@ -1110,10 +1126,16 @@ describe('Token retrieval and related public functions working without init', ()
expect(uid2.getIdentity()).toStrictEqual(identity);
expect(uid2.getAdvertisingTokenAsync()).resolves.toBe(identity.advertising_token);
expect(async () => {
await uid2.setIdentityFromEmail(email, mocks.makeCstgOption());
await uid2.setIdentityFromEmail(email, mocks.makeUid2CstgOption());
}).rejects.toThrow();
expect(async () => {
await uid2.setIdentityFromEmailHash(emailHash, mocks.makeUid2CstgOption());
}).rejects.toThrow();
expect(async () => {
await uid2.setIdentityFromPhone(phone, mocks.makeUid2CstgOption());
}).rejects.toThrow();
expect(async () => {
await uid2.setIdentityFromEmailHash(emailHash, mocks.makeCstgOption());
await uid2.setIdentityFromPhoneHash(phoneHash, mocks.makeUid2CstgOption());
}).rejects.toThrow();
functions.removeIdentity();
});
Expand Down
162 changes: 126 additions & 36 deletions src/integrationTests/clientSideTokenGeneration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import { NAME_CURVE } from '../mocks';
import { base64ToBytes, bytesToBase64 } from '../encoding/base64';
import { EventType } from '../callbackManager';
import { sdkWindow, UID2 } from '../uid2Sdk';
import { EUID } from '../euidSdk';

let uid2: UID2;
let euid: EUID;
let uid2OrEuid: UID2 | EUID;
let xhrMock: any;
let serverKeyPair: CryptoKeyPair;
let serverPublicKey: string;
let serverPublicKeyUid2: string;
let serverPublicKeyEuid: string;

mocks.setupFakeTime();

Expand All @@ -22,62 +26,128 @@ beforeAll(async () => {
);

const serverPubKeyArray = await crypto.subtle.exportKey('spki', serverKeyPair.publicKey);
serverPublicKey = `UID2-X-L-` + bytesToBase64(new Uint8Array(serverPubKeyArray));
serverPublicKeyUid2 = `UID2-X-L-` + bytesToBase64(new Uint8Array(serverPubKeyArray));
serverPublicKeyEuid = `EUID-X-L-` + bytesToBase64(new Uint8Array(serverPubKeyArray));
});

beforeEach(() => {
xhrMock = new mocks.XhrMock(sdkWindow);
mocks.setCookieMock(sdkWindow.document);
removeUid2LocalStorage();
removeEuidLocalStorage();
});

afterEach(() => {
mocks.resetFakeTime();
});

const removeUid2LocalStorage = mocks.removeUid2LocalStorage;
const removeEuidLocalStorage = mocks.removeEuidLocalStorage;

describe('Client-side token generation Tests', () => {
const scenarios = [
{
name: 'setIdentityFromEmail',
setInvalidIdentity: () => uid2.setIdentityFromEmail('test.com', mocks.makeCstgOption()),
identityType: 'uid2',
setInvalidIdentity: () => uid2.setIdentityFromEmail('test.com', mocks.makeUid2CstgOption()),
setIdentity: (serverPublicKey?: string) =>
uid2.setIdentityFromEmail('test@example.com', mocks.makeCstgOption({ serverPublicKey })),
uid2.setIdentityFromEmail(
'test@example.com',
mocks.makeUid2CstgOption({ serverPublicKey })
),
getIdentity: () => mocks.getUid2(),
},
{
name: 'setIdentityFromEmailHash',
identityType: 'uid2',
setInvalidIdentity: () =>
uid2.setIdentityFromEmailHash('test@example.com', mocks.makeCstgOption()),
uid2.setIdentityFromEmailHash('test@example.com', mocks.makeUid2CstgOption()),
setIdentity: (serverPublicKey?: string) =>
uid2.setIdentityFromEmailHash(
'lz3+Rj7IV4X1+Vr1ujkG7tstkxwk5pgkqJ6mXbpOgTs=',
mocks.makeCstgOption({ serverPublicKey })
mocks.makeUid2CstgOption({ serverPublicKey })
),
getIdentity: () => mocks.getUid2(),
},
{
name: 'setIdentityFromPhone',
setInvalidIdentity: () => uid2.setIdentityFromPhone('12345678910', mocks.makeCstgOption()),
identityType: 'uid2',
setInvalidIdentity: () =>
uid2.setIdentityFromPhone('12345678910', mocks.makeUid2CstgOption()),
setIdentity: (serverPublicKey?: string) =>
uid2.setIdentityFromPhone('+12345678910', mocks.makeCstgOption({ serverPublicKey })),
uid2.setIdentityFromPhone('+12345678910', mocks.makeUid2CstgOption({ serverPublicKey })),
getIdentity: () => mocks.getUid2(),
},
{
name: 'setIdentityFromPhoneHash',
identityType: 'uid2',
setInvalidIdentity: () =>
uid2.setIdentityFromPhoneHash('+12345678910', mocks.makeCstgOption()),
uid2.setIdentityFromPhoneHash('+12345678910', mocks.makeUid2CstgOption()),
setIdentity: (serverPublicKey?: string) =>
uid2.setIdentityFromPhoneHash(
'kVJ+4ilhrqm3HZDDnCQy4niZknvCoM4MkoVzZrQSdJw=',
mocks.makeCstgOption({ serverPublicKey })
mocks.makeUid2CstgOption({ serverPublicKey })
),
getIdentity: () => mocks.getUid2(),
},
{
name: 'setIdentityFromEmail',
identityType: 'euid',
setInvalidIdentity: () => euid.setIdentityFromEmail('test.com', mocks.makeEuidCstgOption()),
setIdentity: (serverPublicKey?: string) =>
euid.setIdentityFromEmail(
'test@example.com',
mocks.makeEuidCstgOption({ serverPublicKey })
),
getIdentity: () => mocks.getEuid(),
},
{
name: 'setIdentityFromEmailHash',
identityType: 'euid',
setInvalidIdentity: () =>
euid.setIdentityFromEmailHash('test@example.com', mocks.makeEuidCstgOption()),
setIdentity: (serverPublicKey?: string) =>
euid.setIdentityFromEmailHash(
'lz3+Rj7IV4X1+Vr1ujkG7tstkxwk5pgkqJ6mXbpOgTs=',
mocks.makeEuidCstgOption({ serverPublicKey })
),
getIdentity: () => mocks.getEuid(),
},
{
name: 'setIdentityFromPhone',
identityType: 'euid',
setInvalidIdentity: () =>
euid.setIdentityFromPhone('12345678910', mocks.makeEuidCstgOption()),
setIdentity: (serverPublicKey?: string) =>
euid.setIdentityFromPhone('+12345678910', mocks.makeEuidCstgOption({ serverPublicKey })),
getIdentity: () => mocks.getEuid(),
},
{
name: 'setIdentityFromPhoneHash',
identityType: 'euid',
setInvalidIdentity: () =>
euid.setIdentityFromPhoneHash('+12345678910', mocks.makeEuidCstgOption()),
setIdentity: (serverPublicKey?: string) =>
euid.setIdentityFromPhoneHash(
'kVJ+4ilhrqm3HZDDnCQy4niZknvCoM4MkoVzZrQSdJw=',
mocks.makeEuidCstgOption({ serverPublicKey })
),
getIdentity: () => mocks.getEuid(),
},
];

scenarios.forEach((scenario) => {
describe(scenario.name, () => {
beforeEach(() => {
uid2 = new UID2();
uid2.init({});
if (scenario.identityType === 'uid2') {
uid2 = new UID2();
uid2.init({});
uid2OrEuid = uid2;
} else if (scenario.identityType === 'euid') {
euid = new EUID();
euid.init({});
uid2OrEuid = euid;
}
});

describe('When invalid identity is provided', () => {
Expand Down Expand Up @@ -107,35 +177,45 @@ describe('Client-side token generation Tests', () => {
});

test('should invoke the callback when token is generated', (done) => {
uid2.callbacks.push((eventType, payload) => {
uid2OrEuid.callbacks.push((eventType, payload) => {
if (eventType === EventType.IdentityUpdated) {
expect(payload.identity).toEqual(cstgToken);
done();
}
});
scenario.setIdentity(serverPublicKey);
scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
);
});

test('should set identity to storage', async () => {
await scenario.setIdentity(serverPublicKey);
expect(mocks.getUid2()).toEqual(cstgToken);
await scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
);
expect(scenario.getIdentity()).toEqual(cstgToken);
});

test('UID2 should be in available state', async () => {
await scenario.setIdentity(serverPublicKey);
(expect(uid2) as any).toBeInAvailableState(cstgToken.advertising_token);
test('UID2 or EUID should be in available state', async () => {
await scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
);
(expect(uid2OrEuid) as any).toBeInAvailableState(cstgToken.advertising_token);
});

test('should refresh token when generated token requires a refresh', async () => {
await scenario.setIdentity(serverPublicKey);
await scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
);
const refreshedToken = {
...mocks.makeIdentityV2(),
advertising_token: 'refreshed_token',
};
jest.setSystemTime(refreshFrom);
jest.runOnlyPendingTimers();
xhrMock.sendIdentityInEncodedResponse(refreshedToken, cstgToken.refresh_response_key);
expect(await uid2!.getAdvertisingTokenAsync()).toBe(refreshedToken.advertising_token);
expect(await uid2OrEuid!.getAdvertisingTokenAsync()).toBe(
refreshedToken.advertising_token
);
});
});

Expand All @@ -152,16 +232,20 @@ describe('Client-side token generation Tests', () => {
});
});
test('should not set identity', async () => {
await expect(scenario.setIdentity(serverPublicKey)).rejects.toEqual(
'Client error: Here is a client error'
);
expect(mocks.getUid2()).toBeNull();
await expect(
scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
)
).rejects.toEqual('Client error: Here is a client error');
expect(scenario.getIdentity()).toBeNull();
});
test('should be in unavailable state', async () => {
await expect(scenario.setIdentity(serverPublicKey)).rejects.toEqual(
'Client error: Here is a client error'
);
(expect(uid2) as any).toBeInUnavailableState();
await expect(
scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
)
).rejects.toEqual('Client error: Here is a client error');
(expect(uid2OrEuid) as any).toBeInUnavailableState();
});
});

Expand All @@ -178,28 +262,34 @@ describe('Client-side token generation Tests', () => {
);
});
});
test('UID2 should be in optout state', async () => {
await scenario.setIdentity(serverPublicKey);
(expect(uid2) as any).toBeInOptoutState();
test('UID2 or EUID should be in optout state', async () => {
await scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
);
(expect(uid2OrEuid) as any).toBeInOptoutState();
});

test('The callback should be called with no identity', (done) => {
uid2.callbacks.push((eventType, payload) => {
uid2OrEuid.callbacks.push((eventType, payload) => {
if (eventType === EventType.IdentityUpdated) {
expect(payload.identity).toBeNull();
done();
}
});
scenario.setIdentity(serverPublicKey);
scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
);
});

test('The callback should be called with an optout event', (done) => {
uid2.callbacks.push((eventType, payload) => {
uid2OrEuid.callbacks.push((eventType, payload) => {
if (eventType === EventType.OptoutReceived) {
done();
}
});
scenario.setIdentity(serverPublicKey);
scenario.setIdentity(
scenario.identityType === 'uid2' ? serverPublicKeyUid2 : serverPublicKeyEuid
);
});
});
});
Expand Down
Loading