onesignal-web-sdk
Version:
Web push notifications from OneSignal.
405 lines (369 loc) • 13.6 kB
text/typescript
import "../../support/polyfills/polyfills";
import test, { TestContext, Context } from "ava";
import Database from "../../../src/services/Database";
import {TestEnvironment, BrowserUserAgent} from "../../support/sdk/TestEnvironment";
import OneSignal from "../../../src/OneSignal";
import { InvalidArgumentError } from '../../../src/errors/InvalidArgumentError';
import nock from 'nock';
import Random from "../../support/tester/Random";
import { setUserAgent } from "../../support/tester/browser";
test.beforeEach(async _t => {
await TestEnvironment.initialize();
TestEnvironment.mockInternalOneSignal();
await Database.put('Ids', { type: 'appId', id: OneSignal.context.appConfig.appId });
})
test("setEmail should reject an empty or invalid emails", async t => {
try {
await OneSignal.setEmail(undefined as any);
t.fail('expected exception not caught');
} catch (e) {
t.truthy(e instanceof InvalidArgumentError);
}
try {
await OneSignal.setEmail(null as any);
t.fail('expected exception not caught');
} catch (e) {
t.truthy(e instanceof InvalidArgumentError);
}
try {
await OneSignal.setEmail(null as any);
t.fail('expected exception not caught');
} catch (e) {
t.truthy(e instanceof InvalidArgumentError);
}
try {
await OneSignal.setEmail("test@@example.com");
t.fail('expected exception not caught');
} catch (e) {
t.truthy(e instanceof InvalidArgumentError);
}
});
test("setEmail should not accept an email auth SHA-256 hex hash not 64 characters long", async t => {
try {
await OneSignal.setEmail("test@example.com", {
emailAuthHash: "12345"
});
t.fail('expected exception not caught');
} catch (e) {
t.truthy(e instanceof InvalidArgumentError);
}
});
/*
* Test Case | Description
* -----------------------
* No push subscription, no email, first setEmail call
* No push subscription, existing identical email, refreshing setEmail call
* No push subscription, existing different email, updating email
* Existing push subscription, no email, first setEmail call
* Existing push subscription, existing identical email, refreshing setEmail call
* Existing push subscription, existing different email, updating email
*
* ---
*
* ..., existing email (identical or not), emailAuthHash --> makes a PUT call instead of POST
*/
async function expectEmailRecordCreationRequest(
t: TestContext & Context<any>,
emailAddress: string,
pushDevicePlayerId: string | null,
emailAuthHash: string | undefined | null,
newCreatedEmailId: string
) {
nock('https://onesignal.com')
.post(`/api/v1/players`)
.reply(200, (_uri: string, requestBody: any) => {
const sameValues: {[key: string]: string | undefined } = {
app_id: OneSignal.context.appConfig.appId,
identifier: emailAddress,
device_player_id: pushDevicePlayerId ? pushDevicePlayerId : undefined,
email_auth_hash: emailAuthHash ? emailAuthHash : undefined
};
const anyValues = [
"device_type",
"language",
"timezone",
"device_os",
"sdk",
"device_model"
];
const parsedRequestBody = JSON.parse(requestBody);
for (const sameValueKey of Object.keys(sameValues)) {
t.deepEqual(parsedRequestBody[sameValueKey], sameValues[sameValueKey]);
}
for (const anyValueKey of anyValues) {
t.not(parsedRequestBody[anyValueKey], undefined);
}
return { "success":true, "id": newCreatedEmailId };
});
}
async function expectEmailRecordUpdateRequest(
t: TestContext & Context<any>,
emailId: string | null,
emailAddress: string,
pushDevicePlayerId: string | null,
emailAuthHash: string | undefined,
newUpdatedEmailId: string
) {
nock('https://onesignal.com')
.put(`/api/v1/players/${emailId}`)
.reply(200, (_uri: string, requestBody: any) => {
const sameValues: {[key: string]: string | undefined } = {
app_id: OneSignal.context.appConfig.appId,
identifier: emailAddress,
device_player_id: pushDevicePlayerId ? pushDevicePlayerId : undefined,
email_auth_hash: emailAuthHash ? emailAuthHash : undefined
};
const anyValues = [
"device_type",
"language",
"timezone",
"device_os",
"sdk",
"device_model"
];
const parsedRequestBody = JSON.parse(requestBody);
for (const sameValueKey of Object.keys(sameValues)) {
t.deepEqual(parsedRequestBody[sameValueKey], sameValues[sameValueKey]);
}
for (const anyValueKey of anyValues) {
t.not(parsedRequestBody[anyValueKey], undefined);
}
return { "success":true, "id": newUpdatedEmailId };
});
}
async function expectPushRecordUpdateRequest(
t: TestContext & Context<any>,
pushDevicePlayerId: string,
newEmailId: string,
emailAddress: string,
newUpdatedPlayerId: string
) {
nock('https://onesignal.com')
.put(`/api/v1/players/${pushDevicePlayerId}`)
.reply(200, (_uri: string, requestBody: any) => {
t.deepEqual(
requestBody,
JSON.stringify({
app_id: OneSignal.context.appConfig.appId,
parent_player_id: newEmailId ? newEmailId : undefined,
email: emailAddress,
})
);
return { "success":true, "id": newUpdatedPlayerId };
});
}
interface SetEmailTestData {
existingEmailAddress: string | null;
newEmailAddress: string; /* Email address used for setEmail */
existingPushDeviceId: string | null;
emailAuthHash: string | undefined;
existingEmailId: string | null;
requireEmailAuth: boolean;
newEmailId: string; /* Returned by the create or update email record call */
}
async function setEmailTest(
t: TestContext & Context<any>,
testData: SetEmailTestData
) {
setUserAgent(BrowserUserAgent.FirefoxMacSupported);
if (testData.existingEmailAddress) {
const emailProfile = await Database.getEmailProfile();
emailProfile.emailAddress = testData.existingEmailAddress;
await Database.setEmailProfile(emailProfile);
}
/* If an existing push device ID is set, create a fake one here */
if (testData.existingPushDeviceId) {
const subscription = await Database.getSubscription();
subscription.deviceId = testData.existingPushDeviceId;
await Database.setSubscription(subscription);
}
if (testData.requireEmailAuth) {
const appConfig = await Database.getAppConfig();
appConfig.emailAuthRequired = true;
await Database.setAppConfig(appConfig);
}
/* If test data has an email auth hash, fake the config parameter */
if (testData.emailAuthHash) {
const emailProfile = await Database.getEmailProfile();
emailProfile.emailAuthHash = testData.emailAuthHash;
await Database.setEmailProfile(emailProfile);
}
if (testData.existingEmailId) {
const emailProfile = await Database.getEmailProfile();
emailProfile.emailId = testData.existingEmailId;
await Database.setEmailProfile(emailProfile);
}
// Mock the one or two requests we expect to occur
const isUpdateRequest = testData.emailAuthHash && testData.existingEmailId;
if (isUpdateRequest) {
// Means we're making a PUT call to /players/<id>
expectEmailRecordUpdateRequest(
t,
testData.existingEmailId,
testData.newEmailAddress,
testData.existingPushDeviceId,
testData.emailAuthHash,
testData.newEmailId
);
} else {
// Means we're making a POST call to /players
expectEmailRecordCreationRequest(
t,
testData.newEmailAddress,
testData.existingPushDeviceId,
testData.emailAuthHash,
testData.newEmailId
);
}
if (
testData.existingPushDeviceId &&
!(
testData.existingEmailId === testData.newEmailId &&
testData.existingEmailAddress === testData.newEmailAddress
)
) {
/*
Expect a second call to be made if:
- We're subscribed to web push (existing player ID)
- The email ID or plain text email address changes from what we have saved, or if neither was ever saved
*/
expectPushRecordUpdateRequest(
t,
testData.existingPushDeviceId,
testData.newEmailId,
testData.newEmailAddress,
Random.getRandomUuid(),
);
}
await OneSignal.setEmail(
testData.newEmailAddress,
testData.emailAuthHash ?
{ emailAuthHash: testData.emailAuthHash } :
undefined
);
const { deviceId: finalPushDeviceId } = await Database.getSubscription();
const finalEmailProfile = await Database.getEmailProfile();
t.deepEqual(finalPushDeviceId, testData.existingPushDeviceId ? testData.existingPushDeviceId : null);
t.deepEqual(finalEmailProfile.emailAddress, testData.newEmailAddress);
t.deepEqual(finalEmailProfile.emailAuthHash, testData.emailAuthHash);
t.deepEqual(finalEmailProfile.emailId, testData.newEmailId);
}
test("No push subscription, no email, first setEmail call", async t => {
const testData: SetEmailTestData = {
existingEmailAddress: null,
newEmailAddress: "test@example.com",
existingPushDeviceId: null,
emailAuthHash: undefined,
existingEmailId: null,
requireEmailAuth: false,
newEmailId: Random.getRandomUuid()
};
await setEmailTest(t, testData);
});
test("No push subscription, no email, first setEmail call, test email id return", async t => {
const fakeUuid = Random.getRandomUuid();
expectEmailRecordCreationRequest(
t,
"example@domain.com",
null,
null,
fakeUuid
);
setUserAgent(BrowserUserAgent.FirefoxMacSupported);
t.is(await OneSignal.setEmail("example@domain.com"), fakeUuid);
});
test("No push subscription, existing identical email, refreshing setEmail call", async t => {
const emailId = Random.getRandomUuid();
const testData: SetEmailTestData = {
existingEmailAddress: "test@example.com",
newEmailAddress: "test@example.com",
existingPushDeviceId: null,
emailAuthHash: undefined,
existingEmailId: emailId,
requireEmailAuth: false,
newEmailId: emailId
};
await setEmailTest(t, testData);
});
test("No push subscription, existing different email, updating setEmail call", async t => {
const testData: SetEmailTestData = {
existingEmailAddress: "existing-different-email-address@example.com",
newEmailAddress: "test@example.com",
existingPushDeviceId: null,
emailAuthHash: undefined,
existingEmailId: Random.getRandomUuid(),
requireEmailAuth: false,
newEmailId: Random.getRandomUuid()
};
await setEmailTest(t, testData);
});
test("Existing push subscription, no email, first setEmail call", async t => {
const testData: SetEmailTestData = {
existingEmailAddress: null,
newEmailAddress: "test@example.com",
existingPushDeviceId: Random.getRandomUuid(),
emailAuthHash: undefined,
existingEmailId: null,
requireEmailAuth: false,
newEmailId: Random.getRandomUuid()
};
await setEmailTest(t, testData);
});
test("Existing push subscription, existing identical email, refreshing setEmail call", async t => {
const emailId = Random.getRandomUuid();
const testData: SetEmailTestData = {
existingEmailAddress: "test@example.com",
newEmailAddress: "test@example.com",
existingPushDeviceId: Random.getRandomUuid(),
emailAuthHash: undefined,
existingEmailId: emailId,
requireEmailAuth: false,
newEmailId: emailId
};
await setEmailTest(t, testData);
});
test("Existing push subscription, existing different email, updating setEmail call", async t => {
const testData: SetEmailTestData = {
existingEmailAddress: "existing-different-email@example.com",
newEmailAddress: "test@example.com",
existingPushDeviceId: Random.getRandomUuid(),
emailAuthHash: undefined,
existingEmailId: Random.getRandomUuid(),
requireEmailAuth: false,
newEmailId: Random.getRandomUuid(),
};
await setEmailTest(t, testData);
});
test(
"Existing push subscription, existing identical email, with emailAuthHash, refreshing setEmail call",
async t => {
const testData: SetEmailTestData = {
existingEmailAddress: "existing-different-email@example.com",
newEmailAddress: "test@example.com",
existingPushDeviceId: Random.getRandomUuid(),
emailAuthHash: "432B5BE752724550952437FAED4C8E2798E9D0AF7AACEFE73DEA923A14B94799",
existingEmailId: Random.getRandomUuid(),
requireEmailAuth: true,
newEmailId: Random.getRandomUuid(),
};
await setEmailTest(t, testData);
});
test(
"require email auth without emailAuthHash setEmail call",
async t => {
const testData: SetEmailTestData = {
existingEmailAddress: "existing-different-email@example.com",
newEmailAddress: "test@example.com",
existingPushDeviceId: Random.getRandomUuid(),
emailAuthHash: undefined,
existingEmailId: Random.getRandomUuid(),
requireEmailAuth: true,
newEmailId: Random.getRandomUuid(),
};
try {
await OneSignal.setEmail(null as any);
t.fail('expected exception not caught');
} catch (e) {
t.truthy(e instanceof InvalidArgumentError);
}
});