mirror of
https://github.com/ansible/awx.git
synced 2026-03-09 05:29:26 -02:30
Add JobOutput tests
This commit is contained in:
39
awx/ui_next/package-lock.json
generated
39
awx/ui_next/package-lock.json
generated
@@ -2307,6 +2307,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||||
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
|
||||||
},
|
},
|
||||||
|
"ansi-to-html": {
|
||||||
|
"version": "0.6.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.11.tgz",
|
||||||
|
"integrity": "sha512-88XZtrcwrfkyn6fGstHnkaF1kl7hGtNCYh4vSmItgEV+6JnQHryDBf7udF4f2RhTRQmYvJvPcTtqgaqrxzc9oA==",
|
||||||
|
"requires": {
|
||||||
|
"entities": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ansi-wrap": {
|
"ansi-wrap": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
|
||||||
@@ -4242,6 +4250,16 @@
|
|||||||
"has-ansi": "^2.0.0",
|
"has-ansi": "^2.0.0",
|
||||||
"strip-ansi": "^3.0.0",
|
"strip-ansi": "^3.0.0",
|
||||||
"supports-color": "^2.0.0"
|
"supports-color": "^2.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"has-ansi": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"chardet": {
|
"chardet": {
|
||||||
@@ -5680,8 +5698,7 @@
|
|||||||
"entities": {
|
"entities": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
|
||||||
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
|
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"enzyme": {
|
"enzyme": {
|
||||||
"version": "3.9.0",
|
"version": "3.9.0",
|
||||||
@@ -7953,11 +7970,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"has-ansi": {
|
"has-ansi": {
|
||||||
"version": "2.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-3.0.0.tgz",
|
||||||
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
"integrity": "sha1-Ngd+8dFfMzSEqn+neihgbxxlWzc=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
@@ -8170,8 +8194,7 @@
|
|||||||
"html-entities": {
|
"html-entities": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
|
||||||
"integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=",
|
"integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"html-tokenize": {
|
"html-tokenize": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import ContentError from '@components/ContentError';
|
|||||||
import ContentLoading from '@components/ContentLoading';
|
import ContentLoading from '@components/ContentLoading';
|
||||||
import JobEvent from './JobEvent';
|
import JobEvent from './JobEvent';
|
||||||
import JobEventSkeleton from './JobEventSkeleton';
|
import JobEventSkeleton from './JobEventSkeleton';
|
||||||
import MenuControls from './shared/MenuControls';
|
import MenuControls from './MenuControls';
|
||||||
|
|
||||||
const OutputHeader = styled.div`
|
const OutputHeader = styled.div`
|
||||||
font-weight: var(--pf-global--FontWeight--bold);
|
font-weight: var(--pf-global--FontWeight--bold);
|
||||||
@@ -52,7 +52,7 @@ function range(low, high) {
|
|||||||
class JobOutput extends Component {
|
class JobOutput extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.listRef = React.createRef();
|
||||||
this.state = {
|
this.state = {
|
||||||
contentError: null,
|
contentError: null,
|
||||||
hasContentLoading: true,
|
hasContentLoading: true,
|
||||||
@@ -68,13 +68,14 @@ class JobOutput extends Component {
|
|||||||
|
|
||||||
this.loadJobEvents = this.loadJobEvents.bind(this);
|
this.loadJobEvents = this.loadJobEvents.bind(this);
|
||||||
this.rowRenderer = this.rowRenderer.bind(this);
|
this.rowRenderer = this.rowRenderer.bind(this);
|
||||||
this.handleScrollTop = this.handleScrollTop.bind(this);
|
this.handleScrollFirst = this.handleScrollFirst.bind(this);
|
||||||
this.handleScrollBottom = this.handleScrollBottom.bind(this);
|
this.handleScrollLast = this.handleScrollLast.bind(this);
|
||||||
this.handleScrollNext = this.handleScrollNext.bind(this);
|
this.handleScrollNext = this.handleScrollNext.bind(this);
|
||||||
this.handleScrollPrevious = this.handleScrollPrevious.bind(this);
|
this.handleScrollPrevious = this.handleScrollPrevious.bind(this);
|
||||||
this.handleResize = this.handleResize.bind(this);
|
this.handleResize = this.handleResize.bind(this);
|
||||||
this.isRowLoaded = this.isRowLoaded.bind(this);
|
this.isRowLoaded = this.isRowLoaded.bind(this);
|
||||||
this.loadMoreRows = this.loadMoreRows.bind(this);
|
this.loadMoreRows = this.loadMoreRows.bind(this);
|
||||||
|
this.scrollToRow = this.scrollToRow.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -93,12 +94,12 @@ class JobOutput extends Component {
|
|||||||
this.cache.clear(n);
|
this.cache.clear(n);
|
||||||
});
|
});
|
||||||
if (shouldRecomputeRowHeights) {
|
if (shouldRecomputeRowHeights) {
|
||||||
this.listRef.recomputeRowHeights();
|
if (this.listRef.recomputeRowHeights) {
|
||||||
|
this.listRef.recomputeRowHeights();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listRef = React.createRef();
|
|
||||||
|
|
||||||
async loadJobEvents() {
|
async loadJobEvents() {
|
||||||
const { job } = this.props;
|
const { job } = this.props;
|
||||||
|
|
||||||
@@ -193,25 +194,29 @@ class JobOutput extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scrollToRow(rowIndex) {
|
||||||
|
this.listRef.scrollToRow(rowIndex);
|
||||||
|
}
|
||||||
|
|
||||||
handleScrollPrevious() {
|
handleScrollPrevious() {
|
||||||
const startIndex = this.listRef.Grid._renderedRowStartIndex;
|
const startIndex = this.listRef.Grid._renderedRowStartIndex;
|
||||||
const stopIndex = this.listRef.Grid._renderedRowStopIndex;
|
const stopIndex = this.listRef.Grid._renderedRowStopIndex;
|
||||||
const scrollRange = stopIndex - startIndex + 1;
|
const scrollRange = stopIndex - startIndex + 1;
|
||||||
this.listRef.scrollToRow(Math.max(0, startIndex - scrollRange));
|
this.scrollToRow(Math.max(0, startIndex - scrollRange));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleScrollNext() {
|
handleScrollNext() {
|
||||||
const stopIndex = this.listRef.Grid._renderedRowStopIndex;
|
const stopIndex = this.listRef.Grid._renderedRowStopIndex;
|
||||||
this.listRef.scrollToRow(stopIndex - 1);
|
this.scrollToRow(stopIndex - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleScrollTop() {
|
handleScrollFirst() {
|
||||||
this.listRef.scrollToRow(0);
|
this.scrollToRow(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleScrollBottom() {
|
handleScrollLast() {
|
||||||
const { remoteRowCount } = this.state;
|
const { remoteRowCount } = this.state;
|
||||||
this.listRef.scrollToRow(remoteRowCount - 1);
|
this.scrollToRow(remoteRowCount - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleResize({ width }) {
|
handleResize({ width }) {
|
||||||
@@ -239,8 +244,8 @@ class JobOutput extends Component {
|
|||||||
<OutputHeader>{job.name}</OutputHeader>
|
<OutputHeader>{job.name}</OutputHeader>
|
||||||
<OutputToolbar>
|
<OutputToolbar>
|
||||||
<MenuControls
|
<MenuControls
|
||||||
onScrollTop={this.handleScrollTop}
|
onScrollFirst={this.handleScrollFirst}
|
||||||
onScrollBottom={this.handleScrollBottom}
|
onScrollLast={this.handleScrollLast}
|
||||||
onScrollNext={this.handleScrollNext}
|
onScrollNext={this.handleScrollNext}
|
||||||
onScrollPrevious={this.handleScrollPrevious}
|
onScrollPrevious={this.handleScrollPrevious}
|
||||||
/>
|
/>
|
||||||
@@ -261,13 +266,13 @@ class JobOutput extends Component {
|
|||||||
registerChild(ref);
|
registerChild(ref);
|
||||||
}}
|
}}
|
||||||
deferredMeasurementCache={this.cache}
|
deferredMeasurementCache={this.cache}
|
||||||
height={height}
|
height={height || 1}
|
||||||
onRowsRendered={onRowsRendered}
|
onRowsRendered={onRowsRendered}
|
||||||
rowCount={remoteRowCount}
|
rowCount={remoteRowCount}
|
||||||
rowHeight={this.cache.rowHeight}
|
rowHeight={this.cache.rowHeight}
|
||||||
rowRenderer={this.rowRenderer}
|
rowRenderer={this.rowRenderer}
|
||||||
scrollToAlignment="start"
|
scrollToAlignment="start"
|
||||||
width={width}
|
width={width || 1}
|
||||||
overscanRowCount={20}
|
overscanRowCount={20}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,48 +1,196 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
|
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
|
||||||
|
|
||||||
import JobOutput from './JobOutput';
|
import JobOutput from './JobOutput';
|
||||||
|
import { JobsAPI } from '@api';
|
||||||
|
import mockJobData from './data.job.json';
|
||||||
|
import mockJobEventsData from './data.job_events.json';
|
||||||
|
|
||||||
|
jest.mock('@api');
|
||||||
|
|
||||||
async function checkOutput(wrapper, expectedLines) {
|
async function checkOutput(wrapper, expectedLines) {
|
||||||
await waitForElement(wrapper, 'div[type="job_event"]', (e) => e.length > 1);
|
await waitForElement(wrapper, 'div[type="job_event"]', e => e.length > 1);
|
||||||
const jobEventLines = wrapper.find('div[type="job_event_line_text"]');
|
const jobEventLines = wrapper.find('div[type="job_event_line_text"]');
|
||||||
const actualLines = [];
|
const actualLines = [];
|
||||||
jobEventLines.forEach(line => {
|
jobEventLines.forEach(line => {
|
||||||
actualLines.push(line.text());
|
actualLines.push(line.text());
|
||||||
});
|
});
|
||||||
|
expect(actualLines.length).toEqual(expectedLines.length);
|
||||||
expectedLines.forEach((line, index) => {
|
expectedLines.forEach((line, index) => {
|
||||||
expect(actualLines[index]).toEqual(line);
|
expect(actualLines[index]).toEqual(line);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('<JobOutput />', () => {
|
async function findScrollButtons(wrapper) {
|
||||||
const mockDetails = {
|
const menuControls = await waitForElement(wrapper, 'MenuControls');
|
||||||
name: 'Foo',
|
const scrollFirstButton = menuControls.find(
|
||||||
|
'button[aria-label="scroll first"]'
|
||||||
|
);
|
||||||
|
const scrollLastButton = menuControls.find(
|
||||||
|
'button[aria-label="scroll last"]'
|
||||||
|
);
|
||||||
|
const scrollPreviousButton = menuControls.find(
|
||||||
|
'button[aria-label="scroll previous"]'
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
scrollFirstButton,
|
||||||
|
scrollLastButton,
|
||||||
|
scrollPreviousButton,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('<JobOutput />', () => {
|
||||||
|
let wrapper;
|
||||||
|
const mockJob = mockJobData;
|
||||||
|
const mockJobEvents = mockJobEventsData;
|
||||||
|
const scrollMock = jest.fn();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
JobsAPI.readEvents.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
count: 100,
|
||||||
|
next: null,
|
||||||
|
previous: null,
|
||||||
|
results: mockJobEvents.results,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
test('initially renders succesfully', async done => {
|
test('initially renders succesfully', async done => {
|
||||||
const wrapper = mountWithContexts(<JobOutput job={mockDetails} />);
|
wrapper = mountWithContexts(<JobOutput job={mockJob} />);
|
||||||
// wait until not loading
|
await waitForElement(wrapper, 'JobEvent', el => el.length > 0);
|
||||||
await waitForElement(wrapper, 'EmptyStateBody', (e) => e.length === 0);
|
await checkOutput(wrapper, [
|
||||||
|
'',
|
||||||
|
'PLAY [all] *********************************************************************11:37:25',
|
||||||
|
'',
|
||||||
|
'TASK [debug] *******************************************************************11:37:25',
|
||||||
|
'ok: [localhost] => (item=1) => {',
|
||||||
|
' "msg": "This is a debug message: 1"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=2) => {',
|
||||||
|
' "msg": "This is a debug message: 2"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=3) => {',
|
||||||
|
' "msg": "This is a debug message: 3"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=4) => {',
|
||||||
|
' "msg": "This is a debug message: 4"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=5) => {',
|
||||||
|
' "msg": "This is a debug message: 5"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=6) => {',
|
||||||
|
' "msg": "This is a debug message: 6"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=7) => {',
|
||||||
|
' "msg": "This is a debug message: 7"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=8) => {',
|
||||||
|
' "msg": "This is a debug message: 8"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=9) => {',
|
||||||
|
' "msg": "This is a debug message: 9"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=10) => {',
|
||||||
|
' "msg": "This is a debug message: 10"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=11) => {',
|
||||||
|
' "msg": "This is a debug message: 11"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=12) => {',
|
||||||
|
' "msg": "This is a debug message: 12"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=13) => {',
|
||||||
|
' "msg": "This is a debug message: 13"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=14) => {',
|
||||||
|
' "msg": "This is a debug message: 14"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=15) => {',
|
||||||
|
' "msg": "This is a debug message: 15"',
|
||||||
|
'}',
|
||||||
|
'ok: [localhost] => (item=16) => {',
|
||||||
|
' "msg": "This is a debug message: 16"',
|
||||||
|
'}',
|
||||||
|
]);
|
||||||
|
|
||||||
// await checkOutput(wrapper, [
|
expect(wrapper.find('JobOutput').length).toBe(1);
|
||||||
// '',
|
done();
|
||||||
// 'PLAY [localhost] ***************************************************************08:00:52',
|
});
|
||||||
// '',
|
|
||||||
// 'TASK [Gathering Facts] *********************************************************08:00:52',
|
test('should call scrollToRow with expected index when scroll "previous" button is clicked', async done => {
|
||||||
// 'ok: [localhost]',
|
const handleScrollPrevious = jest.spyOn(
|
||||||
// '',
|
JobOutput.prototype,
|
||||||
// 'TASK [Check Slack accounts against ldap] ***************************************08:00:53',
|
'handleScrollPrevious'
|
||||||
// 'changed: [localhost]',
|
);
|
||||||
// '',
|
wrapper = mountWithContexts(<JobOutput job={mockJob} />);
|
||||||
// 'TASK [E-mail output] ***********************************************************08:00:58',
|
await waitForElement(wrapper, 'JobEvent', el => el.length > 0);
|
||||||
// 'skipping: [localhost]',
|
const { scrollLastButton, scrollPreviousButton } = await findScrollButtons(
|
||||||
// '',
|
wrapper
|
||||||
// 'PLAY RECAP *********************************************************************08:00:58',
|
);
|
||||||
// 'localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0 ',
|
wrapper.find('JobOutput').instance().scrollToRow = scrollMock;
|
||||||
// '',
|
|
||||||
// ]);
|
scrollLastButton.simulate('click');
|
||||||
|
scrollPreviousButton.simulate('click');
|
||||||
|
|
||||||
|
expect(handleScrollPrevious).toHaveBeenCalled();
|
||||||
|
expect(scrollMock).toHaveBeenCalledTimes(2);
|
||||||
|
expect(scrollMock.mock.calls).toEqual([[100], [0]]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call scrollToRow with expected indices on when scroll "first" and "last" buttons are clicked', async done => {
|
||||||
|
const handleScrollFirst = jest.spyOn(
|
||||||
|
JobOutput.prototype,
|
||||||
|
'handleScrollFirst'
|
||||||
|
);
|
||||||
|
wrapper = mountWithContexts(<JobOutput job={mockJob} />);
|
||||||
|
await waitForElement(wrapper, 'JobEvent', el => el.length > 0);
|
||||||
|
const { scrollFirstButton, scrollLastButton } = await findScrollButtons(
|
||||||
|
wrapper
|
||||||
|
);
|
||||||
|
wrapper.find('JobOutput').instance().scrollToRow = scrollMock;
|
||||||
|
|
||||||
|
scrollFirstButton.simulate('click');
|
||||||
|
scrollLastButton.simulate('click');
|
||||||
|
scrollFirstButton.simulate('click');
|
||||||
|
|
||||||
|
expect(handleScrollFirst).toHaveBeenCalled();
|
||||||
|
expect(scrollMock).toHaveBeenCalledTimes(3);
|
||||||
|
expect(scrollMock.mock.calls).toEqual([[0], [100], [0]]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call scrollToRow with expected index on when scroll "last" button is clicked', async done => {
|
||||||
|
const handleScrollLast = jest.spyOn(
|
||||||
|
JobOutput.prototype,
|
||||||
|
'handleScrollLast'
|
||||||
|
);
|
||||||
|
wrapper = mountWithContexts(<JobOutput job={mockJob} />);
|
||||||
|
await waitForElement(wrapper, 'EmptyStateBody', e => e.length === 0);
|
||||||
|
wrapper
|
||||||
|
.find('JobOutput')
|
||||||
|
.instance()
|
||||||
|
.handleResize({ width: 100 });
|
||||||
|
const { scrollLastButton } = await findScrollButtons(wrapper);
|
||||||
|
wrapper.find('JobOutput').instance().scrollToRow = scrollMock;
|
||||||
|
|
||||||
|
scrollLastButton.simulate('click');
|
||||||
|
|
||||||
|
expect(handleScrollLast).toHaveBeenCalled();
|
||||||
|
expect(scrollMock).toHaveBeenCalledTimes(1);
|
||||||
|
expect(scrollMock.mock.calls).toEqual([[100]]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw error', async done => {
|
||||||
|
JobsAPI.readEvents = () => Promise.reject(new Error());
|
||||||
|
wrapper = mountWithContexts(<JobOutput job={mockJob} />);
|
||||||
|
await waitForElement(wrapper, 'ContentError', e => e.length === 1);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ const Button = styled(PFButton)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const MenuControls = ({
|
const MenuControls = ({
|
||||||
onScrollTop,
|
onScrollFirst,
|
||||||
onScrollBottom,
|
onScrollLast,
|
||||||
onScrollNext,
|
onScrollNext,
|
||||||
onScrollPrevious,
|
onScrollPrevious,
|
||||||
}) => (
|
}) => (
|
||||||
@@ -32,16 +32,20 @@ const MenuControls = ({
|
|||||||
<Button variant="plain">
|
<Button variant="plain">
|
||||||
<PlusIcon />
|
<PlusIcon />
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onScrollPrevious} variant="plain">
|
<Button
|
||||||
|
aria-label="scroll previous"
|
||||||
|
onClick={onScrollPrevious}
|
||||||
|
variant="plain"
|
||||||
|
>
|
||||||
<AngleUpIcon />
|
<AngleUpIcon />
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onScrollNext} variant="plain">
|
<Button aria-label="scroll next" onClick={onScrollNext} variant="plain">
|
||||||
<AngleDownIcon />
|
<AngleDownIcon />
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onScrollTop} variant="plain">
|
<Button aria-label="scroll first" onClick={onScrollFirst} variant="plain">
|
||||||
<AngleDoubleUpIcon />
|
<AngleDoubleUpIcon />
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onScrollBottom} variant="plain">
|
<Button aria-label="scroll last" onClick={onScrollLast} variant="plain">
|
||||||
<AngleDoubleDownIcon />
|
<AngleDoubleDownIcon />
|
||||||
</Button>
|
</Button>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
194
awx/ui_next/src/screens/Job/JobOutput/data.job.json
Normal file
194
awx/ui_next/src/screens/Job/JobOutput/data.job.json
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"type": "job",
|
||||||
|
"url": "/api/v2/jobs/2/",
|
||||||
|
"related": {
|
||||||
|
"created_by": "/api/v2/users/1/",
|
||||||
|
"labels": "/api/v2/jobs/2/labels/",
|
||||||
|
"inventory": "/api/v2/inventories/1/",
|
||||||
|
"project": "/api/v2/projects/6/",
|
||||||
|
"extra_credentials": "/api/v2/jobs/2/extra_credentials/",
|
||||||
|
"credentials": "/api/v2/jobs/2/credentials/",
|
||||||
|
"unified_job_template": "/api/v2/job_templates/7/",
|
||||||
|
"stdout": "/api/v2/jobs/2/stdout/",
|
||||||
|
"job_events": "/api/v2/jobs/2/job_events/",
|
||||||
|
"job_host_summaries": "/api/v2/jobs/2/job_host_summaries/",
|
||||||
|
"activity_stream": "/api/v2/jobs/2/activity_stream/",
|
||||||
|
"notifications": "/api/v2/jobs/2/notifications/",
|
||||||
|
"create_schedule": "/api/v2/jobs/2/create_schedule/",
|
||||||
|
"job_template": "/api/v2/job_templates/7/",
|
||||||
|
"cancel": "/api/v2/jobs/2/cancel/",
|
||||||
|
"project_update": "/api/v2/project_updates/4/",
|
||||||
|
"relaunch": "/api/v2/jobs/2/relaunch/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"inventory": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Demo Inventory",
|
||||||
|
"description": "",
|
||||||
|
"has_active_failures": false,
|
||||||
|
"total_hosts": 1,
|
||||||
|
"hosts_with_active_failures": 0,
|
||||||
|
"total_groups": 0,
|
||||||
|
"groups_with_active_failures": 0,
|
||||||
|
"has_inventory_sources": false,
|
||||||
|
"total_inventory_sources": 0,
|
||||||
|
"inventory_sources_with_failures": 0,
|
||||||
|
"organization_id": 1,
|
||||||
|
"kind": ""
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"id": 6,
|
||||||
|
"name": "Demo Project",
|
||||||
|
"description": "",
|
||||||
|
"status": "successful",
|
||||||
|
"scm_type": "git"
|
||||||
|
},
|
||||||
|
"project_update": {
|
||||||
|
"id": 4,
|
||||||
|
"name": "Demo Project",
|
||||||
|
"description": "",
|
||||||
|
"status": "successful",
|
||||||
|
"failed": false
|
||||||
|
},
|
||||||
|
"job_template": {
|
||||||
|
"id": 7,
|
||||||
|
"name": "Demo Job Template",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"unified_job_template": {
|
||||||
|
"id": 7,
|
||||||
|
"name": "Demo Job Template",
|
||||||
|
"description": "",
|
||||||
|
"unified_job_type": "job"
|
||||||
|
},
|
||||||
|
"instance_group": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "tower"
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"delete": true,
|
||||||
|
"start": true
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"count": 0,
|
||||||
|
"results": []
|
||||||
|
},
|
||||||
|
"extra_credentials": [],
|
||||||
|
"credentials": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Demo Credential",
|
||||||
|
"description": "",
|
||||||
|
"kind": "ssh",
|
||||||
|
"cloud": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"created": "2019-08-08T19:24:05.344276Z",
|
||||||
|
"modified": "2019-08-08T19:24:18.162949Z",
|
||||||
|
"name": "Demo Job Template",
|
||||||
|
"description": "",
|
||||||
|
"job_type": "run",
|
||||||
|
"inventory": 1,
|
||||||
|
"project": 6,
|
||||||
|
"playbook": "chatty_tasks.yml",
|
||||||
|
"forks": 0,
|
||||||
|
"limit": "",
|
||||||
|
"verbosity": 0,
|
||||||
|
"extra_vars": "{\"num_messages\": 94}",
|
||||||
|
"job_tags": "",
|
||||||
|
"force_handlers": false,
|
||||||
|
"skip_tags": "",
|
||||||
|
"start_at_task": "",
|
||||||
|
"timeout": 0,
|
||||||
|
"use_fact_cache": false,
|
||||||
|
"unified_job_template": 7,
|
||||||
|
"launch_type": "manual",
|
||||||
|
"status": "successful",
|
||||||
|
"failed": false,
|
||||||
|
"started": "2019-08-08T19:24:18.329589Z",
|
||||||
|
"finished": "2019-08-08T19:24:50.119995Z",
|
||||||
|
"elapsed": 31.79,
|
||||||
|
"job_args": "[\"bwrap\", \"--unshare-pid\", \"--dev-bind\", \"/\", \"/\", \"--proc\", \"/proc\", \"--bind\", \"/tmp/ansible_runner_pi_pzufy15c/ansible_runner_pi_r_aeukpy/tmpvsg8ly2y\", \"/etc/ssh\", \"--bind\", \"/tmp/ansible_runner_pi_pzufy15c/ansible_runner_pi_r_aeukpy/tmpq_grmdym\", \"/projects\", \"--bind\", \"/tmp/ansible_runner_pi_pzufy15c/ansible_runner_pi_r_aeukpy/tmpfq8ea2z6\", \"/tmp\", \"--bind\", \"/tmp/ansible_runner_pi_pzufy15c/ansible_runner_pi_r_aeukpy/tmpq6v4y_tt\", \"/var/lib/awx\", \"--bind\", \"/tmp/ansible_runner_pi_pzufy15c/ansible_runner_pi_r_aeukpy/tmpupj_jhhb\", \"/var/log\", \"--ro-bind\", \"/venv/ansible\", \"/venv/ansible\", \"--ro-bind\", \"/venv/awx\", \"/venv/awx\", \"--bind\", \"/projects/_6__demo_project\", \"/projects/_6__demo_project\", \"--bind\", \"/tmp/awx_2_a4b1afiw\", \"/tmp/awx_2_a4b1afiw\", \"--chdir\", \"/projects/_6__demo_project\", \"ansible-playbook\", \"-u\", \"admin\", \"-i\", \"/tmp/awx_2_a4b1afiw/tmppb57i4_e\", \"-e\", \"@/tmp/awx_2_a4b1afiw/env/extravars\", \"chatty_tasks.yml\"]",
|
||||||
|
"job_cwd": "/projects/_6__demo_project",
|
||||||
|
"job_env": {
|
||||||
|
"HOSTNAME": "awx",
|
||||||
|
"MAKEFLAGS": "w",
|
||||||
|
"RABBITMQ_USER": "guest",
|
||||||
|
"OS": "Operating System: Docker for Mac",
|
||||||
|
"LC_ALL": "en_US.UTF-8",
|
||||||
|
"RABBITMQ_VHOST": "/",
|
||||||
|
"SDB_HOST": "0.0.0.0",
|
||||||
|
"MAKELEVEL": "2",
|
||||||
|
"VIRTUAL_ENV": "/venv/ansible",
|
||||||
|
"MFLAGS": "-w",
|
||||||
|
"PATH": "/venv/ansible/bin:/venv/awx/bin:/venv/awx/bin:/usr/local/n/versions/node/10.15.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||||
|
"RABBITMQ_PASS": "**********",
|
||||||
|
"SUPERVISOR_GROUP_NAME": "tower-processes",
|
||||||
|
"PWD": "/awx_devel",
|
||||||
|
"LANG": "\"en-us\"",
|
||||||
|
"PS1": "(awx) ",
|
||||||
|
"SUPERVISOR_ENABLED": "1",
|
||||||
|
"SHLVL": "2",
|
||||||
|
"HOME": "/var/lib/awx",
|
||||||
|
"LANGUAGE": "en_US:en",
|
||||||
|
"AWX_GROUP_QUEUES": "tower",
|
||||||
|
"SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock",
|
||||||
|
"SUPERVISOR_PROCESS_NAME": "awx-dispatcher",
|
||||||
|
"RABBITMQ_HOST": "rabbitmq",
|
||||||
|
"CURRENT_UID": "501",
|
||||||
|
"_": "/venv/awx/bin/python3",
|
||||||
|
"DJANGO_SETTINGS_MODULE": "awx.settings.development",
|
||||||
|
"DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199",
|
||||||
|
"SDB_NOTIFY_HOST": "docker.for.mac.host.internal",
|
||||||
|
"TZ": "UTC",
|
||||||
|
"ANSIBLE_FORCE_COLOR": "True",
|
||||||
|
"ANSIBLE_HOST_KEY_CHECKING": "False",
|
||||||
|
"ANSIBLE_INVENTORY_UNPARSED_FAILED": "True",
|
||||||
|
"ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False",
|
||||||
|
"ANSIBLE_VENV_PATH": "/venv/ansible",
|
||||||
|
"PROOT_TMP_DIR": "/tmp",
|
||||||
|
"AWX_PRIVATE_DATA_DIR": "/tmp/awx_2_a4b1afiw",
|
||||||
|
"ANSIBLE_COLLECTIONS_PATHS": "/tmp/collections",
|
||||||
|
"PYTHONPATH": "/venv/ansible/lib/python2.7/site-packages:/awx_devel/awx/lib:",
|
||||||
|
"JOB_ID": "2",
|
||||||
|
"INVENTORY_ID": "1",
|
||||||
|
"PROJECT_REVISION": "23f070aad8e2da131d97ea98b42b553ccf0b0b82",
|
||||||
|
"ANSIBLE_RETRY_FILES_ENABLED": "False",
|
||||||
|
"MAX_EVENT_RES": "700000",
|
||||||
|
"ANSIBLE_CALLBACK_PLUGINS": "/awx_devel/awx/plugins/callback",
|
||||||
|
"AWX_HOST": "https://towerhost",
|
||||||
|
"ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_2_a4b1afiw/cp",
|
||||||
|
"ANSIBLE_STDOUT_CALLBACK": "awx_display",
|
||||||
|
"AWX_ISOLATED_DATA_DIR": "/tmp/awx_2_a4b1afiw/artifacts/2"
|
||||||
|
},
|
||||||
|
"job_explanation": "",
|
||||||
|
"execution_node": "awx",
|
||||||
|
"controller_node": "",
|
||||||
|
"result_traceback": "",
|
||||||
|
"event_processing_finished": true,
|
||||||
|
"job_template": 7,
|
||||||
|
"passwords_needed_to_start": [],
|
||||||
|
"allow_simultaneous": false,
|
||||||
|
"artifacts": {},
|
||||||
|
"scm_revision": "23f070aad8e2da131d97ea98b42b553ccf0b0b82",
|
||||||
|
"instance_group": 1,
|
||||||
|
"diff_mode": false,
|
||||||
|
"job_slice_number": 0,
|
||||||
|
"job_slice_count": 1,
|
||||||
|
"host_status_counts": {
|
||||||
|
"ok": 1
|
||||||
|
},
|
||||||
|
"playbook_counts": {
|
||||||
|
"play_count": 1,
|
||||||
|
"task_count": 1
|
||||||
|
},
|
||||||
|
"custom_virtualenv": "/venv/ansible"
|
||||||
|
}
|
||||||
8461
awx/ui_next/src/screens/Job/JobOutput/data.job_events.json
Normal file
8461
awx/ui_next/src/screens/Job/JobOutput/data.job_events.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
|||||||
export { default } from './MenuControls';
|
|
||||||
Reference in New Issue
Block a user