Skip to content

Commit

Permalink
split routing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
wheresrhys committed May 20, 2020
1 parent e5c2876 commit 0d48926
Show file tree
Hide file tree
Showing 11 changed files with 1,198 additions and 1,110 deletions.
168 changes: 168 additions & 0 deletions test/specs/routing/body-matching.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
const chai = require('chai');
const expect = chai.expect;

const { fetchMock } = testGlobals;
describe('body matching', () => {
let fm;
before(() => {
fm = fetchMock.createInstance();
fm.config.warnOnUnmatched = false;
});

afterEach(() => fm.restore());

it('should not match if no body provided in request', async () => {
fm.mock('http://a.com/', 200, { body: { foo: 'bar' } }).catch();

await fm.fetchHandler('http://a.com/', {
method: 'POST',
});
expect(fm.calls(true).length).to.equal(0);
});

it('should match if no content type is specified', async () => {
fm.mock('http://a.com/', 200, { body: { foo: 'bar' } }).catch();

await fm.fetchHandler('http://a.com/', {
method: 'POST',
body: JSON.stringify({ foo: 'bar' }),
});
expect(fm.calls(true).length).to.equal(1);
});

it('should match when using Request', async () => {
fm.mock('http://a.com/', 200, { body: { foo: 'bar' } }).catch();

await fm.fetchHandler(
new fm.config.Request('http://a.com/', {
method: 'POST',
body: JSON.stringify({ foo: 'bar' }),
})
);
expect(fm.calls(true).length).to.equal(1);
});

it('should match if body sent matches expected body', async () => {
fm.mock('http://a.com/', 200, { body: { foo: 'bar' } }).catch();

await fm.fetchHandler('http://a.com/', {
method: 'POST',
body: JSON.stringify({ foo: 'bar' }),
headers: { 'Content-Type': 'application/json' },
});
expect(fm.calls(true).length).to.equal(1);
});

it('should not match if body sent doesn’t match expected body', async () => {
fm.mock('http://a.com/', 200, { body: { foo: 'bar' } }).catch();

await fm.fetchHandler('http://a.com/', {
method: 'POST',
body: JSON.stringify({ foo: 'woah!!!' }),
headers: { 'Content-Type': 'application/json' },
});
expect(fm.calls(true).length).to.equal(0);
});

it('should not match if body sent isn’t JSON', async () => {
fm.mock('http://a.com/', 200, { body: { foo: 'bar' } }).catch();

await fm.fetchHandler('http://a.com/', {
method: 'POST',
body: new ArrayBuffer(8),
headers: { 'Content-Type': 'application/json' },
});
expect(fm.calls(true).length).to.equal(0);
});

it('should ignore the order of the keys in the body', async () => {
fm.mock('http://a.com/', 200, {
body: {
foo: 'bar',
baz: 'qux',
},
}).catch();

await fm.fetchHandler('http://a.com/', {
method: 'POST',
body: JSON.stringify({
baz: 'qux',
foo: 'bar',
}),
headers: { 'Content-Type': 'application/json' },
});
expect(fm.calls(true).length).to.equal(1);
});

it('should ignore the body option matcher if request was GET', async () => {
fm.mock('http://a.com/', 200, {
body: {
foo: 'bar',
baz: 'qux',
},
}).catch();

await fm.fetchHandler('http://a.com/');
expect(fm.calls(true).length).to.equal(1);
});

describe('partial body matching', () => {
it('match when missing properties', async () => {
fm.mock({ body: { ham: 'sandwich' }, matchPartialBody: true }, 200).catch(
404
);
const res = await fm.fetchHandler('http://a.com', {
method: 'POST',
body: JSON.stringify({ ham: 'sandwich', egg: 'mayonaise' }),
});
expect(res.status).to.equal(200);
});

it('match when missing nested properties', async () => {
fm.mock(
{ body: { meal: { ham: 'sandwich' } }, matchPartialBody: true },
200
).catch(404);
const res = await fm.fetchHandler('http://a.com', {
method: 'POST',
body: JSON.stringify({
meal: { ham: 'sandwich', egg: 'mayonaise' },
}),
});
expect(res.status).to.equal(200);
});

it('not match when properties at wrong indentation', async () => {
fm.mock({ body: { ham: 'sandwich' }, matchPartialBody: true }, 200).catch(
404
);
const res = await fm.fetchHandler('http://a.com', {
method: 'POST',
body: JSON.stringify({ meal: { ham: 'sandwich' } }),
});
expect(res.status).to.equal(404);
});

it('match when starting subset of array', async () => {
fm.mock({ body: { ham: [1, 2] }, matchPartialBody: true }, 200).catch(
404
);
const res = await fm.fetchHandler('http://a.com', {
method: 'POST',
body: JSON.stringify({ ham: [1, 2, 3] }),
});
expect(res.status).to.equal(200);
});

it('not match when not starting subset of array', async () => {
fm.mock({ body: { ham: [1, 3] }, matchPartialBody: true }, 200).catch(
404
);
const res = await fm.fetchHandler('http://a.com', {
method: 'POST',
body: JSON.stringify({ ham: [1, 2, 3] }),
});
expect(res.status).to.equal(404);
});
});
});
77 changes: 77 additions & 0 deletions test/specs/routing/edge-cases.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const chai = require('chai');
const expect = chai.expect;

const { fetchMock } = testGlobals;
describe('edge cases', () => {
let fm;
before(() => {
fm = fetchMock.createInstance();
fm.config.warnOnUnmatched = false;
});

afterEach(() => fm.restore());

it('match relative urls', async () => {
fm.mock('/a.com/', 200).catch();

await fm.fetchHandler('/a.com/');
expect(fm.calls(true).length).to.equal(1);
});

it('match relative urls with dots', async () => {
fm.mock('/it.at/there/', 200).catch();

await fm.fetchHandler('/it.at/not/../there/');
expect(fm.calls(true).length).to.equal(1);
await fm.fetchHandler('./it.at/there/');
expect(fm.calls(true).length).to.equal(2);
});

it('match absolute urls with dots', async () => {
fm.mock('http://it.at/there/', 200).catch();

await fm.fetchHandler('http://it.at/not/../there/');
expect(fm.calls(true).length).to.equal(1);
});

it('match when called with Request', async () => {
fm.post('http://a.com/', 200).catch();

await fm.fetchHandler(
new fm.config.Request('http://a.com/', { method: 'POST' })
);
expect(fm.calls(true).length).to.equal(1);
});

it('allow routes only differing in query strings', async () => {
expect(() => {
fm.get(`/xyz/abc?id=486726&id=486727`, 200);
fm.get(`/xyz/abc?id=486727`, 200);
}).not.to.throw();
});

it('express match full url', async () => {
fm.mock('express:/apps/:id', 200).catch();

await fm.fetchHandler('https://api.example.com/apps/abc');
expect(fm.calls(true).length).to.equal(1);
});
it('setup routes correctly when using object definitions', async () => {
fm.get({
matcher: `express:/:var`,
response: 200,
}).put({
matcher: `express:/:var`,
response: 201,
overwriteRoutes: false,
});

const { status } = await fm.fetchHandler('https://api.example.com/lala', {
method: 'put',
});
// before fixing this test it was returning 200 for the put request
// because both teh .get() and .put() calls were failing to correctly
// add the choice of method to the route config
expect(status).to.equal(201);
});
});
111 changes: 111 additions & 0 deletions test/specs/routing/function-matching.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
const chai = require('chai');
const expect = chai.expect;

const { fetchMock } = testGlobals;
describe('function matching', () => {
let fm;
before(() => {
fm = fetchMock.createInstance();
fm.config.warnOnUnmatched = false;
});

afterEach(() => fm.restore());

it('match using custom function', async () => {
fm.mock((url, opts) => {
return (
url.indexOf('logged-in') > -1 &&
opts &&
opts.headers &&
opts.headers.authorized === true
);
}, 200).catch();

await fm.fetchHandler('http://a.com/12345', {
headers: { authorized: true },
});
expect(fm.calls(true).length).to.equal(0);
await fm.fetchHandler('http://a.com/logged-in');
expect(fm.calls(true).length).to.equal(0);
await fm.fetchHandler('http://a.com/logged-in', {
headers: { authorized: true },
});
expect(fm.calls(true).length).to.equal(1);
});

it('match using custom function using request body', async () => {
fm.mock((url, opts) => opts.body === 'a string', 200).catch();
await fm.fetchHandler('http://a.com/logged-in');
expect(fm.calls(true).length).to.equal(0);
await fm.fetchHandler('http://a.com/logged-in', {
method: 'post',
body: 'a string',
});
expect(fm.calls(true).length).to.equal(1);
});

it('match using custom function with Request', async () => {
fm.mock((url, options) => {
return url.indexOf('logged-in') > -1 && options.headers.authorized;
}, 200).catch();

await fm.fetchHandler(
new fm.config.Request('http://a.com/logged-in', {
headers: { authorized: 'true' },
})
);
expect(fm.calls(true).length).to.equal(1);
});

// Following test works in latest chrome but not in v62 in CI
let itInDev = it;

try {
/Chrome\/62/.test(window.navigator.appVersion) && (itInDev = it.skip);
} catch (err) {}

itInDev(
'match using custom function with Request with unusual options',
async () => {
// as node-fetch does not try to emulate all the WHATWG standards, we can't check for the
// same properties in the browser and nodejs
const propertyToCheck = new fm.config.Request('http://example.com').cache
? 'credentials'
: 'timeout';
const valueToSet = propertyToCheck === 'credentials' ? 'include' : 2000;

fm.mock(
(url, options, request) => request[propertyToCheck] === valueToSet,
200
).catch();

await fm.fetchHandler(new fm.config.Request('http://a.com/logged-in'));
expect(fm.calls(true).length).to.equal(0);
await fm.fetchHandler(
new fm.config.Request('http://a.com/logged-in', {
[propertyToCheck]: valueToSet,
})
);
expect(fm.calls(true).length).to.equal(1);
}
);

it('match using custom function alongside other matchers', async () => {
fm.mock('end:profile', 200, {
functionMatcher: (url, opts) => {
return opts && opts.headers && opts.headers.authorized === true;
},
}).catch();

await fm.fetchHandler('http://a.com/profile');
expect(fm.calls(true).length).to.equal(0);
await fm.fetchHandler('http://a.com/not', {
headers: { authorized: true },
});
expect(fm.calls(true).length).to.equal(0);
await fm.fetchHandler('http://a.com/profile', {
headers: { authorized: true },
});
expect(fm.calls(true).length).to.equal(1);
});
});
Loading

0 comments on commit 0d48926

Please sign in to comment.