Skip to content

Commit

Permalink
Add caching tests for when getCacheIdentifier is asynchronous
Browse files Browse the repository at this point in the history
  • Loading branch information
ing-athirlwall authored and tlouisse committed May 7, 2024
1 parent c5ffe9c commit a8105ec
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 66 deletions.
5 changes: 5 additions & 0 deletions .changeset/stupid-pandas-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lion/ajax': patch
---

Add caching tests for when getCacheIdentifier is asynchronous
202 changes: 136 additions & 66 deletions packages/ajax/test/Ajax.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,8 @@ describe('Ajax', () => {
let cacheId;
/** @type {() => string} */
let getCacheIdentifier;
/** @type {() => Promise<string>} */
let getCacheIdentifierAsync;

const newCacheId = () => {
if (!cacheId) {
Expand All @@ -463,6 +465,7 @@ describe('Ajax', () => {

beforeEach(() => {
getCacheIdentifier = () => String(cacheId);
getCacheIdentifierAsync = () => Promise.resolve(String(cacheId));
});

it('does not add cache interceptors when useCache is turned off', () => {
Expand Down Expand Up @@ -503,7 +506,97 @@ describe('Ajax', () => {
expect(customAjax._responseInterceptors.length).to.equal(1);
});

describe('Caching interceptors: synchronous getCacheIdentifier tests', async () => {
const cachingTests = {};
cachingTests.works = async (/** @type {Ajax} */ customAjax) => {
await customAjax.fetch('/foo');

const secondResponse = await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(1);
expect(await secondResponse.text()).to.equal('mock response');
expect(secondResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(secondResponse.headers.get('Content-Type')).to.equal('application/json');
};

cachingTests.resetOnCacheIDChange = async (/** @type {Ajax} */ customAjax) => {
/* Three calls to the same endpoint should result in a
single fetchStubCall due to caching */
await customAjax.fetch('/foo');
await customAjax.fetch('/foo');
await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(1);

newCacheId();
await customAjax.fetch('/foo');

/* The newCacheId call should reset the cache, thereby adding an
extra call to the fetchStub call count. */
expect(fetchStub.callCount).to.equal(2);
};

cachingTests.completePendingOnCacheIDChange = async (/** @type {Ajax} */ customAjax) => {
const requestOne = customAjax.fetch('/foo').then(() => 'completedRequestOne');
newCacheId();
const requestTwo = customAjax.fetch('/foo').then(() => 'completedRequestTwo');
expect(await requestOne).to.equal('completedRequestOne');
expect(await requestTwo).to.equal('completedRequestTwo');
};

cachingTests.worksWithFetchJson = async (/** @type {Ajax} */ customAjax) => {
fetchStub.returns(Promise.resolve(new Response('{"a":1,"b":2}', responseInit())));

const firstResponse = await customAjax.fetchJson('/foo');
expect(firstResponse.body).to.deep.equal({ a: 1, b: 2 });
expect(firstResponse.response.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(firstResponse.response.headers.get('Content-Type')).to.equal('application/json');

const secondResponse = await customAjax.fetchJson('/foo');
expect(fetchStub.callCount).to.equal(1);
expect(secondResponse.body).to.deep.equal({ a: 1, b: 2 });
expect(secondResponse.response.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(secondResponse.response.headers.get('Content-Type')).to.equal('application/json');
};

cachingTests.invalidatesOnNonGetMethod = async (/** @type {Ajax} */ customAjax) => {
await customAjax.fetch('/foo');

const secondResponse = await customAjax.fetch('/foo', { method: 'POST' });
expect(fetchStub.callCount).to.equal(2);
expect(await secondResponse.text()).to.equal('mock response');
expect(secondResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(secondResponse.headers.get('Content-Type')).to.equal('application/json');

const thirdResponse = await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(3);
expect(await thirdResponse.text()).to.equal('mock response');
expect(thirdResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(thirdResponse.headers.get('Content-Type')).to.equal('application/json');
};

cachingTests.invalidatesOnTTLPassed = async (/** @type {Ajax} */ customAjax) => {
const clock = useFakeTimers({
shouldAdvanceTime: true,
});

await customAjax.fetch('/foo');

const secondResponse = await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(1);
expect(await secondResponse.text()).to.equal('mock response');
expect(secondResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(secondResponse.headers.get('Content-Type')).to.equal('application/json');

clock.tick(101);

const thirdResponse = await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(2);
expect(await thirdResponse.text()).to.equal('mock response');
expect(thirdResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(thirdResponse.headers.get('Content-Type')).to.equal('application/json');

clock.restore();
};

describe('Caching interceptors: cache tests with synchronous getCacheIdentifier', async () => {
/**
* @type {Ajax}
*/
Expand All @@ -521,92 +614,69 @@ describe('Ajax', () => {
});

it('works', async () => {
await customAjax.fetch('/foo');

const secondResponse = await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(1);
expect(await secondResponse.text()).to.equal('mock response');
expect(secondResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(secondResponse.headers.get('Content-Type')).to.equal('application/json');
await cachingTests.works(customAjax);
});

it('resets the cache if the cache ID changes', async () => {
/* Three calls to the same endpoint should result in a
single fetchStubCall due to caching */
await customAjax.fetch('/foo');
await customAjax.fetch('/foo');
await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(1);

newCacheId();
await customAjax.fetch('/foo');

/* The newCacheId call should reset the cache, thereby adding an
extra call to the fetchStub call count. */
expect(fetchStub.callCount).to.equal(2);
await cachingTests.resetOnCacheIDChange(customAjax);
});

it('Completes pending requests when the cache ID changes', async () => {
const requestOne = customAjax.fetch('/foo').then(() => 'completedRequestOne');
newCacheId();
const requestTwo = customAjax.fetch('/foo').then(() => 'completedRequestTwo');
expect(await requestOne).to.equal('completedRequestOne');
expect(await requestTwo).to.equal('completedRequestTwo');
await cachingTests.completePendingOnCacheIDChange(customAjax);
});

it('works with fetchJson', async () => {
fetchStub.returns(Promise.resolve(new Response('{"a":1,"b":2}', responseInit())));

const firstResponse = await customAjax.fetchJson('/foo');
expect(firstResponse.body).to.deep.equal({ a: 1, b: 2 });
expect(firstResponse.response.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(firstResponse.response.headers.get('Content-Type')).to.equal('application/json');

const secondResponse = await customAjax.fetchJson('/foo');
expect(fetchStub.callCount).to.equal(1);
expect(secondResponse.body).to.deep.equal({ a: 1, b: 2 });
expect(secondResponse.response.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(secondResponse.response.headers.get('Content-Type')).to.equal('application/json');
await cachingTests.worksWithFetchJson(customAjax);
});

it('is invalidated on non-get method', async () => {
await customAjax.fetch('/foo');

const secondResponse = await customAjax.fetch('/foo', { method: 'POST' });
expect(fetchStub.callCount).to.equal(2);
expect(await secondResponse.text()).to.equal('mock response');
expect(secondResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(secondResponse.headers.get('Content-Type')).to.equal('application/json');

const thirdResponse = await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(3);
expect(await thirdResponse.text()).to.equal('mock response');
expect(thirdResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(thirdResponse.headers.get('Content-Type')).to.equal('application/json');
await cachingTests.invalidatesOnNonGetMethod(customAjax);
});

it('is invalidated after TTL has passed', async () => {
const clock = useFakeTimers({
shouldAdvanceTime: true,
await cachingTests.invalidatesOnTTLPassed(customAjax);
});
});

describe('Caching interceptors: cache tests with asynchronous getCacheIdentifier', async () => {
/**
* @type {Ajax}
*/
let customAjax;

beforeEach(async () => {
newCacheId();
customAjax = new Ajax({
cacheOptions: {
useCache: true,
maxAge: 100,
getCacheIdentifier: getCacheIdentifierAsync,
},
});
});

await customAjax.fetch('/foo');
it('works', async () => {
await cachingTests.works(customAjax);
});

it('resets the cache if the cache ID changes', async () => {
await cachingTests.resetOnCacheIDChange(customAjax);
});

const secondResponse = await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(1);
expect(await secondResponse.text()).to.equal('mock response');
expect(secondResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(secondResponse.headers.get('Content-Type')).to.equal('application/json');
it('Completes pending requests when the cache ID changes', async () => {
await cachingTests.completePendingOnCacheIDChange(customAjax);
});

clock.tick(101);
it('works with fetchJson', async () => {
await cachingTests.worksWithFetchJson(customAjax);
});

const thirdResponse = await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(2);
expect(await thirdResponse.text()).to.equal('mock response');
expect(thirdResponse.headers.get('X-Custom-Header')).to.equal('y-custom-value');
expect(thirdResponse.headers.get('Content-Type')).to.equal('application/json');
it('is invalidated on non-get method', async () => {
await cachingTests.invalidatesOnNonGetMethod(customAjax);
});

clock.restore();
it('is invalidated after TTL has passed', async () => {
await cachingTests.invalidatesOnTTLPassed(customAjax);
});
});
});
Expand Down

0 comments on commit a8105ec

Please sign in to comment.