kopia lustrzana https://gitlab.com/rysiekpl/libresilient
1619 wiersze
61 KiB
JavaScript
1619 wiersze
61 KiB
JavaScript
const makeServiceWorkerEnv = require('service-worker-mock');
|
|
|
|
global.fetch = require('node-fetch');
|
|
jest.mock('node-fetch')
|
|
|
|
|
|
describe("service-worker", () => {
|
|
beforeEach(() => {
|
|
|
|
global.fetch.mockImplementation((url, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
})
|
|
);
|
|
});
|
|
|
|
Object.assign(global, makeServiceWorkerEnv());
|
|
global.self = new ServiceWorkerGlobalScope()
|
|
jest.resetModules();
|
|
self.LibResilientPlugins = new Array()
|
|
self.importScripts = jest.fn((url)=>{
|
|
console.debug(`importScripts('../${url}')`)
|
|
try {
|
|
require('../' + url);
|
|
} catch(e) {}
|
|
})
|
|
// TODO: pretty ugly, but necessary for some reason...
|
|
global.LibResilientPluginConstructors = new Map()
|
|
self.LibResilientPluginConstructors = global.LibResilientPluginConstructors
|
|
})
|
|
|
|
test("basic set-up: LibResilientPlugins", async () => {
|
|
self.LibResilientPlugins = false
|
|
self.LibResilientConfig = {
|
|
plugins: [],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
require("../service-worker.js");
|
|
expect(self.LibResilientPlugins).toBeInstanceOf(Array)
|
|
})
|
|
|
|
test("Promise.any() polyfill should work", async () => {
|
|
self.LibResilientPlugins = false
|
|
self.LibResilientConfig = {
|
|
plugins: [],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
expect.assertions(4)
|
|
// we want to make sure to actually test the polyfill
|
|
Promise.any = undefined
|
|
expect(typeof Promise.any).toEqual('undefined')
|
|
require("../service-worker.js");
|
|
expect(typeof Promise.any).toEqual('function')
|
|
expect(await Promise.any([
|
|
Promise.resolve('test resolve 1'),
|
|
Promise.reject('test reject 2')
|
|
])).toEqual('test resolve 1')
|
|
try {
|
|
await Promise.any([
|
|
Promise.reject('test reject 1'),
|
|
Promise.reject('test reject 2')
|
|
])
|
|
} catch (e) {
|
|
expect(e).toEqual([
|
|
"test reject 1",
|
|
"test reject 2"
|
|
])
|
|
}
|
|
})
|
|
|
|
test("basic set-up: use default LibResilientConfig values when config.json missing", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
global.fetch.mockImplementation((url, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "fail" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 404,
|
|
statusText: "Not Found",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
})
|
|
);
|
|
});
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(10000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "fetch"},{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'fetch', 'cache'])
|
|
expect(fetch).toHaveBeenCalled();
|
|
})
|
|
|
|
test("basic set-up: use default LibResilientConfig values when config.json not valid JSON", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
global.fetch.mockImplementation((url, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
["not a JSON"],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
})
|
|
);
|
|
});
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(10000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "fetch"},{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'fetch', 'cache'])
|
|
expect(fetch).toHaveBeenCalled();
|
|
})
|
|
|
|
test("basic set-up: use default LibResilientConfig values when no valid 'plugins' field in config.json", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
global.fetch.mockImplementation((url, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({loggedComponents: ['service-worker', 'fetch'], plugins: 'not a valid array'})],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
})
|
|
);
|
|
});
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(10000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "fetch"},{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'fetch', 'cache'])
|
|
expect(fetch).toHaveBeenCalled();
|
|
})
|
|
|
|
test("basic set-up: use default LibResilientConfig values when no valid 'loggedComponents' field in config.json", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
global.fetch.mockImplementation((url, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({loggedComponents: 'not a valid array', plugins: [{name: "fetch"}]})],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
})
|
|
);
|
|
});
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(10000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "fetch"},{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'fetch', 'cache'])
|
|
expect(fetch).toHaveBeenCalled();
|
|
})
|
|
|
|
test("basic set-up: use default LibResilientConfig values when 'defaultPluginTimeout' field in config.json contains an invalid value", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
global.fetch.mockImplementation((url, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({loggedComponents: ['service-worker', 'fetch'], plugins: [{name: "fetch"}], defaultPluginTimeout: 'not an integer'})],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
})
|
|
);
|
|
});
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(10000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "fetch"},{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'fetch', 'cache'])
|
|
expect(fetch).toHaveBeenCalled();
|
|
})
|
|
|
|
test("basic set-up: use config values from a valid config.json file", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
global.fetch.mockImplementation((url, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({loggedComponents: ['service-worker', 'cache'], plugins: [{name: "cache"}], defaultPluginTimeout: 5000})],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
})
|
|
);
|
|
});
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(5000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'cache'])
|
|
expect(fetch).toHaveBeenCalled();
|
|
})
|
|
|
|
test("basic set-up: a valid config.json file gets cached", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
var configData = {loggedComponents: ['service-worker', 'cache'], plugins: [{name: "cache"}], defaultPluginTimeout: 5000}
|
|
global.fetch.mockImplementation((url, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify(configData)],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: url
|
|
})
|
|
);
|
|
});
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(5000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'cache'])
|
|
expect(fetch).toHaveBeenCalled();
|
|
expect (await caches.open('v1').then((cache)=>{
|
|
return cache.match(self.location.origin + '/config.json')
|
|
}).then((response)=>{
|
|
return response.json()
|
|
}).then((json)=>{
|
|
return json
|
|
})).toStrictEqual({loggedComponents: ['service-worker', 'cache'], plugins: [{name: "cache"}], defaultPluginTimeout: 5000})
|
|
})
|
|
|
|
test("basic set-up: a cached valid config.json file gets used, no fetch happens", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
var configData = {loggedComponents: ['service-worker', 'cache'], plugins: [{name: "cache"}], defaultPluginTimeout: 5000}
|
|
var configUrl = '/config.json'
|
|
var configResponse = new Response(
|
|
new Blob(
|
|
[JSON.stringify(configData)],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: configUrl
|
|
})
|
|
await caches
|
|
.open('v1')
|
|
.then((cache)=>{
|
|
return cache.put(configUrl, configResponse)
|
|
})
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(5000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'cache'])
|
|
expect(fetch).not.toHaveBeenCalled();
|
|
})
|
|
|
|
|
|
test("basic set-up: a stale cached valid config.json file gets used, no fetch happens, fresh config.json is retrieved using the configured plugins and cached", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
var configData = {loggedComponents: ['service-worker', 'cache', 'fetch'], plugins: [{name: "fetch"},{name: "cache"}], defaultPluginTimeout: 5000}
|
|
var configUrl = '/config.json'
|
|
var configResponse = new Response(
|
|
new Blob(
|
|
[JSON.stringify(configData)],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader',
|
|
// very stale date
|
|
'Date': new Date(0).toUTCString()
|
|
},
|
|
url: configUrl
|
|
})
|
|
await caches
|
|
.open('v1')
|
|
.then((cache)=>{
|
|
return cache.put(configUrl, configResponse)
|
|
})
|
|
|
|
|
|
var newConfigData = {loggedComponents: ['service-worker', 'fetch'], plugins: [{name: "fetch"}], defaultPluginTimeout: 2000}
|
|
let resolveConfigFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify(newConfigData)],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader',
|
|
// very current date
|
|
'Date': new Date().toUTCString()
|
|
},
|
|
url: configUrl
|
|
})
|
|
)
|
|
})
|
|
global.LibResilientPluginConstructors.set('fetch', ()=>{
|
|
return {
|
|
name: 'fetch',
|
|
description: 'Resolve with config data (pretending to be fetch).',
|
|
version: '0.0.1',
|
|
fetch: resolveConfigFetch
|
|
}
|
|
})
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
// verify current config (the one from the pre-cached stale `config.json`)
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(5000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "fetch"},{name: "cache"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'cache', 'fetch'])
|
|
expect(fetch).not.toHaveBeenCalled();
|
|
expect(resolveConfigFetch).toHaveBeenCalled();
|
|
|
|
// verify that the *new* config got cached
|
|
cdata = await caches
|
|
.open('v1')
|
|
.then((cache)=>{
|
|
return cache.match(configUrl)
|
|
})
|
|
.then((cresponse)=>{
|
|
return cresponse.json()
|
|
})
|
|
expect(cdata).toStrictEqual(newConfigData)
|
|
})
|
|
|
|
|
|
test("basic set-up: a stale cached valid config.json file gets used, no fetch happens; invalid config.json retrieved using the configured plugins is not cached", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
var configData = {loggedComponents: ['service-worker', 'cache', 'resolve-config'], plugins: [{name: "cache"}, {name: "resolve-config"}], defaultPluginTimeout: 5000}
|
|
var configUrl = '/config.json'
|
|
var configResponse = new Response(
|
|
new Blob(
|
|
[JSON.stringify(configData)],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader',
|
|
// very stale date
|
|
'Date': new Date(0).toUTCString()
|
|
},
|
|
url: configUrl
|
|
})
|
|
await caches
|
|
.open('v1')
|
|
.then((cache)=>{
|
|
return cache.put(configUrl, configResponse)
|
|
})
|
|
|
|
|
|
var newConfigData = {loggedComponentsInvalid: ['service-worker', 'resolve-config'], pluginsInvalid: [{name: "resolve-config"}], defaultPluginTimeoutInvalid: 2000}
|
|
let resolveConfigFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify(newConfigData)],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader',
|
|
// very current date
|
|
'Date': new Date().toUTCString()
|
|
},
|
|
url: configUrl
|
|
})
|
|
)
|
|
})
|
|
global.LibResilientPluginConstructors.set('resolve-config', ()=>{
|
|
return {
|
|
name: 'resolve-config',
|
|
description: 'Resolve with config data.',
|
|
version: '0.0.1',
|
|
fetch: resolveConfigFetch
|
|
}
|
|
})
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
// verify current config (the one from the pre-cached stale `config.json`)
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(5000)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual([{name: "cache"}, {name: "resolve-config"}])
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(['service-worker', 'cache', 'resolve-config'])
|
|
expect(fetch).not.toHaveBeenCalled();
|
|
expect(resolveConfigFetch).toHaveBeenCalled();
|
|
|
|
// verify that the *new* config got cached
|
|
cdata = await caches
|
|
.open('v1')
|
|
.then((cache)=>{
|
|
return cache.match(configUrl)
|
|
})
|
|
.then((cresponse)=>{
|
|
return cresponse.json()
|
|
})
|
|
expect(cdata).toStrictEqual(configData)
|
|
})
|
|
|
|
|
|
test("basic set-up: a stale cached valid config.json file gets used, no fetch happens; valid config.json (configuring additional plugins) is retrieved using the configured plugins other than fetch, and is not cached", async () => {
|
|
self.LibResilientConfig = null
|
|
|
|
var configData = {loggedComponents: ['service-worker', 'resolve-config'], plugins: [{name: "resolve-config"}], defaultPluginTimeout: 5000}
|
|
var configUrl = '/config.json'
|
|
var configResponse = new Response(
|
|
new Blob(
|
|
[JSON.stringify(configData)],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader',
|
|
// very stale date
|
|
'Date': new Date(0).toUTCString()
|
|
},
|
|
url: configUrl
|
|
})
|
|
await caches
|
|
.open('v1')
|
|
.then((cache)=>{
|
|
return cache.put(configUrl, configResponse)
|
|
})
|
|
|
|
|
|
var newConfigData = {loggedComponents: ['service-worker', 'resolve-config', 'cache'], plugins: [{name: "resolve-config"}, {name: "cache"}], defaultPluginTimeout: 2000}
|
|
let resolveConfigFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify(newConfigData)],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader',
|
|
// very current date
|
|
'Date': new Date().toUTCString()
|
|
},
|
|
url: configUrl
|
|
})
|
|
)
|
|
})
|
|
global.LibResilientPluginConstructors.set('resolve-config', ()=>{
|
|
return {
|
|
name: 'resolve-config',
|
|
description: 'Resolve with config data.',
|
|
version: '0.0.1',
|
|
fetch: resolveConfigFetch
|
|
}
|
|
})
|
|
|
|
try {
|
|
require("../service-worker.js");
|
|
} catch(e) {}
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
// verify current config (the one from the pre-cached stale `config.json`)
|
|
expect(typeof self.LibResilientConfig).toEqual('object')
|
|
expect(self.LibResilientConfig.defaultPluginTimeout).toBe(configData.defaultPluginTimeout)
|
|
expect(self.LibResilientConfig.plugins).toStrictEqual(configData.plugins)
|
|
expect(self.LibResilientConfig.loggedComponents).toStrictEqual(configData.loggedComponents)
|
|
expect(fetch).not.toHaveBeenCalled();
|
|
expect(resolveConfigFetch).toHaveBeenCalled();
|
|
|
|
// verify that the *new* config got cached
|
|
cdata = await caches
|
|
.open('v1')
|
|
.then((cache)=>{
|
|
return cache.match(configUrl)
|
|
})
|
|
.then((cresponse)=>{
|
|
return cresponse.json()
|
|
})
|
|
expect(cdata).toStrictEqual(configData)
|
|
})
|
|
|
|
test("failed fetch by first configured plugin should not affect a successful fetch by a second one", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'reject-all'
|
|
},{
|
|
name: 'resolve-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
let rejectingFetch = jest.fn((request, init)=>{ return Promise.reject(request); })
|
|
let resolvingFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
})
|
|
global.LibResilientPluginConstructors.set('reject-all', ()=>{
|
|
return {
|
|
name: 'reject-all',
|
|
description: 'Reject all requests.',
|
|
version: '0.0.1',
|
|
fetch: rejectingFetch
|
|
}
|
|
})
|
|
global.LibResilientPluginConstructors.set('resolve-all', ()=>{
|
|
return {
|
|
name: 'resolve-all',
|
|
description: 'Resolve all requests.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch
|
|
}
|
|
})
|
|
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
var response = await self.trigger('fetch', new Request('/test.json'))
|
|
expect(rejectingFetch).toHaveBeenCalled();
|
|
expect(resolvingFetch).toHaveBeenCalled();
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
});
|
|
|
|
test("plugins should receive the Request() init data", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'reject-all'
|
|
},{
|
|
name: 'resolve-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
let rejectingFetch = jest.fn((request, init)=>{ return Promise.reject(request); })
|
|
let resolvingFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
})
|
|
global.LibResilientPluginConstructors.set('reject-all', ()=>{
|
|
return {
|
|
name: 'reject-all',
|
|
description: 'Reject all requests.',
|
|
version: '0.0.1',
|
|
fetch: rejectingFetch
|
|
}
|
|
})
|
|
global.LibResilientPluginConstructors.set('resolve-all', ()=>{
|
|
return {
|
|
name: 'resolve-all',
|
|
description: 'Resolve all requests.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch
|
|
}
|
|
})
|
|
|
|
var initTest = {
|
|
method: "GET",
|
|
// TODO: ref. https://gitlab.com/rysiekpl/libresilient/-/issues/23
|
|
//headers: new Headers({"x-stub": "STUB"}),
|
|
//mode: "mode-stub",
|
|
//credentials: "credentials-stub",
|
|
cache: "cache-stub",
|
|
referrer: "referrer-stub",
|
|
// these are not implemented by service-worker-mock
|
|
// https://github.com/zackargyle/service-workers/blob/master/packages/service-worker-mock/models/Request.js#L20
|
|
redirect: undefined,
|
|
integrity: undefined,
|
|
cache: undefined
|
|
}
|
|
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
var response = await self.trigger('fetch', new Request('/test.json', initTest))
|
|
expect(rejectingFetch).toHaveBeenCalled();
|
|
expect(resolvingFetch).toHaveBeenCalled();
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
expect(rejectingFetch).toHaveBeenCalledWith('https://www.test.com/test.json', initTest)
|
|
expect(resolvingFetch).toHaveBeenCalledWith('https://www.test.com/test.json', initTest)
|
|
});
|
|
|
|
test("defaultPluginTimeout should be respected", async () => {
|
|
self.LibResilientConfig = {
|
|
defaultPluginTimeout: 100,
|
|
plugins: [{
|
|
name: 'resolve-with-timeout'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker',
|
|
]
|
|
}
|
|
let rwtCallback = jest.fn()
|
|
global.LibResilientPluginConstructors.set('resolve-with-timeout', ()=>{
|
|
return {
|
|
name: 'resolve-with-timeout',
|
|
description: 'Resolve all requests after a timeout.',
|
|
version: '0.0.1',
|
|
fetch: (request, init)=>{
|
|
return new Promise((resolve, reject)=>{
|
|
setTimeout(rwtCallback, 300)
|
|
})
|
|
}
|
|
}
|
|
})
|
|
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
var response = self.trigger('fetch', new Request('/test.json'))
|
|
expect.assertions(2)
|
|
try {
|
|
await response
|
|
} catch(e) {
|
|
expect(e.toString()).toBe("Error: LibResilient request using resolve-with-timeout timed out after 100ms.")
|
|
}
|
|
expect(rwtCallback).not.toHaveBeenCalled()
|
|
});
|
|
|
|
test("making an external request should work and not go through the plugins", async () => {
|
|
global.fetch.mockImplementation((request, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
method: 'GET',
|
|
url: request.url
|
|
})
|
|
);
|
|
});
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'reject-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
global.LibResilientPluginConstructors.set('reject-all', ()=>{
|
|
return {
|
|
name: 'reject-all',
|
|
description: 'Reject all requests.',
|
|
version: '0.0.1',
|
|
fetch: (request, init)=>{ return Promise.reject(request); }
|
|
}
|
|
})
|
|
require("../service-worker.js");
|
|
var response = await self.trigger('fetch', new Request('https://example.com/test.json'))
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
})
|
|
|
|
test("making a POST request should work and not go through the plugins", async () => {
|
|
global.fetch.mockImplementation((request, init) => {
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
method: 'POST',
|
|
url: request.url
|
|
})
|
|
);
|
|
});
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'reject-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
global.LibResilientPluginConstructors.set('reject-all', ()=>{
|
|
return {
|
|
name: 'reject-all',
|
|
description: 'Reject all requests.',
|
|
version: '0.0.1',
|
|
fetch: (request, init)=>{ return Promise.reject(request); }
|
|
}
|
|
})
|
|
require("../service-worker.js");
|
|
var response = await self.trigger('fetch', new Request('/test.json', {method: "POST"}))
|
|
expect(response.method).toEqual('POST')
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
})
|
|
|
|
test("stashing content after a successful fetch should work", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'fetch'
|
|
},{
|
|
name: 'cache'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker', 'fetch', 'cache'
|
|
]
|
|
}
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
var response = await self.trigger('fetch', new Request('/test.json'))
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
expect (await caches.open('v1').then((cache)=>{
|
|
return cache.keys()
|
|
}).then((keys)=>{
|
|
return keys[0].url
|
|
})).toEqual(self.location.origin + '/test.json')
|
|
expect (await caches.open('v1').then((cache)=>{
|
|
return cache.match(self.location.origin + '/test.json')
|
|
}).then((response)=>{
|
|
return response.json()
|
|
}).then((json)=>{
|
|
return json
|
|
})).toEqual({ test: "success" })
|
|
});
|
|
|
|
test("stashing should be skipped if content was retrieved from a stashing plugin", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'stashing-test'
|
|
},{
|
|
name: 'reject-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
let resolvingFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'X-LibResilient-Method': 'resolve-all',
|
|
'X-LibResilient-ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
})
|
|
let rejectingFetch = jest.fn((request, init)=>{ return Promise.reject(request); })
|
|
let stashingStash = jest.fn()
|
|
|
|
global.LibResilientPluginConstructors.set('stashing-test', ()=>{
|
|
return {
|
|
name: 'stashing-test',
|
|
description: 'Mock stashing plugin.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch,
|
|
stash: stashingStash
|
|
}
|
|
})
|
|
global.LibResilientPluginConstructors.set('reject-all', ()=>{
|
|
return {
|
|
name: 'reject-all',
|
|
description: 'Reject all requests.',
|
|
version: '0.0.1',
|
|
fetch: rejectingFetch
|
|
}
|
|
})
|
|
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
var response = await self.trigger('fetch', new Request('/test.json'))
|
|
expect(resolvingFetch).toHaveBeenCalled();
|
|
expect(stashingStash).not.toHaveBeenCalled();
|
|
expect(rejectingFetch).toHaveBeenCalled();
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
});
|
|
|
|
test("content should be stashed if it was retrieved from a job after retrieval from a stashing plugin, and it differs from the stashed version", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'stashing-test'
|
|
},{
|
|
name: 'resolve-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
let resolvingFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'X-LibResilient-Method': 'resolve-all',
|
|
'X-LibResilient-ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
})
|
|
let resolvingFetch2 = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success2" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'NewTestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
})
|
|
let stashingStash = jest.fn(async (response, url)=>{
|
|
expect(await response.json()).toEqual({ test: "success2" })
|
|
expect(response.headers.get('ETag')).toEqual('NewTestingETagHeader')
|
|
})
|
|
|
|
global.LibResilientPluginConstructors.set('stashing-test', ()=>{
|
|
return {
|
|
name: 'stashing-test',
|
|
description: 'Mock stashing plugin.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch,
|
|
stash: stashingStash
|
|
}
|
|
})
|
|
global.LibResilientPluginConstructors.set('resolve-all', ()=>{
|
|
return {
|
|
name: 'resolve-all',
|
|
description: 'Resolve all requests.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch2
|
|
}
|
|
})
|
|
|
|
var testClient = new Client()
|
|
self.clients.clients.push(testClient)
|
|
var fetchedDiffersFound = false
|
|
testClient.addEventListener('message', event => {
|
|
if (event.data.fetchedDiffers) {
|
|
fetchedDiffersFound = true
|
|
}
|
|
})
|
|
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
var response = await self.trigger('fetch', {
|
|
request: new Request('/test.json'),
|
|
clientId: testClient.id
|
|
})
|
|
expect(resolvingFetch).toHaveBeenCalled();
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
expect(resolvingFetch2).toHaveBeenCalled();
|
|
expect(stashingStash).toHaveBeenCalled();
|
|
expect(fetchedDiffersFound).toEqual(true)
|
|
});
|
|
|
|
test("content should be stashed if it was retrieved from a job after retrieval from a stashing plugin, even it does not differ from the stashed version", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'stashing-test'
|
|
},{
|
|
name: 'resolve-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
let resolvingFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'X-LibResilient-Method': 'resolve-all',
|
|
'X-LibResilient-ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
})
|
|
let stashingStash = jest.fn()
|
|
|
|
global.LibResilientPluginConstructors.set('stashing-test', ()=>{
|
|
return {
|
|
name: 'stashing-test',
|
|
description: 'Mock stashing plugin.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch,
|
|
stash: stashingStash
|
|
}
|
|
})
|
|
global.LibResilientPluginConstructors.set('resolve-all', ()=>{
|
|
return {
|
|
name: 'resolve-all',
|
|
description: 'Resolve all requests.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch
|
|
}
|
|
})
|
|
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
var response = await self.trigger('fetch', new Request('/test.json'))
|
|
expect(resolvingFetch).toHaveBeenCalledTimes(2);
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
expect(stashingStash).toHaveBeenCalled();
|
|
});
|
|
|
|
test("stashing content explicitly should work", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'cache'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker', 'cache'
|
|
]
|
|
}
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
await self.trigger(
|
|
'message',
|
|
{
|
|
data:{
|
|
stash: [new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})]
|
|
}
|
|
})
|
|
// needed here also
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
|
expect (await caches.open('v1').then((cache)=>{
|
|
return cache.keys()
|
|
}).then((keys)=>{
|
|
return keys[0].url
|
|
})).toEqual(self.location.origin + '/test.json')
|
|
expect (await caches.open('v1').then((cache)=>{
|
|
return cache.match(self.location.origin + '/test.json')
|
|
}).then((response)=>{
|
|
return response.json()
|
|
}).then((json)=>{
|
|
return json
|
|
})).toEqual({ test: "success" })
|
|
});
|
|
|
|
test("after a retrieval from a stashing plugin, background plugin should receive the Request() init data", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'stashing-test'
|
|
},{
|
|
name: 'resolve-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
let resolvingFetch = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'X-LibResilient-Method': 'resolve-all',
|
|
'X-LibResilient-ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
})
|
|
let resolvingFetch2 = jest.fn((request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success2" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'NewTestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
})
|
|
let stashingStash = jest.fn(async (response, url)=>{
|
|
expect(await response.json()).toEqual({ test: "success2" })
|
|
expect(response.headers.get('ETag')).toEqual('NewTestingETagHeader')
|
|
})
|
|
|
|
global.LibResilientPluginConstructors.set('stashing-test', ()=>{
|
|
return {
|
|
name: 'stashing-test',
|
|
description: 'Mock stashing plugin.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch,
|
|
stash: stashingStash
|
|
}
|
|
})
|
|
global.LibResilientPluginConstructors.set('resolve-all', ()=>{
|
|
return {
|
|
name: 'resolve-all',
|
|
description: 'Resolve all requests.',
|
|
version: '0.0.1',
|
|
fetch: resolvingFetch2
|
|
}
|
|
})
|
|
|
|
var testClient = new Client()
|
|
self.clients.clients.push(testClient)
|
|
var fetchedDiffersFound = false
|
|
testClient.addEventListener('message', event => {
|
|
if (event.data.fetchedDiffers) {
|
|
fetchedDiffersFound = true
|
|
}
|
|
})
|
|
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
var initTest = {
|
|
method: "GET",
|
|
// TODO: ref. https://gitlab.com/rysiekpl/libresilient/-/issues/23
|
|
//headers: new Headers({"x-stub": "STUB"}),
|
|
//mode: "mode-stub",
|
|
//credentials: "credentials-stub",
|
|
cache: "cache-stub",
|
|
referrer: "referrer-stub",
|
|
// these are not implemented by service-worker-mock
|
|
// https://github.com/zackargyle/service-workers/blob/master/packages/service-worker-mock/models/Request.js#L20
|
|
redirect: undefined,
|
|
integrity: undefined,
|
|
cache: undefined
|
|
}
|
|
|
|
var response = await self.trigger('fetch', {
|
|
request: new Request('/test.json', initTest),
|
|
clientId: testClient.id
|
|
})
|
|
expect(resolvingFetch).toHaveBeenCalled();
|
|
expect(await response.json()).toEqual({ test: "success" })
|
|
expect(resolvingFetch).toHaveBeenCalledWith('https://www.test.com/test.json', initTest);
|
|
expect(resolvingFetch2).toHaveBeenCalledWith('https://www.test.com/test.json', initTest);
|
|
});
|
|
|
|
test("unstashing content explicitly should work", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'cache'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker', 'cache'
|
|
]
|
|
}
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
await self.trigger(
|
|
'message',
|
|
{
|
|
data:{
|
|
stash: [new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})]
|
|
}
|
|
})
|
|
// needed here also
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
|
|
expect (await caches.open('v1').then((cache)=>{
|
|
return cache.keys()
|
|
}).then((keys)=>{
|
|
return keys[0].url
|
|
})).toEqual(self.location.origin + '/test.json')
|
|
expect (await caches.open('v1').then((cache)=>{
|
|
return cache.match(self.location.origin + '/test.json')
|
|
}).then((response)=>{
|
|
return response.json()
|
|
}).then((json)=>{
|
|
return json
|
|
})).toEqual({ test: "success" })
|
|
|
|
// now unstash
|
|
await self.trigger(
|
|
'message',
|
|
{
|
|
data:{
|
|
unstash: [self.location.origin + '/test.json']
|
|
}
|
|
})
|
|
expect (await caches.open('v1').then((cache)=>{
|
|
return cache.keys()
|
|
})).toEqual([])
|
|
});
|
|
|
|
test("publishing content explicitly should work (stub)", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'publish-test'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
var result = false
|
|
global.LibResilientPluginConstructors.set('publish-test', ()=>{
|
|
return {
|
|
name: 'publish-test',
|
|
description: 'Publish plugin fixture.',
|
|
version: '0.0.1',
|
|
publish: (request)=>{
|
|
result = 'publish-test success: ' + request.url
|
|
}
|
|
}
|
|
})
|
|
require("../service-worker.js");
|
|
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
|
|
await self.trigger(
|
|
'message',
|
|
{
|
|
data:{
|
|
publish: [new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})]
|
|
}
|
|
})
|
|
expect(result).toEqual('publish-test success: ' + self.location.origin + '/test.json')
|
|
})
|
|
|
|
test("using plugins with dependencies should work", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'dependent-test',
|
|
uses: [{
|
|
name: 'dependency1-test'
|
|
},{
|
|
name: 'dependency2-test'
|
|
}]
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
global.LibResilientPluginConstructors.set('dependent-test', ()=>{
|
|
return {
|
|
name: 'dependent-test',
|
|
description: 'Dependent plugin fixture.',
|
|
version: '0.0.1',
|
|
uses: [{
|
|
name: 'dependency1-test'
|
|
},{
|
|
name: 'dependency2-test'
|
|
}]
|
|
}
|
|
})
|
|
global.LibResilientPluginConstructors.set('dependency1-test', ()=>{
|
|
return {
|
|
name: 'dependency1-test',
|
|
description: 'First dependency plugin fixture.',
|
|
version: '0.0.1'
|
|
}
|
|
})
|
|
global.LibResilientPluginConstructors.set('dependency2-test', ()=>{
|
|
return {
|
|
name: 'dependency2-test',
|
|
description: 'Second dependency plugin fixture.',
|
|
version: '0.0.1'
|
|
}
|
|
})
|
|
require("../service-worker.js");
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(self.LibResilientPlugins.map(p=>p.name)).toEqual(['dependent-test'])
|
|
expect(self.LibResilientPlugins[0].uses.map(p=>p.name)).toEqual(['dependency1-test', 'dependency2-test'])
|
|
})
|
|
|
|
test("using multiple instances of the same plugin should work", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'plugin-test',
|
|
},{
|
|
name: 'plugin-test',
|
|
},{
|
|
name: 'plugin-test',
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
var pver = 0
|
|
global.LibResilientPluginConstructors.set('plugin-test', ()=>{
|
|
pver += 1
|
|
return {
|
|
name: 'plugin-test',
|
|
description: 'Simple plugin stub.',
|
|
version: '0.0.' + pver
|
|
}
|
|
})
|
|
require("../service-worker.js");
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect(self.LibResilientPlugins.map(p=>p.name)).toEqual(['plugin-test', 'plugin-test', 'plugin-test'])
|
|
expect(self.LibResilientPlugins.map(p=>p.version)).toEqual(['0.0.1', '0.0.2', '0.0.3'])
|
|
})
|
|
|
|
test("should error out if all plugins fail", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'reject-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
global.LibResilientPluginConstructors.set('reject-all', ()=>{
|
|
return {
|
|
name: 'reject-all',
|
|
description: 'Reject all requests.',
|
|
version: '0.0.1',
|
|
fetch: (request, init)=>{ return Promise.reject(request); }
|
|
}
|
|
})
|
|
require("../service-worker.js");
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
expect.assertions(1)
|
|
try {
|
|
await self.trigger('fetch', new Request('/test.json', {method: "GET"}))
|
|
} catch(e) {
|
|
expect(e).toEqual(self.location.origin + '/test.json')
|
|
}
|
|
})
|
|
|
|
test("should send clientId back if event.resultingClientId is set", async () => {
|
|
self.LibResilientConfig = {
|
|
plugins: [{
|
|
name: 'resolve-all'
|
|
}],
|
|
loggedComponents: [
|
|
'service-worker'
|
|
]
|
|
}
|
|
global.LibResilientPluginConstructors.set('resolve-all', ()=>{
|
|
return {
|
|
name: 'resolve-all',
|
|
description: 'Resolve all requests.',
|
|
version: '0.0.1',
|
|
fetch: (request, init)=>{
|
|
return Promise.resolve(
|
|
new Response(
|
|
new Blob(
|
|
[JSON.stringify({ test: "success" })],
|
|
{type: "application/json"}
|
|
),
|
|
{
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
'ETag': 'TestingETagHeader'
|
|
},
|
|
url: self.location.origin + '/test.json'
|
|
})
|
|
)
|
|
}
|
|
}
|
|
})
|
|
var testClient = new Client()
|
|
self.clients.clients.push(testClient)
|
|
// monkey-patching addEventListener so that we can add
|
|
// the resultingClientId field to the event in a fetch callback
|
|
self.oldAddEventListener = self.addEventListener
|
|
self.addEventListener = (eventName, callback) => {
|
|
if (eventName === 'fetch') {
|
|
return self.oldAddEventListener(eventName, event => {
|
|
event.resultingClientId = testClient.id
|
|
return callback(event)
|
|
})
|
|
} else {
|
|
return self.oldAddEventListener(eventName, callback)
|
|
}
|
|
}
|
|
expect.hasAssertions()
|
|
testClient.addEventListener('message', event => {
|
|
if (event.data.clientId) {
|
|
expect(event.data.clientId).toEqual(testClient.id)
|
|
}
|
|
})
|
|
require("../service-worker.js");
|
|
await self.trigger('install')
|
|
// this is silly but works, and is necessary because
|
|
// event.waitUntil() in the install event handler is not handled correctly in NodeJS
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
await self.trigger('activate')
|
|
await self.trigger('fetch', new Request('/test.json'))
|
|
})
|
|
|
|
});
|