2017-09-28 19:18:12 -04:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
2018-05-09 11:11:43 -04:00
|
|
|
import {PLATFORM_ID} from '@angular/core';
|
2017-10-16 06:08:41 -04:00
|
|
|
import {TestBed} from '@angular/core/testing';
|
2017-09-28 19:18:12 -04:00
|
|
|
|
|
|
|
import {NgswCommChannel} from '../src/low_level';
|
2018-05-09 11:11:43 -04:00
|
|
|
import {RegistrationOptions, ngswCommChannelFactory} from '../src/module';
|
2017-09-28 19:18:12 -04:00
|
|
|
import {SwPush} from '../src/push';
|
|
|
|
import {SwUpdate} from '../src/update';
|
|
|
|
import {MockServiceWorkerContainer, MockServiceWorkerRegistration} from '../testing/mock';
|
|
|
|
|
2017-12-16 17:42:55 -05:00
|
|
|
{
|
2017-09-28 19:18:12 -04:00
|
|
|
describe('ServiceWorker library', () => {
|
|
|
|
let mock: MockServiceWorkerContainer;
|
|
|
|
let comm: NgswCommChannel;
|
|
|
|
beforeEach(() => {
|
|
|
|
mock = new MockServiceWorkerContainer();
|
2018-05-09 11:11:43 -04:00
|
|
|
comm = new NgswCommChannel(mock as any);
|
2017-09-28 19:18:12 -04:00
|
|
|
});
|
|
|
|
describe('NgswCommsChannel', () => {
|
|
|
|
it('can access the registration when it comes before subscription', (done: DoneFn) => {
|
|
|
|
const mock = new MockServiceWorkerContainer();
|
2018-05-09 11:11:43 -04:00
|
|
|
const comm = new NgswCommChannel(mock as any);
|
2017-09-28 19:18:12 -04:00
|
|
|
const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration;
|
|
|
|
|
|
|
|
mock.setupSw();
|
|
|
|
|
2017-12-17 18:10:54 -05:00
|
|
|
(comm as any).registration.subscribe((reg: any) => { done(); });
|
2017-09-28 19:18:12 -04:00
|
|
|
});
|
|
|
|
it('can access the registration when it comes after subscription', (done: DoneFn) => {
|
|
|
|
const mock = new MockServiceWorkerContainer();
|
2018-05-09 11:11:43 -04:00
|
|
|
const comm = new NgswCommChannel(mock as any);
|
2017-09-28 19:18:12 -04:00
|
|
|
const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration;
|
|
|
|
|
2017-12-17 18:10:54 -05:00
|
|
|
(comm as any).registration.subscribe((reg: any) => { done(); });
|
2017-09-28 19:18:12 -04:00
|
|
|
|
|
|
|
mock.setupSw();
|
|
|
|
});
|
2018-05-09 11:11:43 -04:00
|
|
|
});
|
|
|
|
describe('ngswCommChannelFactory', () => {
|
|
|
|
it('gives disabled NgswCommChannel for platform-server', () => {
|
|
|
|
TestBed.configureTestingModule({
|
|
|
|
providers: [
|
|
|
|
{provide: PLATFORM_ID, useValue: 'server'},
|
|
|
|
{provide: RegistrationOptions, useValue: {enabled: true}}, {
|
|
|
|
provide: NgswCommChannel,
|
|
|
|
useFactory: ngswCommChannelFactory,
|
|
|
|
deps: [RegistrationOptions, PLATFORM_ID]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(TestBed.get(NgswCommChannel).isEnabled).toEqual(false);
|
2017-11-11 18:39:27 -05:00
|
|
|
});
|
2018-05-09 11:11:43 -04:00
|
|
|
it('gives disabled NgswCommChannel when \'enabled\' option is false', () => {
|
|
|
|
TestBed.configureTestingModule({
|
|
|
|
providers: [
|
|
|
|
{provide: PLATFORM_ID, useValue: 'browser'},
|
|
|
|
{provide: RegistrationOptions, useValue: {enabled: false}}, {
|
|
|
|
provide: NgswCommChannel,
|
|
|
|
useFactory: ngswCommChannelFactory,
|
|
|
|
deps: [RegistrationOptions, PLATFORM_ID]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(TestBed.get(NgswCommChannel).isEnabled).toEqual(false);
|
|
|
|
});
|
|
|
|
it('gives disabled NgswCommChannel when navigator.serviceWorker is undefined', () => {
|
|
|
|
TestBed.configureTestingModule({
|
|
|
|
providers: [
|
|
|
|
{provide: PLATFORM_ID, useValue: 'browser'},
|
|
|
|
{provide: RegistrationOptions, useValue: {enabled: true}},
|
|
|
|
{
|
|
|
|
provide: NgswCommChannel,
|
|
|
|
useFactory: ngswCommChannelFactory,
|
|
|
|
deps: [RegistrationOptions, PLATFORM_ID],
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|
|
|
|
|
|
|
|
const context: any = global || window;
|
|
|
|
const originalDescriptor = Object.getOwnPropertyDescriptor(context, 'navigator');
|
|
|
|
const patchedDescriptor = {value: {serviceWorker: undefined}, configurable: true};
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Set `navigator` to `{serviceWorker: undefined}`.
|
|
|
|
Object.defineProperty(context, 'navigator', patchedDescriptor);
|
|
|
|
expect(TestBed.get(NgswCommChannel).isEnabled).toBe(false);
|
|
|
|
} finally {
|
|
|
|
if (originalDescriptor) {
|
|
|
|
Object.defineProperty(context, 'navigator', originalDescriptor);
|
|
|
|
} else {
|
|
|
|
delete context.navigator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
it('gives enabled NgswCommChannel when browser supports SW and enabled option is true',
|
|
|
|
() => {
|
|
|
|
TestBed.configureTestingModule({
|
|
|
|
providers: [
|
|
|
|
{provide: PLATFORM_ID, useValue: 'browser'},
|
|
|
|
{provide: RegistrationOptions, useValue: {enabled: true}}, {
|
|
|
|
provide: NgswCommChannel,
|
|
|
|
useFactory: ngswCommChannelFactory,
|
|
|
|
deps: [RegistrationOptions, PLATFORM_ID]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
});
|
|
|
|
|
|
|
|
const context: any = global || window;
|
|
|
|
const originalDescriptor = Object.getOwnPropertyDescriptor(context, 'navigator');
|
|
|
|
const patchedDescriptor = {value: {serviceWorker: mock}, configurable: true};
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Set `navigator` to `{serviceWorker: mock}`.
|
|
|
|
Object.defineProperty(context, 'navigator', patchedDescriptor);
|
|
|
|
expect(TestBed.get(NgswCommChannel).isEnabled).toBe(true);
|
|
|
|
} finally {
|
|
|
|
if (originalDescriptor) {
|
|
|
|
Object.defineProperty(context, 'navigator', originalDescriptor);
|
|
|
|
} else {
|
|
|
|
delete context.navigator;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2017-09-28 19:18:12 -04:00
|
|
|
});
|
2017-10-16 06:08:41 -04:00
|
|
|
describe('SwPush', () => {
|
2017-09-28 19:18:12 -04:00
|
|
|
let push: SwPush;
|
2017-10-26 13:29:36 -04:00
|
|
|
beforeEach(() => {
|
2017-09-28 19:18:12 -04:00
|
|
|
push = new SwPush(comm);
|
|
|
|
mock.setupSw();
|
|
|
|
});
|
|
|
|
it('receives push messages', (done: DoneFn) => {
|
|
|
|
push.messages.subscribe(msg => {
|
|
|
|
expect(msg).toEqual({
|
|
|
|
message: 'this was a push message',
|
|
|
|
});
|
|
|
|
done();
|
|
|
|
});
|
2017-10-26 13:29:36 -04:00
|
|
|
mock.sendMessage({
|
2017-09-28 19:18:12 -04:00
|
|
|
type: 'PUSH',
|
|
|
|
data: {
|
|
|
|
message: 'this was a push message',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
2017-10-16 06:08:41 -04:00
|
|
|
it('is injectable', () => {
|
|
|
|
TestBed.configureTestingModule({
|
|
|
|
providers: [
|
|
|
|
SwPush,
|
|
|
|
{provide: NgswCommChannel, useValue: comm},
|
|
|
|
]
|
|
|
|
});
|
|
|
|
expect(() => TestBed.get(SwPush)).not.toThrow();
|
|
|
|
});
|
2017-11-30 11:22:41 -05:00
|
|
|
describe('with no SW', () => {
|
2018-05-09 11:11:43 -04:00
|
|
|
beforeEach(() => { comm = new NgswCommChannel(undefined); });
|
2017-11-30 11:22:41 -05:00
|
|
|
it('can be instantiated', () => { push = new SwPush(comm); });
|
|
|
|
it('does not crash on subscription to observables', () => {
|
|
|
|
push = new SwPush(comm);
|
|
|
|
push.messages.toPromise().catch(err => fail(err));
|
|
|
|
push.subscription.toPromise().catch(err => fail(err));
|
|
|
|
});
|
|
|
|
it('gives an error when registering', done => {
|
|
|
|
push = new SwPush(comm);
|
|
|
|
push.requestSubscription({serverPublicKey: 'test'}).catch(err => { done(); });
|
|
|
|
});
|
|
|
|
it('gives an error when unsubscribing', done => {
|
|
|
|
|
|
|
|
push = new SwPush(comm);
|
|
|
|
push.unsubscribe().catch(err => { done(); });
|
|
|
|
});
|
|
|
|
});
|
2017-09-28 19:18:12 -04:00
|
|
|
});
|
2017-10-16 06:08:41 -04:00
|
|
|
describe('SwUpdate', () => {
|
2017-09-28 19:18:12 -04:00
|
|
|
let update: SwUpdate;
|
2017-10-26 13:29:36 -04:00
|
|
|
beforeEach(() => {
|
2017-09-28 19:18:12 -04:00
|
|
|
update = new SwUpdate(comm);
|
|
|
|
mock.setupSw();
|
|
|
|
});
|
|
|
|
it('processes update availability notifications when sent', (done: DoneFn) => {
|
|
|
|
update.available.subscribe(event => {
|
|
|
|
expect(event.current).toEqual({version: 'A'});
|
|
|
|
expect(event.available).toEqual({version: 'B'});
|
|
|
|
expect(event.type).toEqual('UPDATE_AVAILABLE');
|
|
|
|
done();
|
|
|
|
});
|
2017-10-26 13:29:36 -04:00
|
|
|
mock.sendMessage({
|
2017-09-28 19:18:12 -04:00
|
|
|
type: 'UPDATE_AVAILABLE',
|
|
|
|
current: {
|
|
|
|
version: 'A',
|
|
|
|
},
|
|
|
|
available: {
|
|
|
|
version: 'B',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('processes update activation notifications when sent', (done: DoneFn) => {
|
|
|
|
update.activated.subscribe(event => {
|
|
|
|
expect(event.previous).toEqual({version: 'A'});
|
|
|
|
expect(event.current).toEqual({version: 'B'});
|
|
|
|
expect(event.type).toEqual('UPDATE_ACTIVATED');
|
|
|
|
done();
|
|
|
|
});
|
2017-10-26 13:29:36 -04:00
|
|
|
mock.sendMessage({
|
2017-09-28 19:18:12 -04:00
|
|
|
type: 'UPDATE_ACTIVATED',
|
|
|
|
previous: {
|
|
|
|
version: 'A',
|
|
|
|
},
|
|
|
|
current: {
|
|
|
|
version: 'B',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('activates updates when requested', (done: DoneFn) => {
|
|
|
|
mock.messages.subscribe((msg: {action: string, statusNonce: number}) => {
|
|
|
|
expect(msg.action).toEqual('ACTIVATE_UPDATE');
|
2017-10-26 13:29:36 -04:00
|
|
|
mock.sendMessage({
|
2017-09-28 19:18:12 -04:00
|
|
|
type: 'STATUS',
|
|
|
|
nonce: msg.statusNonce,
|
|
|
|
status: true,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return update.activateUpdate().then(() => done()).catch(err => done.fail(err));
|
|
|
|
});
|
|
|
|
it('reports activation failure when requested', (done: DoneFn) => {
|
|
|
|
mock.messages.subscribe((msg: {action: string, statusNonce: number}) => {
|
|
|
|
expect(msg.action).toEqual('ACTIVATE_UPDATE');
|
2017-10-26 13:29:36 -04:00
|
|
|
mock.sendMessage({
|
2017-09-28 19:18:12 -04:00
|
|
|
type: 'STATUS',
|
|
|
|
nonce: msg.statusNonce,
|
|
|
|
status: false,
|
|
|
|
error: 'Failed to activate',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return update.activateUpdate()
|
|
|
|
.catch(err => { expect(err.message).toEqual('Failed to activate'); })
|
|
|
|
.then(() => done())
|
|
|
|
.catch(err => done.fail(err));
|
|
|
|
});
|
2017-10-16 06:08:41 -04:00
|
|
|
it('is injectable', () => {
|
|
|
|
TestBed.configureTestingModule({
|
|
|
|
providers: [
|
|
|
|
SwUpdate,
|
|
|
|
{provide: NgswCommChannel, useValue: comm},
|
|
|
|
]
|
|
|
|
});
|
|
|
|
expect(() => TestBed.get(SwUpdate)).not.toThrow();
|
|
|
|
});
|
2017-11-30 11:22:41 -05:00
|
|
|
describe('with no SW', () => {
|
2018-05-09 11:11:43 -04:00
|
|
|
beforeEach(() => { comm = new NgswCommChannel(undefined); });
|
2017-11-30 11:22:41 -05:00
|
|
|
it('can be instantiated', () => { update = new SwUpdate(comm); });
|
|
|
|
it('does not crash on subscription to observables', () => {
|
|
|
|
update = new SwUpdate(comm);
|
|
|
|
update.available.toPromise().catch(err => fail(err));
|
|
|
|
update.activated.toPromise().catch(err => fail(err));
|
|
|
|
});
|
|
|
|
it('gives an error when checking for updates', done => {
|
|
|
|
update = new SwUpdate(comm);
|
|
|
|
update.checkForUpdate().catch(err => { done(); });
|
|
|
|
});
|
|
|
|
it('gives an error when activating updates', done => {
|
|
|
|
update = new SwUpdate(comm);
|
|
|
|
update.activateUpdate().catch(err => { done(); });
|
|
|
|
});
|
|
|
|
});
|
2017-09-28 19:18:12 -04:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|