onesignal-web-sdk
Version:
Web push notifications from OneSignal.
949 lines (842 loc) • 33.5 kB
text/typescript
import "../../support/polyfills/polyfills";
import test, { TestContext, Context } from "ava";
import sinon, { SinonSandbox, SinonStub } from 'sinon';
import nock from "nock";
import {
TestEnvironment, HttpHttpsEnvironment, TestEnvironmentConfig
} from '../../support/sdk/TestEnvironment';
import { ConfigIntegrationKind, ServerAppConfig } from '../../../src/models/AppConfig';
import Random from "../../support/tester/Random";
import OneSignalApiBase from "../../../src/OneSignalApiBase";
import OneSignalApiShared from "../../../src/OneSignalApiShared";
import {
stubMessageChannel, mockIframeMessaging, mockWebPushAnalytics, InitTestHelper
} from '../../support/tester/utils';
import Popover from "../../../src/popover/Popover";
import OneSignalEvent from "../../../src/Event";
import { DynamicResourceLoader, ResourceLoadState } from "../../../src/services/DynamicResourceLoader";
import { ServiceWorkerManager } from "../../../src/managers/ServiceWorkerManager";
import { NotificationPermission } from "../../../src/models/NotificationPermission";
import Database from "../../../src/services/Database";
import { Subscription } from "../../../src/models/Subscription";
import { SessionManager } from "../../../src/managers/SessionManager";
import { SubscriptionManager } from "../../../src/managers/SubscriptionManager";
import InitHelper from "../../../src/helpers/InitHelper";
import ServiceWorkerRegistration from '../../support/mocks/service-workers/models/ServiceWorkerRegistration';
import { ServiceWorkerActiveState } from '../../../src/helpers/ServiceWorkerHelper';
import { WorkerMessenger } from '../../../src/libraries/WorkerMessenger';
import { UpdateManager } from '../../../src/managers/UpdateManager';
import PermissionManager from '../../../src/managers/PermissionManager';
const sinonSandbox: SinonSandbox = sinon.sandbox.create();
const initTestHelper = new InitTestHelper(sinonSandbox);
const playerId = Random.getRandomUuid();
const appId = Random.getRandomUuid();
test.beforeEach(function () {
mockWebPushAnalytics();
});
test.afterEach(function (_t: TestContext) {
sinonSandbox.restore();
OneSignal._initCalled = false;
OneSignal.__initAlreadyCalled = false;
OneSignal._sessionInitAlreadyRunning = false;
});
/**
* HTTP/HTTPS
* 1. user not subscribed and not opted out
* 1. first page view
* + 1. autoPrompt -> click allow -> player create
* + 2. autoPrompt -> click dismiss -> no requests
* + 3. autoResubscribe and permissions granted -> player create
* + 4. autoResubscribe and permissions default or blocked -> no requests
* + 5. no autoResubscribe and no autoPrompt -> no requests
* 2. second page view - TODO
* 2. user opted out
* + 1. new on session flag enabled and first page view -> on session
* + 2. no flag and first page view -> no requests
* + 3. second page view -> no requests
* 3. user subscribed
* + 1. expiring subscription -> player update
* + 2. not-expiring subscription and first page view -> on session
* 3. second page view -> no requests - TODO
*/
test.serial(`HTTPS: User not subscribed and not opted out => first page view => slidedown's autoPrompt is on =>
click allow => sends player create`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
pushIdentifier: 'granted'
};
const stubs = await beforeTest(testConfig, t);
simulateSlidedownAllowAfterShown();
simulateNativeAllowAfterShown();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const subscriptionPromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SUBSCRIPTION_CHANGED, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 1);
inspectPushRecordCreationRequest(t, stubs.createPlayerPostStub);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
},
autoResubscribe: false,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
await subscriptionPromise;
});
test.serial(`HTTPS: User not subscribed and not opted out => first page view => slidedown's autoPrompt is on =>
click dismiss => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
pushIdentifier: 'granted'
};
const stubs = await beforeTest(testConfig, t);
simulateSlidedownDismissAfterShown();
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
},
autoResubscribe: false,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTPS: User not subscribed and not opted out => first page view => autoResubscribe is on =>
permissions already granted => sends player create`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
};
const stubs = await beforeTest(testConfig, t);
stubServiceWorkerInstallation();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 1);
inspectPushRecordCreationRequest(t, stubs.createPlayerPostStub);
resolve();
});
});
const registrationPromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.REGISTERED, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 1);
resolve();
});
});
const subscriptionPromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SUBSCRIPTION_CHANGED, () => {
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
await registrationPromise;
await subscriptionPromise;
});
test.serial(`HTTPS: User not subscribed and not opted out => first page view => autoResubscribe is on =>
permissions default => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Default,
};
const stubs = await beforeTest(testConfig, t);
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
OneSignal.on(OneSignal.EVENTS.SUBSCRIPTION_CHANGED, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTPS: User not subscribed and not opted out => first page view => no autoResubscribe and no autoPrompt =>
no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
pushIdentifier: 'granted',
permission: NotificationPermission.Granted,
};
const stubs = await beforeTest(testConfig, t);
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: false,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTPS: User opted out => first page view => onSession flag is on => sends on session`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const serverAppConfig = TestEnvironment.getFakeServerAppConfig(testConfig.integration!);
serverAppConfig.features.enable_on_session = true;
const stubs = await beforeTest(testConfig, t, serverAppConfig);
await markUserAsOptedOut();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 1);
inspectOnSessionRequest(t, stubs.onSessionStub);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
});
test.serial(`HTTPS: User opted out => first page view => onSession flag is off => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const serverAppConfig = TestEnvironment.getFakeServerAppConfig(testConfig.integration!);
serverAppConfig.features.enable_on_session = false;
const stubs = await beforeTest(testConfig, t, serverAppConfig);
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
await markUserAsOptedOut();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTPS: User opted out => second page view => onSession flag is on => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const serverAppConfig = TestEnvironment.getFakeServerAppConfig(testConfig.integration!);
serverAppConfig.features.enable_on_session = true;
const stubs = await beforeTest(testConfig, t, serverAppConfig);
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
await markUserAsOptedOut();
sinonSandbox.stub(SessionManager.prototype, "getPageViewCount").resolves(2);
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTPS: User subscribed => first page view => expiring subscription => sends player update`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const stubs = await beforeTest(testConfig, t);
// Using spy instead of stub here is intended. Spy does callThrough, i.e. executes underlying function, by default
// while stub prevents the actual execution.
// Workaround with stubs would be `sinon.stub(object, "method", object.method);`
const playerUpdateStub = sinonSandbox.spy(UpdateManager.prototype, "sendPlayerUpdate");
await markUserAsSubscribed(true);
stubServiceWorkerInstallation();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
// sends player update which actually calls on_session if this is the first call we're performing.
t.is(playerUpdateStub.callCount, 1);
t.is(stubs.onSessionStub.callCount, 1);
inspectOnSessionRequest(t, stubs.onSessionStub);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
});
test.serial(`HTTPS: User subscribed => first page view => sends on session`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const stubs = await beforeTest(testConfig, t);
await markUserAsSubscribed();
stubServiceWorkerInstallation();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 1);
inspectOnSessionRequest(t, stubs.onSessionStub);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
});
test.serial(`HTTP: User not subscribed and not opted out => first page view => slidedown's autoPrompt is on =>
click allow => sends player create`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Https,
integration: ConfigIntegrationKind.Custom,
pushIdentifier: 'granted'
};
const stubs = await beforeTest(testConfig, t);
simulateSlidedownAllowAfterShown();
simulateNativeAllowAfterShown();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const subscriptionPromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SUBSCRIPTION_CHANGED, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 1);
inspectPushRecordCreationRequest(t, stubs.createPlayerPostStub);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
},
autoResubscribe: false,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
await subscriptionPromise;
});
test.serial(`HTTP: User not subscribed and not opted out => first page view => slidedown's autoPrompt is on =>
click dismiss => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
pushIdentifier: 'granted'
};
const stubs = await beforeTest(testConfig, t);
simulateSlidedownDismissAfterShown();
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
},
autoResubscribe: false,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
// autoResubscribe works only on https
test.serial(`HTTP: User not subscribed and not opted out => first page view => autoResubscribe is on =>
permissions already granted => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
};
const stubs = await beforeTest(testConfig, t);
stubServiceWorkerInstallation();
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTP: User not subscribed and not opted out => first page view => autoResubscribe is on =>
permissions default => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Default,
};
const stubs = await beforeTest(testConfig, t);
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
OneSignal.on(OneSignal.EVENTS.SUBSCRIPTION_CHANGED, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTP: User not subscribed and not opted out => first page view => no autoResubscribe and no autoPrompt =>
no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
pushIdentifier: 'granted',
permission: NotificationPermission.Granted,
};
const stubs = await beforeTest(testConfig, t);
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: false,
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTP: User opted out => first page view => onSession flag is on => sends on session`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const serverAppConfig = TestEnvironment.getFakeServerAppConfig(testConfig.integration!, false);
serverAppConfig.features.enable_on_session = true;
const stubs = await beforeTest(testConfig, t, serverAppConfig);
await markUserAsOptedOut();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 1);
inspectOnSessionRequest(t, stubs.onSessionStub);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
});
test.serial(`HTTP: User opted out => first page view => onSession flag is off => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const serverAppConfig = TestEnvironment.getFakeServerAppConfig(testConfig.integration!, false);
serverAppConfig.features.enable_on_session = false;
const stubs = await beforeTest(testConfig, t, serverAppConfig);
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
await markUserAsOptedOut();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTP: User opted out => second page view => onSession flag is on => no requests`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const serverAppConfig = TestEnvironment.getFakeServerAppConfig(testConfig.integration!, false);
serverAppConfig.features.enable_on_session = true;
const stubs = await beforeTest(testConfig, t, serverAppConfig);
const subscribeSpy = sinonSandbox.spy(SubscriptionManager.prototype, "subscribe");
await markUserAsOptedOut();
sinonSandbox.stub(SessionManager.prototype, "getPageViewCount").resolves(2);
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
await initializePromise;
t.is(subscribeSpy.callCount, 0);
});
test.serial(`HTTP: User subscribed => first page view => expiring subscription => sends player update`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const stubs = await beforeTest(testConfig, t);
const registerStub = sinonSandbox.stub(InitHelper, "registerSubscriptionInProxyFrame").resolves(createSubscription());
await markUserAsSubscribedOnHttp(true);
stubServiceWorkerInstallation();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
// t.is(registerStub.callCount, 1);
t.is(stubs.onSessionStub.callCount, 0);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
});
test.serial(`HTTP: User subscribed => first page view => sends on session`, async t => {
const testConfig: TestEnvironmentConfig = {
httpOrHttps: HttpHttpsEnvironment.Http,
integration: ConfigIntegrationKind.Custom,
permission: NotificationPermission.Granted,
pushIdentifier: 'granted'
};
const stubs = await beforeTest(testConfig, t);
await markUserAsSubscribedOnHttp();
stubServiceWorkerInstallation();
const initializePromise = new Promise((resolve) => {
OneSignal.on(OneSignal.EVENTS.SDK_INITIALIZED_PUBLIC, () => {
t.is(stubs.onSessionStub.callCount, 1);
inspectOnSessionRequest(t, stubs.onSessionStub);
t.is(stubs.createPlayerPostStub.callCount, 0);
resolve();
});
});
const initPromise = OneSignal.init({
appId,
autoResubscribe: true,
promptOptions: {
slidedown: {
enabled: true,
autoPrompt: true,
}
}
});
await initPromise;
t.is(OneSignal.context.sessionManager.getPageViewCount(), 1);
await initializePromise;
});
/** Helper methods */
async function beforeTest(
testConfig: TestEnvironmentConfig,
t: TestContext & Context<any>,
customServerAppConfig?: ServerAppConfig
) {
await TestEnvironment.initialize(testConfig);
initTestHelper.mockBasicInitEnv(testConfig, customServerAppConfig);
OneSignal.initialized = false;
OneSignal.__doNotShowWelcomeNotification = true;
(window as any).Notification.permission = testConfig.permission || "default";
const createPlayerPostStub = sinonSandbox.stub(OneSignalApiBase, "post")
.resolves({success: true, id: playerId});
const onSessionStub = sinonSandbox.stub(OneSignalApiShared, "updateUserSession")
.resolves({success: true, id: playerId});
sinonSandbox.stub(DynamicResourceLoader.prototype, "loadSdkStylesheet").resolves(ResourceLoadState.Loaded);
sinonSandbox.stub(ServiceWorkerManager.prototype, "installWorker").resolves();
nock('https://onesignal.com')
.get(/.*icon$/)
.reply(200, (_uri: string, _requestBody: string) => {
return { success: true };
});
if (testConfig.httpOrHttps === HttpHttpsEnvironment.Http) {
stubMessageChannel(t);
mockIframeMessaging(sinonSandbox);
}
return { createPlayerPostStub, onSessionStub };
}
function simulateSlidedownAllowAfterShown() {
OneSignal.on(Popover.EVENTS.SHOWN, () => {
OneSignalEvent.trigger(Popover.EVENTS.ALLOW_CLICK);
});
}
function simulateSlidedownDismissAfterShown() {
OneSignal.on(Popover.EVENTS.SHOWN, () => {
OneSignalEvent.trigger(Popover.EVENTS.CANCEL_CLICK);
});
}
function simulateNativeAllowAfterShown() {
OneSignal.emitter.on(OneSignal.EVENTS.PERMISSION_PROMPT_DISPLAYED, () => {
sinonSandbox.stub(SubscriptionManager.prototype, "getSubscriptionState")
.resolves({subscribed: true, isOptedOut: false});
stubServiceWorkerInstallation();
});
}
async function markUserAsOptedOut() {
const subscription = new Subscription();
subscription.deviceId = playerId;
subscription.optedOut = true;
subscription.subscriptionToken = "some_token";
subscription.createdAt = Date.now();
await Database.setSubscription(subscription);
}
async function markUserAsSubscribed(expired?: boolean) {
const subscription = createSubscription();
await Database.setSubscription(subscription);
sinonSandbox.stub(SubscriptionManager.prototype, "getSubscriptionState")
.resolves({subscribed: true, isOptedOut: false});
if (expired) {
sinonSandbox.stub(InitHelper, "processExpiringSubscriptions").resolves(true);
}
}
async function markUserAsSubscribedOnHttp(expired?: boolean) {
markUserAsSubscribed(expired);
sinonSandbox.stub(PermissionManager.prototype, "getOneSignalSubdomainNotificationPermission")
.resolves(NotificationPermission.Granted);
}
function stubServiceWorkerInstallation() {
const swRegistration = new ServiceWorkerRegistration();
sinonSandbox.stub(SubscriptionManager.prototype, "subscribeWithVapidKey")
.resolves(TestEnvironment.getFakeRawPushSubscription());
sinonSandbox.stub((global as any).navigator.serviceWorker, 'ready')
.get(() => new Promise((resolve) => { resolve(swRegistration); }));
sinonSandbox.stub(ServiceWorkerManager.prototype, "getActiveState")
.resolves(ServiceWorkerActiveState.WorkerA);
sinonSandbox.stub(ServiceWorkerManager, "getRegistration")
.resolves(swRegistration);
sinonSandbox.stub(WorkerMessenger.prototype, "unicast").resolves();
}
function createSubscription(): Subscription {
const subscription = new Subscription();
subscription.deviceId = playerId;
subscription.optedOut = false;
subscription.subscriptionToken = "some_token";
subscription.createdAt = new Date(2017, 11, 13, 2, 3, 4, 0).getTime();
return subscription;
}
async function inspectPushRecordCreationRequest(t: TestContext, requestStub: SinonStub) {
// For player#create device record is already serialized. Checking serialized structure.
const anyValues = [
"device_type",
"language",
"timezone",
"device_os",
"sdk",
"device_model",
"identifier",
"notification_types"
];
t.is(requestStub.callCount, 1);
t.not(requestStub.getCall(0), null);
const data: any = requestStub.getCall(0).args[1];
anyValues.forEach(valueKey => {
t.not(data[valueKey], undefined, `player create: ${valueKey} is undefined! => data: ${JSON.stringify(data)}`);
});
}
async function inspectOnSessionRequest(t: TestContext, requestStub: SinonStub) {
// Device record is serialized inside of `updateUserSession`. Checking original DeviceRecord properties.
const anyValues = [
"deliveryPlatform",
"language",
"timezone",
"browserVersion",
"sdkVersion",
"subscriptionState",
"deviceModel",
];
t.is(requestStub.callCount, 1);
t.not(requestStub.getCall(0), null);
const data: any = requestStub.getCall(0).args[1];
anyValues.forEach(valueKey => {
t.not(data[valueKey], undefined, `on_session: ${valueKey} is undefined! => data: ${JSON.stringify(data)}`);
});
}