Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# data-mocks

# modified by aiden for websocket support.
# will hopefully be deleted soon when merged in to upstream

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also write usage

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you fix this up?

[![GitHub license](https://img.shields.io/github/license/ovotech/data-mocks.svg)](https://github.com/grug/data-mocks)
![npm](https://img.shields.io/npm/dm/data-mocks.svg)

Expand Down
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'jsdom'
testEnvironment: 'jsdom',
verbose: true,
};
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"name": "data-mocks",
"version": "4.1.0",
"name": "@ovotech/data-mocks",
"version": "4.2.1",
"main": "dist/mocks.js",
"types": "dist/types.d.ts",
"repository": "[email protected]:grug/data-mocks.git",
"repository": "[email protected]:aidenscott2016/data-mocks.git",
"author": "Dave Cooper <[email protected]>",
"license": "MIT",
"homepage": "https://github.com/grug/data-mocks",
"homepage": "https://github.com/aidenscott2016/data-mocks",
"scripts": {
"clean": "rimraf dist",
"prepublishOnly": "yarn build",
Expand All @@ -23,6 +23,7 @@
},
"dependencies": {
"fetch-mock": "^9.4.0",
"mock-socket": "^9.0.3",
"query-string": "^5.1.1",
"xhr-mock": "^2.5.1"
},
Expand Down
127 changes: 121 additions & 6 deletions src/mocks.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,65 @@
import 'isomorphic-fetch';
import axios from 'axios';
import fetchMock from 'fetch-mock';
import 'isomorphic-fetch';
import { Server as MockSever } from 'mock-socket';
import XHRMock, { proxy } from 'xhr-mock';
import {
injectMocks,
extractScenarioFromLocation,
injectMocks,
reduceAllMocksForScenario,
} from './mocks';
import { HttpMethod, Scenarios, MockConfig } from './types';
import XHRMock, { proxy } from 'xhr-mock';
import fetchMock from 'fetch-mock';
import { HttpMethod, MockConfig, Scenarios } from './types';

describe('data-mocks', () => {
beforeEach(() => {
fetchMock.resetHistory();
});

describe('Websockets', () => {
const testURL = 'ws://localhost/foo';
it('Spawns a working websocket server', async () => {
const onMessage = jest.fn();
const onConnect = jest.fn();
const scenarios: Scenarios = {
default: [
{
url: testURL,
method: 'WEBSOCKET',
server: (s) => {
s.on('connection', (socket) => {
console.log('conneted');
onConnect();
socket.on('message', (req) => {
onMessage();
socket.send(req.toString());
s.close();
});
});
},
},
],
};
injectMocks(scenarios, 'default');

const socket = new WebSocket(testURL);
let res;
socket.addEventListener('message', (data) => {
res = data.data;
socket.close();
});

await awaitSocket(socket, WebSocket.OPEN);
expect(onConnect).toBeCalled();

const message = 'hello world';
socket.send(message);
await awaitSocket(socket, WebSocket.CLOSED);
expect(onMessage).toBeCalled();

expect(res).toEqual(message);
});
});

describe('REST', () => {
describe('HTTP methods', () => {
const httpMethods: HttpMethod[] = [
Expand Down Expand Up @@ -50,7 +96,6 @@ describe('data-mocks', () => {
const xhrSpy = jest.spyOn(XHRMock, httpMethod.toLowerCase() as any);

injectMocks(scenarios, 'default');

expect(fetchSpy).toHaveBeenCalledTimes(2);
expect(fetchSpy.mock.calls[0][0]).toEqual(/foo/);
expect(fetchSpy.mock.calls[1][0]).toEqual(/bar/);
Expand Down Expand Up @@ -282,6 +327,8 @@ describe('data-mocks', () => {
});

describe('Scenarios', () => {
const websocketServerFn = jest.fn();
const anotherServerFn = jest.fn();
const scenarios: Scenarios = {
default: [
{
Expand All @@ -299,6 +346,22 @@ describe('data-mocks', () => {
responseHeaders: { token: 'bar' },
},
{ url: /bar/, method: 'POST', response: {}, responseCode: 200 },
{
url: /graphql/,
method: 'GRAPHQL',
operations: [
{
operationName: 'Query',
type: 'query',
response: { data: { test: 'data' } },
},
],
},
{
url: 'ws://localhost',
method: 'WEBSOCKET',
server: websocketServerFn,
},
],
someScenario: [
{
Expand All @@ -308,6 +371,18 @@ describe('data-mocks', () => {
responseCode: 401,
},
{ url: /baz/, method: 'POST', response: {}, responseCode: 200 },
{
url: /graphql/,
method: 'GRAPHQL',
operations: [
{
operationName: 'Query',
type: 'query',
response: { data: { test: 'different data' } },
},
],
},
{ url: 'ws://localhost', method: 'WEBSOCKET', server: anotherServerFn },
],
};

Expand Down Expand Up @@ -340,6 +415,22 @@ describe('data-mocks', () => {
responseHeaders: { token: 'bar' },
},
{ url: /bar/, method: 'POST', response: {}, responseCode: 200 },
{
url: /graphql/,
method: 'GRAPHQL',
operations: [
{
operationName: 'Query',
type: 'query',
response: { data: { test: 'data' } },
},
],
},
{
url: 'ws://localhost',
method: 'WEBSOCKET',
server: websocketServerFn,
},
]);
});

Expand Down Expand Up @@ -367,6 +458,18 @@ describe('data-mocks', () => {
responseCode: 200,
},
{ url: /baz/, method: 'POST', response: {}, responseCode: 200 },
{
url: /graphql/,
method: 'GRAPHQL',
operations: [
{
operationName: 'Query',
type: 'query',
response: { data: { test: 'different data' } },
},
],
},
{ url: 'ws://localhost', method: 'WEBSOCKET', server: anotherServerFn },
]);
});

Expand Down Expand Up @@ -536,3 +639,15 @@ describe('data-mocks', () => {
});
});
});

const awaitSocket = (socket, state) => {
return new Promise(function (resolve) {
setTimeout(function () {
if (socket.readyState === state) {
resolve(true);
} else {
awaitSocket(socket, state).then(resolve);
}
}, 1000);
});
};
37 changes: 31 additions & 6 deletions src/mocks.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import fetchMock from 'fetch-mock';
import XHRMock, { delay as xhrMockDelay, proxy } from 'xhr-mock';
import { parse } from 'query-string';
import { Server as MockServer } from 'mock-socket';
import {
Scenarios,
MockConfig,
Mock,
HttpMock,
GraphQLMock,
Operation,
WebSocketMock,
} from './types';

/**
Expand Down Expand Up @@ -44,13 +46,20 @@ export const injectMocks = (
throw new Error('Unable to instantiate mocks');
}

const restMocks = mocks.filter((m) => m.method !== 'GRAPHQL') as HttpMock[];
const restMocks = mocks.filter(
(m) => !['GRAPHQL', 'WEBSOCKET'].includes(m.method)
) as HttpMock[];
const graphQLMocks = mocks.filter(
(m) => m.method === 'GRAPHQL'
) as GraphQLMock[];

const webSocketMocks = mocks.filter(
(m) => m.method === 'WEBSOCKET'
) as WebSocketMock[];

restMocks.forEach(handleRestMock);
graphQLMocks.forEach(handleGraphQLMock);
webSocketMocks.forEach(handleWebsocketMock);

if (config?.allowXHRPassthrough) {
XHRMock.use(proxy);
Expand Down Expand Up @@ -79,12 +88,24 @@ export const reduceAllMocksForScenario = (
const mocks = defaultMocks.concat(scenarioMocks);

const initialHttpMocks = mocks.filter(
({ method }) => method !== 'GRAPHQL'
(m) => !['GRAPHQL', 'WEBSOCKET'].includes(m.method)
) as HttpMock[];
const initialGraphQlMocks = mocks.filter(
({ method }) => method === 'GRAPHQL'
) as GraphQLMock[];

const initialWebsocketMocks = mocks.filter(
(m) => m.method === 'WEBSOCKET'
) as WebSocketMock[];

const websocketMocksByUrl = initialWebsocketMocks.reduce<
Record<string, WebSocketMock>
>((result, mock) => {
const { url } = mock;
result[url] = mock;
return result;
}, {});

const httpMocksByUrlAndMethod = initialHttpMocks.reduce<
Record<string, HttpMock>
>((result, mock) => {
Expand Down Expand Up @@ -130,7 +151,9 @@ export const reduceAllMocksForScenario = (
}
) as GraphQLMock[];

return (httpMocks as any).concat(graphQlMocks);
const websocketMocks = Object.values(websocketMocksByUrl);

return [...httpMocks, ...graphQlMocks, ...websocketMocks];
};

/**
Expand All @@ -149,7 +172,6 @@ function handleRestMock({
status: responseCode,
headers: responseHeaders,
};

switch (method) {
case 'GET':
fetchMock.get(url, () => addDelay(delay).then(() => finalResponse), {
Expand Down Expand Up @@ -188,8 +210,7 @@ function handleRestMock({
}
}

/**
* Mocks the right HTTP method for a GraphQL mock.
/** const graphQLMocks = mocks.filter(ethod for a GraphQL mock.
*/
function handleGraphQLMock({ url, operations }: GraphQLMock) {
const graphQLErrorResponse = { errors: [] };
Expand Down Expand Up @@ -281,6 +302,10 @@ function handleGraphQLMock({ url, operations }: GraphQLMock) {
});
}

const handleWebsocketMock = ({ url, server }: WebSocketMock) => {
server(new MockServer(url));
};

/**
* Adds delay (in ms) before resolving a promise.
*/
Expand Down
10 changes: 9 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export {
injectMocks,
reduceAllMocksForScenario,
} from './mocks';
import { Server as MockServer } from 'mock-socket';

export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';

Expand All @@ -27,6 +28,13 @@ export type GraphQLMock = {
operations: Array<Operation>;
};

export type WebSocketServerMock = (mockServer: MockServer) => void;
export type WebSocketMock = {
url: string;
method: 'WEBSOCKET';
server: WebSocketServerMock;
};

export type Operation = {
type: 'query' | 'mutation';
operationName: string;
Expand All @@ -36,7 +44,7 @@ export type Operation = {
delay?: number;
};

export type Mock = HttpMock | GraphQLMock;
export type Mock = HttpMock | GraphQLMock | WebSocketMock;

export type Scenarios = {
default: Mock[];
Expand Down
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"removeComments": true /* Do not emit comments to output. */,
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": false /* Raise error on expressions and declarations with an implied 'any' type. */,
"noUnusedLocals": true /* Report errors on unused locals. */,
"noUnusedParameters": true /* Report errors on unused parameters. */,
"noUnusedLocals": false /* Report errors on unused locals. */,
"noUnusedParameters": false /* Report errors on unused parameters. */,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change me

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change comes from within, brother 😌

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inshallah

"lib": ["es2017", "dom"],
"esModuleInterop": true
},
Expand Down
Loading