1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-30 22:21:13 +03:00

mock websockets; test useWsJobs

This commit is contained in:
Keith Grant 2020-06-15 14:24:44 -07:00
parent 48977e50df
commit 0bedd6fbd8
6 changed files with 165 additions and 21 deletions

View File

@ -8988,6 +8988,12 @@
}
}
},
"jest-websocket-mock": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/jest-websocket-mock/-/jest-websocket-mock-2.0.2.tgz",
"integrity": "sha512-SFTUI8O/LDGqROOMnfAzbrrX5gQ8GDhRqkzVrt8Y67evnFKccRPFI3ymS05tKcMONvVfxumat4pX/LRjM/CjVg==",
"dev": true
},
"jest-worker": {
"version": "24.9.0",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
@ -9893,6 +9899,15 @@
"minimist": "^1.2.5"
}
},
"mock-socket": {
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.0.3.tgz",
"integrity": "sha512-SxIiD2yE/By79p3cNAAXyLQWTvEFNEzcAO7PH+DzRqKSFaplAPFjiQLmw8ofmpCsZf+Rhfn2/xCJagpdGmYdTw==",
"dev": true,
"requires": {
"url-parse": "^1.4.4"
}
},
"moo": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz",

View File

@ -72,6 +72,8 @@
"eslint-plugin-react": "^7.11.1",
"eslint-plugin-react-hooks": "^2.2.0",
"http-proxy-middleware": "^1.0.3",
"jest-websocket-mock": "^2.0.2",
"mock-socket": "^9.0.3",
"prettier": "^1.18.2"
},
"jest": {

View File

@ -0,0 +1,21 @@
import { useState, useEffect, useRef } from 'react';
export default function useThrottle(value, limit) {
const [throttledValue, setThrottledValue] = useState(value);
const lastRan = useRef(Date.now());
useEffect(() => {
const handler = setTimeout(() => {
if (Date.now() - lastRan.current >= limit) {
setThrottledValue(value);
lastRan.current = Date.now();
}
}, limit - (Date.now() - lastRan.current));
return () => {
clearTimeout(handler);
};
}, [value, limit]);
return throttledValue;
}

View File

@ -1,10 +1,10 @@
import { useState, useEffect, useRef } from 'react';
import useThrottle from './useThrottle';
export default function useWsJobs(initialJobs, fetchJobsById, filtersApplied) {
const [jobs, setJobs] = useState(initialJobs);
const [lastMessage, setLastMessage] = useState(null);
const [jobsToFetch, setJobsToFetch] = useState([]);
// const debouncedJobsToFetch = useDebounce(jobsToFetch, 5000);
const throttleJobsToFetch = useThrottle(jobsToFetch, 5000);
useEffect(() => {
@ -101,23 +101,3 @@ function updateJob(jobs, index, message) {
};
return [...jobs.slice(0, index), job, ...jobs.slice(index + 1)];
}
function useThrottle(value, limit) {
const [throttledValue, setThrottledValue] = useState(value);
const lastRan = useRef(Date.now());
useEffect(() => {
const handler = setTimeout(() => {
if (Date.now() - lastRan.current >= limit) {
setThrottledValue(value);
lastRan.current = Date.now();
}
}, limit - (Date.now() - lastRan.current));
return () => {
clearTimeout(handler);
};
}, [value, limit]);
return throttledValue;
}

View File

@ -0,0 +1,126 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { mount } from 'enzyme';
import WS from 'jest-websocket-mock';
import useWsJobs from './useWsJobs';
/*
Jest mock timers dont play well with jest-websocket-mock,
so we'll stub out throttling to resolve immediately
*/
jest.mock('./useThrottle', () => ({
__esModule: true,
default: jest.fn(val => val),
}));
function TestInner() {
return <div />;
}
function Test({ jobs, fetch }) {
const syncedJobs = useWsJobs(jobs, fetch);
return <TestInner jobs={syncedJobs} />;
}
describe('useWsJobs hook', () => {
let debug;
let wrapper;
beforeEach(() => {
debug = global.console.debug; // eslint-disable-line prefer-destructuring
global.console.debug = () => {};
});
afterEach(() => {
global.console.debug = debug;
});
test('should return jobs list', () => {
const jobs = [{ id: 1 }];
wrapper = mount(<Test jobs={jobs} />);
expect(wrapper.find('TestInner').prop('jobs')).toEqual(jobs);
WS.clean();
});
test('should establish websocket connection', async () => {
global.document.cookie = 'csrftoken=abc123';
const mockServer = new WS('wss://localhost/websocket/');
const jobs = [{ id: 1 }];
await act(async () => {
wrapper = await mount(<Test jobs={jobs} />);
});
await mockServer.connected;
await expect(mockServer).toReceiveMessage(
JSON.stringify({
xrftoken: 'abc123',
groups: {
jobs: ['status_changed'],
schedules: ['changed'],
control: ['limit_reached_1'],
},
})
);
WS.clean();
});
test('should update job status', async () => {
global.document.cookie = 'csrftoken=abc123';
const mockServer = new WS('wss://localhost/websocket/');
const jobs = [{ id: 1, status: 'running' }];
await act(async () => {
wrapper = await mount(<Test jobs={jobs} />);
});
await mockServer.connected;
await expect(mockServer).toReceiveMessage(
JSON.stringify({
xrftoken: 'abc123',
groups: {
jobs: ['status_changed'],
schedules: ['changed'],
control: ['limit_reached_1'],
},
})
);
expect(wrapper.find('TestInner').prop('jobs')[0].status).toEqual('running');
act(() => {
mockServer.send(
JSON.stringify({
unified_job_id: 1,
status: 'successful',
})
);
});
wrapper.update();
expect(wrapper.find('TestInner').prop('jobs')[0].status).toEqual(
'successful'
);
WS.clean();
});
test('should fetch new job', async () => {
global.document.cookie = 'csrftoken=abc123';
const mockServer = new WS('wss://localhost/websocket/');
const jobs = [{ id: 1 }];
const fetch = jest.fn();
await act(async () => {
wrapper = await mount(<Test jobs={jobs} fetch={fetch} />);
});
await mockServer.connected;
act(() => {
mockServer.send(
JSON.stringify({
unified_job_id: 2,
status: 'running',
})
);
});
expect(fetch).toHaveBeenCalledWith([2]);
WS.clean();
});
});