diff --git a/.gitignore b/.gitignore index 80ae1ad..30d338b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ node_modules -*.js.map lcov.info \ No newline at end of file diff --git a/README.md b/README.md index 6816b7c..5f126a6 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ A PokeAPI wrapper intended for browsers. Comes fully asynchronous, zero dependen - [Example requests](#example-requests) - [Configuration](#configuration) - [Caching images](#caching-images) + - [Caching methods](#caching-methods) - [Tests](#tests) - [Endpoints](#endpoints) - [Root Endpoints list](#root-endpoints-list) @@ -31,7 +32,7 @@ console.log(await pokedex.getPokemonsList()) ```html diff --git a/src/pokeapi-js-wrapper-sw.js b/test/pokeapi-js-wrapper-sw.js similarity index 100% rename from src/pokeapi-js-wrapper-sw.js rename to test/pokeapi-js-wrapper-sw.js diff --git a/test/test.html.js b/test/test.html.js index 64f2007..f935098 100644 --- a/test/test.html.js +++ b/test/test.html.js @@ -8,7 +8,10 @@ describe("service worker", function () { this.timeout(10000); before(async function() { - P = await Pokedex.init({ cacheImages: true }); + P = await Pokedex.init({ + cacheImages: true, + swLocation: '/test/' + }); }); it("should be activated on second run", async function () { @@ -42,16 +45,17 @@ describe("pokedex", function () { describe(".resource(Mixed: array) not cached", function () { it("should have property name", async function () { - const res = await customP.resource(['/api/v2/pokemon/36', 'api/v2/berry/8', 'https://pokeapi.co/api/v2/ability/9/']); + const res = await customP.resource(['pokemon/37', '/pokemon/36', '/berry/8', 'https://pokeapi.co/api/v2/ability/9/']); expect(res[0]).to.have.property('name'); expect(res[1]).to.have.property('name'); expect(res[2]).to.have.property('name'); + expect(res[3]).to.have.property('name'); }); }); describe(".resource(Path: string)", function () { it("should have property height", async function () { - const res = await defaultP.resource('/api/v2/pokemon/34'); + const res = await defaultP.resource('pokemon/34'); expect(res).to.have.property('height'); }); }); @@ -372,6 +376,75 @@ describe("pokedex", function () { }); }); +describe("Cache", function () { + this.timeout(10000); + const originalFetch = window.fetch; + let P; + let fetchCalls = []; + + before(async function () { + P = await Pokedex.init({ cache: true }); + window.fetch = async (url) => { + const url_str = url.toString(); + fetchCalls.push(url_str); + + if (url_str.includes('/pokemon/ditto')) { + return new Response(JSON.stringify({ name: 'ditto' }), { + headers: { 'X-PokeAPI-Deploy-Date': '100' } + }); + } + if (url_str.includes('/pokemon/pikachu')) { + return new Response(JSON.stringify({ name: 'pikachu' }), { + headers: { 'X-PokeAPI-Deploy-Date': '300' } + }); + } + if (url_str.includes('/meta')) { + return new Response(JSON.stringify({ deploy_date: '200' })); + } + return originalFetch(url); + }; + }); + + beforeEach(async function () { + await P.clearCache(); + fetchCalls = []; + }); + + after(function () { + window.fetch = originalFetch; + }); + + it("should invalidate old cache entries and keep new ones", async function () { + await P.getPokemonByName('ditto'); + await P.getPokemonByName('pikachu'); + expect(fetchCalls.length).to.equal(2); + + let cacheSize = await P.getCacheLength(); + expect(cacheSize).to.equal(2); + + fetchCalls = []; + await P.getPokemonByName('ditto'); + await P.getPokemonByName('pikachu'); + expect(fetchCalls.length).to.equal(0); + + await P.invalidateCache(); + expect(fetchCalls.length).to.equal(1); + expect(fetchCalls[0]).to.include('/meta'); + + cacheSize = await P.getCacheLength(); + expect(cacheSize).to.equal(1); + + fetchCalls = []; + await P.getPokemonByName('ditto'); + await P.getPokemonByName('pikachu'); + expect(fetchCalls.length).to.equal(1); + expect(fetchCalls[0]).to.include('/pokemon/ditto'); + + cacheSize = await P.getCacheLength(); + expect(cacheSize).to.equal(2); + }); +}); + const button = document.getElementById('flush-cache-btn'); button.addEventListener('click', async () => { diff --git a/test/test.js b/test/test.js index db51b9e..f9dffdd 100644 --- a/test/test.js +++ b/test/test.js @@ -7,6 +7,7 @@ describe("pokedex", { timeout: 30000 }, function () { let p2; const id = 2; + const string = 'pokemon/33'; const path = '/api/v2/pokemon/34'; const url = 'https://pokeapi.co/api/v2/pokemon/35'; const interval = { limit: 10, offset: 34 }; @@ -31,6 +32,36 @@ describe("pokedex", { timeout: 30000 }, function () { }); }); + // --- Resource Methods --- + describe(".resource()", function () { + it("should succeed with a single path", async function () { + const res = await p1.resource(path); + assert.ok(res.height, "Response should have height"); + }); + it("should succeed with a single path", async function () { + const res = await p1.resource(string); + assert.ok(res.height, "Response should have height"); + }); + it("should succeed with an array of paths", async function () { + const res = await p1.resource([path, url, string]); + assert.strictEqual(res.length, 3); + assert.ok(res[0].height, 'Should have property height'); + assert.ok(res[1].height, 'Should have property height'); + assert.ok(res[2].height, 'Should have property height'); + }); + it("should succeed with an array of paths with trailing /", async function () { + const res = await p1.resource([`${path}/`, `${url}/`, `${string}/`]); + assert.strictEqual(res.length, 3); + assert.ok(res[0].height, 'Should have property height'); + assert.ok(res[1].height, 'Should have property height'); + assert.ok(res[2].height, 'Should have property height'); + }); + it("should fail with an invalid path", async function () { + const result = await p1.resource(123); + assert.strictEqual(result, "String or Array is required"); + }); + }); + // --- List Methods --- describe(".getPokemonsList()", function () { it("should succeed with default interval", async function () { @@ -49,4 +80,26 @@ describe("pokedex", { timeout: 30000 }, function () { ); }); }); + + // --- IndexedDB --- + describe("IndexedDB", function () { + it(".getCacheLength() should throw an error", async function () { + await assert.rejects( + p1.getCacheLength(), + Error + ); + }); + it(".clearCache() should throw an error", async function () { + await assert.rejects( + p1.clearCache(), + Error + ); + }); + it(".invalidateCache() should throw an error", async function () { + await assert.rejects( + p1.invalidateCache(), + Error + ); + }); + }); }); \ No newline at end of file