fix(aio): v2 - when browser lacks service worker, disable sw feature
This commit is contained in:
parent
c530c5d317
commit
0799f184dc
35
aio/src/app/sw-updates/noop-ng-service-worker.ts
Normal file
35
aio/src/app/sw-updates/noop-ng-service-worker.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Alternative to NgServiceWorker when the browser doesn't support NgServiceWorker
|
||||||
|
//
|
||||||
|
// Many browsers do not support ServiceWorker (e.g, Safari).
|
||||||
|
// The Angular NgServiceWorker assumes that the browser supports ServiceWorker
|
||||||
|
// and starts talking to it immediately in its constructor without checking if it exists.
|
||||||
|
// Merely injecting the `NgServiceWorker` is an exception in any browser w/o ServiceWorker.
|
||||||
|
//
|
||||||
|
// Solution: when the browser doesn't support service worker and a class injects `NgServiceWorker`
|
||||||
|
// substitute the inert `NoopNgServiceWorker`.
|
||||||
|
|
||||||
|
import { Injector } from '@angular/core';
|
||||||
|
import { NgServiceWorker } from '@angular/service-worker';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { of } from 'rxjs/observable/of';
|
||||||
|
|
||||||
|
export class NoopNgServiceWorker {
|
||||||
|
// Service worker is supported if `navigator['serviceWorker'] is defined.
|
||||||
|
isServiceWorkerSupported = !!navigator['serviceWorker'];
|
||||||
|
|
||||||
|
checkForUpdate() { return of(false); }
|
||||||
|
activateUpdate(version: string) { return of(false); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class NgServiceWorkerForReals {}
|
||||||
|
|
||||||
|
export function NgServiceWorkerFactory(injector: Injector, nsw: NoopNgServiceWorker) {
|
||||||
|
return nsw.isServiceWorkerSupported ? injector.get(NgServiceWorkerForReals) : nsw;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const noopNgServiceWorkerProviders = [
|
||||||
|
NoopNgServiceWorker,
|
||||||
|
{ provide: NgServiceWorkerForReals, useClass: NgServiceWorker },
|
||||||
|
{ provide: NgServiceWorker, useFactory: NgServiceWorkerFactory,
|
||||||
|
deps: [Injector, NoopNgServiceWorker] }];
|
@ -2,16 +2,17 @@ import { NgModule } from '@angular/core';
|
|||||||
import { MdSnackBarModule } from '@angular/material';
|
import { MdSnackBarModule } from '@angular/material';
|
||||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||||
|
|
||||||
|
import { noopNgServiceWorkerProviders } from './noop-ng-service-worker';
|
||||||
import { SwUpdateNotificationsService } from './sw-update-notifications.service';
|
import { SwUpdateNotificationsService } from './sw-update-notifications.service';
|
||||||
import { SwUpdatesService } from './sw-updates.service';
|
import { SwUpdatesService } from './sw-updates.service';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
MdSnackBarModule,
|
MdSnackBarModule,
|
||||||
ServiceWorkerModule
|
ServiceWorkerModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
noopNgServiceWorkerProviders,
|
||||||
SwUpdateNotificationsService,
|
SwUpdateNotificationsService,
|
||||||
SwUpdatesService
|
SwUpdatesService
|
||||||
]
|
]
|
||||||
|
@ -1,32 +1,41 @@
|
|||||||
import { ReflectiveInjector } from '@angular/core';
|
import { ReflectiveInjector } from '@angular/core';
|
||||||
import { fakeAsync, tick } from '@angular/core/testing';
|
import { fakeAsync, tick } from '@angular/core/testing';
|
||||||
import { NgServiceWorker } from '@angular/service-worker';
|
import { NgServiceWorker } from '@angular/service-worker';
|
||||||
|
import { of } from 'rxjs/observable/of';
|
||||||
import { Subject } from 'rxjs/Subject';
|
import { Subject } from 'rxjs/Subject';
|
||||||
import 'rxjs/add/operator/take';
|
import 'rxjs/add/operator/take';
|
||||||
|
|
||||||
|
import { NgServiceWorkerForReals, NoopNgServiceWorker, noopNgServiceWorkerProviders } from './noop-ng-service-worker';
|
||||||
import { SwUpdatesService } from './sw-updates.service';
|
import { SwUpdatesService } from './sw-updates.service';
|
||||||
|
|
||||||
|
|
||||||
describe('SwUpdatesService', () => {
|
describe('SwUpdatesService', () => {
|
||||||
let injector: ReflectiveInjector;
|
let injector: ReflectiveInjector;
|
||||||
let service: SwUpdatesService;
|
let service: SwUpdatesService;
|
||||||
let sw: MockNgServiceWorker;
|
let sw: MockNgServiceWorker;
|
||||||
|
let nsw: NoopNgServiceWorker;
|
||||||
let checkInterval: number;
|
let checkInterval: number;
|
||||||
|
let isServiceWorkerSupportedInTest: boolean;
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// Because `SwUpdatesService` uses the `debounceTime` operator, it needs to be instantiated
|
// Because `SwUpdatesService` uses the `debounceTime` operator, it needs to be instantiated
|
||||||
// inside the `fakeAsync` zone (when `fakeAsync` is used for the test). Thus, we can't run
|
// inside the `fakeAsync` zone (when `fakeAsync` is used for the test). Thus, we can't run
|
||||||
// `setup()` in a `beforeEach()` block. We use the `run()` helper to call it inside each test's
|
// `setup()` in a `beforeEach()` block. We use the `run()` helper to call it inside each test' zone.
|
||||||
// zone.
|
|
||||||
const setup = () => {
|
const setup = () => {
|
||||||
injector = ReflectiveInjector.resolveAndCreate([
|
injector = ReflectiveInjector.resolveAndCreate([
|
||||||
{ provide: NgServiceWorker, useClass: MockNgServiceWorker },
|
noopNgServiceWorkerProviders,
|
||||||
|
{ provide: NgServiceWorkerForReals, useClass: MockNgServiceWorker },
|
||||||
|
{ provide: NoopNgServiceWorker, useClass: MockNoopNgServiceWorker },
|
||||||
SwUpdatesService
|
SwUpdatesService
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
nsw = injector.get(NoopNgServiceWorker);
|
||||||
|
// Set whether service worker exists before getting the SwUpdatesService!
|
||||||
|
nsw.isServiceWorkerSupported = isServiceWorkerSupportedInTest;
|
||||||
|
|
||||||
service = injector.get(SwUpdatesService);
|
service = injector.get(SwUpdatesService);
|
||||||
sw = injector.get(NgServiceWorker);
|
|
||||||
checkInterval = (service as any).checkInterval;
|
checkInterval = (service as any).checkInterval;
|
||||||
|
sw = injector.get(NgServiceWorkerForReals);
|
||||||
};
|
};
|
||||||
const tearDown = () => service.ngOnDestroy();
|
const tearDown = () => service.ngOnDestroy();
|
||||||
const run = specFn => () => {
|
const run = specFn => () => {
|
||||||
@ -35,178 +44,212 @@ describe('SwUpdatesService', () => {
|
|||||||
tearDown();
|
tearDown();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
describe('when service worker is supported', () => {
|
||||||
|
|
||||||
it('should create', run(() => {
|
beforeEach(() => {
|
||||||
expect(service).toBeTruthy();
|
isServiceWorkerSupportedInTest = true;
|
||||||
}));
|
});
|
||||||
|
|
||||||
it('should immediatelly check for updates when instantiated', run(() => {
|
it('should create', run(() => {
|
||||||
expect(sw.checkForUpdate).toHaveBeenCalled();
|
expect(service).toBeTruthy();
|
||||||
}));
|
|
||||||
|
|
||||||
it('should schedule a new check if there is no update available', fakeAsync(run(() => {
|
|
||||||
sw.checkForUpdate.calls.reset();
|
|
||||||
|
|
||||||
sw.$$checkForUpdateSubj.next(false);
|
|
||||||
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
tick(checkInterval);
|
|
||||||
expect(sw.checkForUpdate).toHaveBeenCalled();
|
|
||||||
})));
|
|
||||||
|
|
||||||
it('should not schedule a new check if there is an update available', fakeAsync(run(() => {
|
|
||||||
sw.checkForUpdate.calls.reset();
|
|
||||||
|
|
||||||
sw.$$checkForUpdateSubj.next(true);
|
|
||||||
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
tick(checkInterval);
|
|
||||||
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
|
||||||
})));
|
|
||||||
|
|
||||||
describe('#activateUpdate()', () => {
|
|
||||||
it('should return a promise', run(() => {
|
|
||||||
expect(service.activateUpdate()).toEqual(jasmine.any(Promise));
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should call `NgServiceWorker.activateUpdate()`', run(() => {
|
it('should call the NgServiceWorker', run(() => {
|
||||||
expect(sw.activateUpdate).not.toHaveBeenCalled();
|
// does not call the Angular ServiceWorker
|
||||||
|
expect(sw.checkForUpdate).toHaveBeenCalled();
|
||||||
service.activateUpdate();
|
// calls the noop Angular ServiceWorker instead
|
||||||
expect(sw.activateUpdate).toHaveBeenCalled();
|
expect(nsw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not pass a specific version to `NgServiceWorker.activateUpdate()`', run(() => {
|
it('should immediatelly check for updates when instantiated', run(() => {
|
||||||
(service.activateUpdate as Function)('foo');
|
expect(sw.checkForUpdate).toHaveBeenCalled();
|
||||||
expect(sw.activateUpdate).toHaveBeenCalledWith(null);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve the promise with the activation outcome', fakeAsync(run(() => {
|
it('should schedule a new check if there is no update available', fakeAsync(run(() => {
|
||||||
let outcome;
|
|
||||||
|
|
||||||
service.activateUpdate().then(v => outcome = v);
|
|
||||||
sw.$$activateUpdateSubj.next(true);
|
|
||||||
tick();
|
|
||||||
expect(outcome).toBe(true);
|
|
||||||
|
|
||||||
service.activateUpdate().then(v => outcome = v);
|
|
||||||
sw.$$activateUpdateSubj.next(false);
|
|
||||||
tick();
|
|
||||||
expect(outcome).toBe(false);
|
|
||||||
})));
|
|
||||||
|
|
||||||
it('should schedule a new check (if the activation succeeded)', fakeAsync(run(() => {
|
|
||||||
sw.checkForUpdate.calls.reset();
|
sw.checkForUpdate.calls.reset();
|
||||||
|
|
||||||
service.activateUpdate();
|
sw.$$checkForUpdateSubj.next(false);
|
||||||
|
|
||||||
tick(checkInterval);
|
|
||||||
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
sw.$$activateUpdateSubj.next(true);
|
|
||||||
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
|
|
||||||
tick(checkInterval);
|
tick(checkInterval);
|
||||||
expect(sw.checkForUpdate).toHaveBeenCalled();
|
expect(sw.checkForUpdate).toHaveBeenCalled();
|
||||||
})));
|
})));
|
||||||
|
|
||||||
it('should schedule a new check (if the activation failed)', fakeAsync(run(() => {
|
it('should not schedule a new check if there is an update available', fakeAsync(run(() => {
|
||||||
sw.checkForUpdate.calls.reset();
|
sw.checkForUpdate.calls.reset();
|
||||||
|
|
||||||
service.activateUpdate();
|
sw.$$checkForUpdateSubj.next(true);
|
||||||
|
|
||||||
tick(checkInterval);
|
|
||||||
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
sw.$$activateUpdateSubj.next(false);
|
|
||||||
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
|
|
||||||
tick(checkInterval);
|
tick(checkInterval);
|
||||||
expect(sw.checkForUpdate).toHaveBeenCalled();
|
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
})));
|
})));
|
||||||
});
|
|
||||||
|
|
||||||
describe('#isUpdateAvailable', () => {
|
describe('#activateUpdate()', () => {
|
||||||
let emittedValues: boolean[];
|
it('should return a promise', run(() => {
|
||||||
|
expect(service.activateUpdate()).toEqual(jasmine.any(Promise));
|
||||||
|
}));
|
||||||
|
|
||||||
// Helpers
|
it('should call `NgServiceWorker.activateUpdate()`', run(() => {
|
||||||
const withSubscription = specFn => () => {
|
expect(sw.activateUpdate).not.toHaveBeenCalled();
|
||||||
emittedValues = [];
|
|
||||||
service.isUpdateAvailable.subscribe(v => emittedValues.push(v));
|
|
||||||
specFn();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
it('should emit `false/true` when there is/isn\'t an update available',
|
|
||||||
fakeAsync(run(withSubscription(() => {
|
|
||||||
expect(emittedValues).toEqual([]);
|
|
||||||
|
|
||||||
sw.$$checkForUpdateSubj.next(false);
|
|
||||||
expect(emittedValues).toEqual([false]);
|
|
||||||
|
|
||||||
tick(checkInterval);
|
|
||||||
sw.$$checkForUpdateSubj.next(true);
|
|
||||||
expect(emittedValues).toEqual([false, true]);
|
|
||||||
})))
|
|
||||||
);
|
|
||||||
|
|
||||||
it('should emit only when the value has changed',
|
|
||||||
fakeAsync(run(withSubscription(() => {
|
|
||||||
expect(emittedValues).toEqual([]);
|
|
||||||
|
|
||||||
sw.$$checkForUpdateSubj.next(false);
|
|
||||||
expect(emittedValues).toEqual([false]);
|
|
||||||
|
|
||||||
tick(checkInterval);
|
|
||||||
sw.$$checkForUpdateSubj.next(false);
|
|
||||||
expect(emittedValues).toEqual([false]);
|
|
||||||
|
|
||||||
tick(checkInterval);
|
|
||||||
sw.$$checkForUpdateSubj.next(false);
|
|
||||||
expect(emittedValues).toEqual([false]);
|
|
||||||
})))
|
|
||||||
);
|
|
||||||
|
|
||||||
it('should emit `false` after a successful activation',
|
|
||||||
fakeAsync(run(withSubscription(() => {
|
|
||||||
sw.$$checkForUpdateSubj.next(true);
|
|
||||||
expect(emittedValues).toEqual([true]);
|
|
||||||
|
|
||||||
service.activateUpdate();
|
service.activateUpdate();
|
||||||
|
expect(sw.activateUpdate).toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should not pass a specific version to `NgServiceWorker.activateUpdate()`', run(() => {
|
||||||
|
(service.activateUpdate as Function)('foo');
|
||||||
|
expect(sw.activateUpdate).toHaveBeenCalledWith(null);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should resolve the promise with the activation outcome', fakeAsync(run(() => {
|
||||||
|
let outcome;
|
||||||
|
|
||||||
|
service.activateUpdate().then(v => outcome = v);
|
||||||
sw.$$activateUpdateSubj.next(true);
|
sw.$$activateUpdateSubj.next(true);
|
||||||
|
tick();
|
||||||
|
expect(outcome).toBe(true);
|
||||||
|
|
||||||
expect(emittedValues).toEqual([true, false]);
|
service.activateUpdate().then(v => outcome = v);
|
||||||
})))
|
|
||||||
);
|
|
||||||
|
|
||||||
it('should emit `false` after a failed activation',
|
|
||||||
fakeAsync(run(withSubscription(() => {
|
|
||||||
sw.$$checkForUpdateSubj.next(true);
|
|
||||||
expect(emittedValues).toEqual([true]);
|
|
||||||
|
|
||||||
service.activateUpdate();
|
|
||||||
sw.$$activateUpdateSubj.next(false);
|
sw.$$activateUpdateSubj.next(false);
|
||||||
|
tick();
|
||||||
|
expect(outcome).toBe(false);
|
||||||
|
})));
|
||||||
|
|
||||||
expect(emittedValues).toEqual([true, false]);
|
it('should schedule a new check (if the activation succeeded)', fakeAsync(run(() => {
|
||||||
})))
|
sw.checkForUpdate.calls.reset();
|
||||||
);
|
|
||||||
|
|
||||||
it('should emit not emit a vew value after activation if already `false`',
|
|
||||||
fakeAsync(run(withSubscription(() => {
|
|
||||||
sw.$$checkForUpdateSubj.next(false);
|
|
||||||
expect(emittedValues).toEqual([false]);
|
|
||||||
|
|
||||||
service.activateUpdate();
|
service.activateUpdate();
|
||||||
sw.$$activateUpdateSubj.next(true);
|
|
||||||
|
|
||||||
expect(emittedValues).toEqual([false]);
|
tick(checkInterval);
|
||||||
})))
|
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
);
|
|
||||||
|
sw.$$activateUpdateSubj.next(true);
|
||||||
|
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
tick(checkInterval);
|
||||||
|
expect(sw.checkForUpdate).toHaveBeenCalled();
|
||||||
|
})));
|
||||||
|
|
||||||
|
it('should schedule a new check (if the activation failed)', fakeAsync(run(() => {
|
||||||
|
sw.checkForUpdate.calls.reset();
|
||||||
|
|
||||||
|
service.activateUpdate();
|
||||||
|
|
||||||
|
tick(checkInterval);
|
||||||
|
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
sw.$$activateUpdateSubj.next(false);
|
||||||
|
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
tick(checkInterval);
|
||||||
|
expect(sw.checkForUpdate).toHaveBeenCalled();
|
||||||
|
})));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#isUpdateAvailable', () => {
|
||||||
|
let emittedValues: boolean[];
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
const withSubscription = specFn => () => {
|
||||||
|
emittedValues = [];
|
||||||
|
service.isUpdateAvailable.subscribe(v => emittedValues.push(v));
|
||||||
|
specFn();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
it('should emit `false/true` when there is/isn\'t an update available',
|
||||||
|
fakeAsync(run(withSubscription(() => {
|
||||||
|
expect(emittedValues).toEqual([]);
|
||||||
|
|
||||||
|
sw.$$checkForUpdateSubj.next(false);
|
||||||
|
expect(emittedValues).toEqual([false]);
|
||||||
|
|
||||||
|
tick(checkInterval);
|
||||||
|
sw.$$checkForUpdateSubj.next(true);
|
||||||
|
expect(emittedValues).toEqual([false, true]);
|
||||||
|
})))
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should emit only when the value has changed',
|
||||||
|
fakeAsync(run(withSubscription(() => {
|
||||||
|
expect(emittedValues).toEqual([]);
|
||||||
|
|
||||||
|
sw.$$checkForUpdateSubj.next(false);
|
||||||
|
expect(emittedValues).toEqual([false]);
|
||||||
|
|
||||||
|
tick(checkInterval);
|
||||||
|
sw.$$checkForUpdateSubj.next(false);
|
||||||
|
expect(emittedValues).toEqual([false]);
|
||||||
|
|
||||||
|
tick(checkInterval);
|
||||||
|
sw.$$checkForUpdateSubj.next(false);
|
||||||
|
expect(emittedValues).toEqual([false]);
|
||||||
|
})))
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should emit `false` after a successful activation',
|
||||||
|
fakeAsync(run(withSubscription(() => {
|
||||||
|
sw.$$checkForUpdateSubj.next(true);
|
||||||
|
expect(emittedValues).toEqual([true]);
|
||||||
|
|
||||||
|
service.activateUpdate();
|
||||||
|
sw.$$activateUpdateSubj.next(true);
|
||||||
|
|
||||||
|
expect(emittedValues).toEqual([true, false]);
|
||||||
|
})))
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should emit `false` after a failed activation',
|
||||||
|
fakeAsync(run(withSubscription(() => {
|
||||||
|
sw.$$checkForUpdateSubj.next(true);
|
||||||
|
expect(emittedValues).toEqual([true]);
|
||||||
|
|
||||||
|
service.activateUpdate();
|
||||||
|
sw.$$activateUpdateSubj.next(false);
|
||||||
|
|
||||||
|
expect(emittedValues).toEqual([true, false]);
|
||||||
|
})))
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should not emit a new value after activation if already `false`',
|
||||||
|
fakeAsync(run(withSubscription(() => {
|
||||||
|
sw.$$checkForUpdateSubj.next(false);
|
||||||
|
expect(emittedValues).toEqual([false]);
|
||||||
|
|
||||||
|
service.activateUpdate();
|
||||||
|
sw.$$activateUpdateSubj.next(true);
|
||||||
|
|
||||||
|
expect(emittedValues).toEqual([false]);
|
||||||
|
})))
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('when service worker isn\'t supported (Safari)', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
isServiceWorkerSupportedInTest = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', run(() => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should call the NoopNgServiceWorker', run(() => {
|
||||||
|
// does not call the Angular ServiceWorker
|
||||||
|
expect(sw.checkForUpdate).not.toHaveBeenCalled();
|
||||||
|
// calls the noop Angular ServiceWorker instead
|
||||||
|
expect(nsw.checkForUpdate).toHaveBeenCalled();
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mocks
|
// Mocks
|
||||||
class MockNgServiceWorker {
|
class MockNgServiceWorker {
|
||||||
|
|
||||||
$$activateUpdateSubj = new Subject<boolean>();
|
$$activateUpdateSubj = new Subject<boolean>();
|
||||||
$$checkForUpdateSubj = new Subject<boolean>();
|
$$checkForUpdateSubj = new Subject<boolean>();
|
||||||
|
|
||||||
@ -216,3 +259,12 @@ class MockNgServiceWorker {
|
|||||||
checkForUpdate = jasmine.createSpy('MockNgServiceWorker.checkForUpdate')
|
checkForUpdate = jasmine.createSpy('MockNgServiceWorker.checkForUpdate')
|
||||||
.and.callFake(() => this.$$checkForUpdateSubj.take(1));
|
.and.callFake(() => this.$$checkForUpdateSubj.take(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MockNoopNgServiceWorker extends NoopNgServiceWorker {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.isServiceWorkerSupported = true; // assume it is by default
|
||||||
|
spyOn(this, 'activateUpdate').and.callThrough();
|
||||||
|
spyOn(this, 'checkForUpdate').and.callThrough();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Injectable, Injector, OnDestroy } from '@angular/core';
|
import { Injectable, OnDestroy } from '@angular/core';
|
||||||
import { NgServiceWorker } from '@angular/service-worker';
|
import { NgServiceWorker } from '@angular/service-worker';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
import { ReplaySubject } from 'rxjs/ReplaySubject';
|
||||||
@ -36,13 +36,9 @@ export class SwUpdatesService implements OnDestroy {
|
|||||||
private onDestroy = new Subject();
|
private onDestroy = new Subject();
|
||||||
private checkForUpdateSubj = new Subject();
|
private checkForUpdateSubj = new Subject();
|
||||||
private isUpdateAvailableSubj = new ReplaySubject<boolean>(1);
|
private isUpdateAvailableSubj = new ReplaySubject<boolean>(1);
|
||||||
private sw: NgServiceWorker | NullServiceWorker = null;
|
|
||||||
isUpdateAvailable = this.isUpdateAvailableSubj.distinctUntilChanged();
|
isUpdateAvailable = this.isUpdateAvailableSubj.distinctUntilChanged();
|
||||||
isServiceWorkAvailable = !!navigator['serviceWorker'];
|
|
||||||
|
|
||||||
constructor(injector: Injector) {
|
|
||||||
this.sw = this.isServiceWorkAvailable ? injector.get(NgServiceWorker) : new NullServiceWorker();
|
|
||||||
|
|
||||||
|
constructor(private sw: NgServiceWorker) {
|
||||||
this.checkForUpdateSubj
|
this.checkForUpdateSubj
|
||||||
.debounceTime(this.checkInterval)
|
.debounceTime(this.checkInterval)
|
||||||
.takeUntil(this.onDestroy)
|
.takeUntil(this.onDestroy)
|
||||||
@ -78,8 +74,3 @@ export class SwUpdatesService implements OnDestroy {
|
|||||||
.subscribe(v => this.isUpdateAvailableSubj.next(v));
|
.subscribe(v => this.isUpdateAvailableSubj.next(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NullServiceWorker {
|
|
||||||
checkForUpdate() { return Observable.of(false); }
|
|
||||||
activateUpdate(version: string) { return Observable.of(false); }
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user