Skip to content

Commit

Permalink
feat: QA-14 Implemented matching most recently added mock first.
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Changed order for adding mocks - newest first.
  • Loading branch information
pawfa committed Jul 26, 2019
1 parent 9be9418 commit 9699ef0
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 109 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ await mocketeer.activate(page);
#### .mockREST(filter: RequestFilter, response: MockedResponse, options?): RestMock

Respond to xhr and fetch requests that match the `filter` with provided `response`.
Request are matched based on adding order - most recently added first.
Pass query params through `query` argument in `filter` object or simply append text to `url`

###### Arguments
Expand Down Expand Up @@ -220,6 +221,7 @@ mocketeer.mockREST(
#### .mockDELETE(filter: RequestMethodFilter | string, response: MockedResponse, options?): RestMock

Respond to xhr and fetch requests with adequate rest method that match the `filter` with provided `response`.
Request are matched based on adding order - most recently added first.
Pass `filter` as an object or as an `url` string.
Pass query params through `query` argument in `filter` object or simply append text to `url`

Expand Down
10 changes: 6 additions & 4 deletions src/mocketeer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
RequestMethodFilter,
REST_METHOD,
} from './types';
import { printRequest, requestToPlainObject } from './utils';
import { addMockByPriority, printRequest, requestToPlainObject } from './utils';

const interceptedTypes: ResourceType[] = ['xhr', 'fetch'];

Expand Down Expand Up @@ -59,7 +59,8 @@ export class Mocketeer {
const mock = new RestMock(filter, response, {
...options,
});
this.mocks.push(mock);

addMockByPriority(this.mocks, mock);
return mock;
}

Expand All @@ -71,7 +72,8 @@ export class Mocketeer {
const mock = new RestMock(filter, response, {
...options,
});
this.mocks.push(mock);

addMockByPriority(this.mocks, mock);
return mock;
}

Expand Down Expand Up @@ -172,7 +174,7 @@ export class Mocketeer {
const { protocol, host } = parse(originFrameUrl);
const origin = `${protocol}//${host}`;

for (const mock of this.mocks.sort(RestMock.sortByPriority)) {
for (const mock of this.mocks) {
const response = mock.getResponseForRequest(requestData, origin);

if (response) {
Expand Down
6 changes: 1 addition & 5 deletions src/rest-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class RestMock implements IMock {
private filter: ParsedFilterRequest;
private response: MockedResponse;
private requests: Array<MatchedRequest> = [];
private options: MockOptions = {
public options: MockOptions = {
priority: 0,
once: false,
};
Expand Down Expand Up @@ -182,10 +182,6 @@ export class RestMock implements IMock {
});
}

public static sortByPriority(a: RestMock, b: RestMock) {
return b.options.priority - a.options.priority;
}

private prettyPrint(): string {
const qs = stringify(this.filter.query);
return `(${this.debugId}) ${this.filter.method} ${this.filter.path +
Expand Down
12 changes: 12 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,15 @@ export function nth(d: number): string {
return `${d}th`;
}
}

export function addMockByPriority<T extends { options: { priority: number } }>(
mockArr: T[],
mock: T
) {
const index = mockArr.findIndex(
(item: T) => item.options.priority <= mock.options.priority
);
const calculatedIndex = index === -1 ? mockArr.length : index;
mockArr.splice(calculatedIndex, 0, mock);
return mockArr;
}
194 changes: 160 additions & 34 deletions test/integration/mocketeer.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,47 +467,173 @@ describe('Mocketeer integration', () => {
await expect(mock.getRequest()).resolves.toEqual(expect.anything());
});

it('matches only once request with once set to true', async () => {
spyOn(console, 'error');
await mocketeer.mockREST(requestGetFoo, response200Ok, { once: true });
describe('ordering', () => {
const makeRequest = () =>
page.evaluate(() => fetch('/foo').then(res => res.status));

const response = await page.evaluate(() =>
fetch('/foo').then(res => res.json())
);
it('matches only once request with once set to true', async () => {
spyOn(console, 'error');
await mocketeer.mockREST(requestGetFoo, response200Ok, {
once: true,
});

await expect(response).toEqual(response200Ok.body);
await expect(makeRequest()).resolves.toBe(200);

const statusCode = await page.evaluate(() =>
fetch('/foo').then(res => res.status)
);
await expect(statusCode).toBe(404);
expect(console.error).toHaveBeenCalled();
});
await expect(makeRequest()).resolves.toBe(404);
expect(console.error).toHaveBeenCalled();
});

it('matches only once every request in order with once set to true', async () => {
await mocketeer.mockREST(
requestGetFoo,
{ status: 200, body: {} },
{ once: true }
);
await mocketeer.mockREST(
requestGetFoo,
{ status: 201, body: {} },
{
once: true,
}
);
it('matches only once request with once set to true', async () => {
await mocketeer.mockREST(requestGetFoo, { status: 200, body: {} });

const firstResponseStatus = await page.evaluate(() =>
fetch('/foo').then(res => res.status)
);
await mocketeer.mockREST(
requestGetFoo,
{ status: 201, body: {} },
{
once: true,
}
);

await expect(firstResponseStatus).toBe(200);
await expect(makeRequest()).resolves.toBe(201);
await expect(makeRequest()).resolves.toBe(200);
await expect(makeRequest()).resolves.toBe(200);
});

const secondResponseStatus = await page.evaluate(() =>
fetch('/foo').then(res => res.status)
);
it('matches only once every request in order with once set to true', async () => {
await mocketeer.mockREST(
requestGetFoo,
{ status: 200, body: {} },
{ once: true }
);

await mocketeer.mockREST(
requestGetFoo,
{ status: 201, body: {} },
{
once: true,
}
);

await expect(makeRequest()).resolves.toBe(201);
await expect(makeRequest()).resolves.toBe(200);
});

it('matches newest request when added mock with same filter', async () => {
await mocketeer.mockREST(requestGetFoo, { status: 200, body: {} });
await expect(makeRequest()).resolves.toBe(200);

await mocketeer.mockREST(requestGetFoo, { status: 201, body: {} });
await expect(makeRequest()).resolves.toBe(201);
});

it('matches newest request when multiple mocks have same filter', async () => {
await mocketeer.mockREST(requestGetFoo, { status: 200, body: {} });
await mocketeer.mockREST(requestGetFoo, { status: 201, body: {} });

await expect(makeRequest()).resolves.toBe(201);
});

it('matches newest request when added mock with same filter and older mock has once set to true ', async () => {
await mocketeer.mockREST(
requestGetFoo,
{ status: 200, body: {} },
{ once: true }
);
await expect(makeRequest()).resolves.toBe(200);

await expect(secondResponseStatus).toBe(201);
await mocketeer.mockREST(requestGetFoo, { status: 201, body: {} });
await expect(makeRequest()).resolves.toBe(201);
});

it('matches requests with once set to true in correct order when multiple mocks have same filter', async () => {
await mocketeer.mockREST(
requestGetFoo,
{ status: 200, body: {} },
{ once: true }
);

await mocketeer.mockREST(
requestGetFoo,
{ status: 201, body: {} },
{
once: true,
}
);

await mocketeer.mockREST(
requestGetFoo,
{ status: 202, body: {} },
{
once: true,
}
);

await expect(makeRequest()).resolves.toBe(202);
await expect(makeRequest()).resolves.toBe(201);
await expect(makeRequest()).resolves.toBe(200);
});

it('matches request with highest priority when multiple mocks have same filter', async () => {
await mocketeer.mockREST(
requestGetFoo,
{ status: 200, body: {} },
{ priority: 10 }
);

await mocketeer.mockREST(requestGetFoo, { status: 201, body: {} });

await mocketeer.mockREST(
requestGetFoo,
{ status: 202, body: {} },
{ priority: 5 }
);

await expect(makeRequest()).resolves.toBe(200);
});

it('matches request in correct order with priority and once set to true when multiple mocks have same filter', async () => {
await mocketeer.mockREST(
requestGetFoo,
{ status: 200, body: {} },
{ once: true }
);

await mocketeer.mockREST(
requestGetFoo,
{ status: 201, body: {} },
{ once: true, priority: 10 }
);

await mocketeer.mockREST(
requestGetFoo,
{ status: 202, body: {} },
{ once: true }
);

await mocketeer.mockREST(
requestGetFoo,
{ status: 203, body: {} },
{ once: true, priority: 10 }
);

await mocketeer.mockREST(
requestGetFoo,
{ status: 204, body: {} },
{ once: true, priority: 5 }
);

await mocketeer.mockREST(
requestGetFoo,
{ status: 205, body: {} },
{ once: true }
);

await expect(makeRequest()).resolves.toBe(203);
await expect(makeRequest()).resolves.toBe(201);
await expect(makeRequest()).resolves.toBe(204);
await expect(makeRequest()).resolves.toBe(205);
await expect(makeRequest()).resolves.toBe(202);
await expect(makeRequest()).resolves.toBe(200);
});
});
});
21 changes: 21 additions & 0 deletions test/unit/fixtures/request.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Request } from 'puppeteer';
import { MockOptions, RequestFilter, RestMock } from '../../../src';

export const createMockRequest = (): jest.Mocked<Request> => ({
postData: jest.fn().mockReturnValue(''),
Expand All @@ -19,3 +20,23 @@ export const createMockRequest = (): jest.Mocked<Request> => ({
const a = createMockRequest();

a.headers.mockReturnValue({ a: '' });

const mockedResponse = {
status: 200,
body: {},
};

export const createRestMock = (
change: Partial<RequestFilter> = {},
options?: Partial<MockOptions>
) => {
return new RestMock(
{
url: '/foo',
method: 'GET',
...change,
},
mockedResponse,
options
);
};
Loading

0 comments on commit 9699ef0

Please sign in to comment.