mirror of
https://github.com/ansible/awx.git
synced 2026-04-05 01:59:25 -02:30
mock websockets; test useWsJobs
This commit is contained in:
15
awx/ui_next/package-lock.json
generated
15
awx/ui_next/package-lock.json
generated
@@ -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": {
|
"jest-worker": {
|
||||||
"version": "24.9.0",
|
"version": "24.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
|
||||||
@@ -9893,6 +9899,15 @@
|
|||||||
"minimist": "^1.2.5"
|
"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": {
|
"moo": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz",
|
||||||
|
|||||||
@@ -72,6 +72,8 @@
|
|||||||
"eslint-plugin-react": "^7.11.1",
|
"eslint-plugin-react": "^7.11.1",
|
||||||
"eslint-plugin-react-hooks": "^2.2.0",
|
"eslint-plugin-react-hooks": "^2.2.0",
|
||||||
"http-proxy-middleware": "^1.0.3",
|
"http-proxy-middleware": "^1.0.3",
|
||||||
|
"jest-websocket-mock": "^2.0.2",
|
||||||
|
"mock-socket": "^9.0.3",
|
||||||
"prettier": "^1.18.2"
|
"prettier": "^1.18.2"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
|
|||||||
21
awx/ui_next/src/components/JobList/useThrottle.js
Normal file
21
awx/ui_next/src/components/JobList/useThrottle.js
Normal 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;
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useState, useEffect, useRef } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
|
import useThrottle from './useThrottle';
|
||||||
|
|
||||||
export default function useWsJobs(initialJobs, fetchJobsById, filtersApplied) {
|
export default function useWsJobs(initialJobs, fetchJobsById, filtersApplied) {
|
||||||
const [jobs, setJobs] = useState(initialJobs);
|
const [jobs, setJobs] = useState(initialJobs);
|
||||||
const [lastMessage, setLastMessage] = useState(null);
|
const [lastMessage, setLastMessage] = useState(null);
|
||||||
const [jobsToFetch, setJobsToFetch] = useState([]);
|
const [jobsToFetch, setJobsToFetch] = useState([]);
|
||||||
// const debouncedJobsToFetch = useDebounce(jobsToFetch, 5000);
|
|
||||||
const throttleJobsToFetch = useThrottle(jobsToFetch, 5000);
|
const throttleJobsToFetch = useThrottle(jobsToFetch, 5000);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -101,23 +101,3 @@ function updateJob(jobs, index, message) {
|
|||||||
};
|
};
|
||||||
return [...jobs.slice(0, index), job, ...jobs.slice(index + 1)];
|
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;
|
|
||||||
}
|
|
||||||
|
|||||||
126
awx/ui_next/src/components/JobList/useWsJobs.test.jsx
Normal file
126
awx/ui_next/src/components/JobList/useWsJobs.test.jsx
Normal 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 don’t 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user