chore(ajax): add tests for response values and headers in caching calls

This commit is contained in:
Martin Pool 2022-04-26 18:42:28 +02:00 committed by Thijs Louisse
parent 2b3d2bd6a4
commit b291e60794

View file

@ -8,9 +8,20 @@ describe('Ajax', () => {
/** @type {Ajax} */ /** @type {Ajax} */
let ajax; let ajax;
let responseId = 1;
const responseInit = () => ({
headers: {
// eslint-disable-next-line no-plusplus
'x-request-id': `${responseId++}`,
'content-type': 'application/json',
'x-custom-header': 'y-custom-value',
},
});
beforeEach(() => { beforeEach(() => {
fetchStub = stub(window, 'fetch'); fetchStub = stub(window, 'fetch');
fetchStub.returns(Promise.resolve(new Response('mock response'))); fetchStub.callsFake(() => Promise.resolve(new Response('mock response', responseInit())));
ajax = new Ajax(); ajax = new Ajax();
}); });
@ -68,13 +79,16 @@ describe('Ajax', () => {
describe('fetch()', () => { describe('fetch()', () => {
it('calls fetch with the given args, returning the result', async () => { it('calls fetch with the given args, returning the result', async () => {
const response = await (await ajax.fetch('/foo', { method: 'POST' })).text(); const response = await ajax.fetch('/foo', { method: 'POST' });
const responseText = await response.text();
expect(fetchStub).to.have.been.calledOnce; expect(fetchStub).to.have.been.calledOnce;
const request = fetchStub.getCall(0).args[0]; const request = fetchStub.getCall(0).args[0];
expect(request.url).to.equal(`${window.location.origin}/foo`); expect(request.url).to.equal(`${window.location.origin}/foo`);
expect(request.method).to.equal('POST'); expect(request.method).to.equal('POST');
expect(response).to.equal('mock response'); expect(responseText).to.equal('mock response');
expect(response.headers.get('Content-Type')).to.equal('application/json');
expect(response.headers.get('X-Custom-Header')).to.equal('y-custom-value');
}); });
it('throws on 4xx responses', async () => { it('throws on 4xx responses', async () => {
@ -112,7 +126,7 @@ describe('Ajax', () => {
}); });
}); });
describe('fetchtJson', () => { describe('fetchJson', () => {
beforeEach(() => { beforeEach(() => {
fetchStub.returns(Promise.resolve(new Response('{}'))); fetchStub.returns(Promise.resolve(new Response('{}')));
}); });
@ -124,9 +138,11 @@ describe('Ajax', () => {
}); });
it('decodes response from json', async () => { it('decodes response from json', async () => {
fetchStub.returns(Promise.resolve(new Response('{"a":1,"b":2}'))); fetchStub.returns(Promise.resolve(new Response('{"a":1,"b":2}', responseInit())));
const response = await ajax.fetchJson('/foo'); const response = await ajax.fetchJson('/foo');
expect(response.body).to.eql({ a: 1, b: 2 }); expect(response.body).to.eql({ a: 1, b: 2 });
expect(response.response.headers.get('Content-Type')).to.equal('application/json');
expect(response.response.headers.get('X-Custom-Header')).to.equal('y-custom-value');
}); });
describe('given a request body', () => { describe('given a request body', () => {
@ -287,39 +303,87 @@ describe('Ajax', () => {
getCacheIdentifier = () => String(cacheId); getCacheIdentifier = () => String(cacheId);
}); });
it('allows configuring cache interceptors on the Ajax config', async () => { describe('caching interceptors', async () => {
newCacheId(); /**
const customAjax = new Ajax({ * @type {Ajax}
cacheOptions: { */
useCache: true, let customAjax;
maxAge: 100,
getCacheIdentifier, beforeEach(async () => {
}, newCacheId();
customAjax = new Ajax({
cacheOptions: {
useCache: true,
maxAge: 100,
getCacheIdentifier,
},
});
}); });
const clock = useFakeTimers({ it('works', async () => {
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');
}); });
// Smoke test 1: verify caching works it('works with fetchJson', async () => {
await customAjax.fetch('/foo'); fetchStub.returns(Promise.resolve(new Response('{"a":1,"b":2}', responseInit())));
expect(fetchStub.callCount).to.equal(1);
await customAjax.fetch('/foo');
expect(fetchStub.callCount).to.equal(1);
// Smoke test 2: verify caching is invalidated on non-get method const firstResponse = await customAjax.fetchJson('/foo');
await customAjax.fetch('/foo', { method: 'POST' }); expect(firstResponse.body).to.deep.equal({ a: 1, b: 2 });
expect(fetchStub.callCount).to.equal(2); expect(firstResponse.response.headers.get('X-Custom-Header')).to.equal('y-custom-value');
await customAjax.fetch('/foo'); expect(firstResponse.response.headers.get('Content-Type')).to.equal('application/json');
expect(fetchStub.callCount).to.equal(3);
// Smoke test 3: verify caching is invalidated after TTL has passed const secondResponse = await customAjax.fetchJson('/foo');
await customAjax.fetch('/foo'); expect(fetchStub.callCount).to.equal(1);
expect(fetchStub.callCount).to.equal(3); expect(secondResponse.body).to.deep.equal({ a: 1, b: 2 });
clock.tick(101); expect(secondResponse.response.headers.get('X-Custom-Header')).to.equal('y-custom-value');
await customAjax.fetch('/foo'); expect(secondResponse.response.headers.get('Content-Type')).to.equal('application/json');
expect(fetchStub.callCount).to.equal(4); });
clock.restore();
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');
});
it('is invalidated after TTL has passed', async () => {
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();
});
}); });
}); });