Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/ci/job_details/components/log')
-rw-r--r--spec/frontend/ci/job_details/components/log/collapsible_section_spec.js103
-rw-r--r--spec/frontend/ci/job_details/components/log/line_header_spec.js8
-rw-r--r--spec/frontend/ci/job_details/components/log/log_spec.js96
-rw-r--r--spec/frontend/ci/job_details/components/log/mock_data.js243
4 files changed, 212 insertions, 238 deletions
diff --git a/spec/frontend/ci/job_details/components/log/collapsible_section_spec.js b/spec/frontend/ci/job_details/components/log/collapsible_section_spec.js
deleted file mode 100644
index 5abf2a5ce53..00000000000
--- a/spec/frontend/ci/job_details/components/log/collapsible_section_spec.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import CollapsibleSection from '~/ci/job_details/components/log/collapsible_section.vue';
-import LogLine from '~/ci/job_details/components/log/line.vue';
-import LogLineHeader from '~/ci/job_details/components/log/line_header.vue';
-import { collapsibleSectionClosed, collapsibleSectionOpened } from './mock_data';
-
-describe('Job Log Collapsible Section', () => {
- let wrapper;
-
- const jobLogEndpoint = 'jobs/335';
-
- const findLogLineHeader = () => wrapper.findComponent(LogLineHeader);
- const findLogLineHeaderSvg = () => findLogLineHeader().find('svg');
- const findLogLines = () => wrapper.findAllComponents(LogLine);
-
- const createComponent = (props = {}) => {
- wrapper = mount(CollapsibleSection, {
- propsData: {
- ...props,
- },
- });
- };
-
- describe('with closed section', () => {
- beforeEach(() => {
- createComponent({
- section: collapsibleSectionClosed,
- jobLogEndpoint,
- });
- });
-
- it('renders clickable header line', () => {
- expect(findLogLineHeader().text()).toBe('1 foo');
- expect(findLogLineHeader().attributes('role')).toBe('button');
- });
-
- it('renders an icon with a closed state', () => {
- expect(findLogLineHeaderSvg().attributes('data-testid')).toBe('chevron-lg-right-icon');
- });
-
- it('does not render collapsed lines', () => {
- expect(findLogLines()).toHaveLength(0);
- });
- });
-
- describe('with opened section', () => {
- beforeEach(() => {
- createComponent({
- section: collapsibleSectionOpened,
- jobLogEndpoint,
- });
- });
-
- it('renders clickable header line', () => {
- expect(findLogLineHeader().text()).toContain('foo');
- expect(findLogLineHeader().attributes('role')).toBe('button');
- });
-
- it('renders an icon with the open state', () => {
- expect(findLogLineHeaderSvg().attributes('data-testid')).toBe('chevron-lg-down-icon');
- });
-
- it('renders collapsible lines', () => {
- expect(findLogLines().at(0).text()).toContain('this is a collapsible nested section');
- expect(findLogLines()).toHaveLength(collapsibleSectionOpened.lines.length);
- });
- });
-
- it('emits onClickCollapsibleLine on click', async () => {
- createComponent({
- section: collapsibleSectionOpened,
- jobLogEndpoint,
- });
-
- findLogLineHeader().trigger('click');
-
- await nextTick();
- expect(wrapper.emitted('onClickCollapsibleLine').length).toBe(1);
- });
-
- describe('with search results', () => {
- it('passes isHighlighted prop correctly', () => {
- const mockSearchResults = [
- {
- content: [{ text: 'foo' }],
- lineNumber: 1,
- offset: 5,
- section: 'prepare-script',
- section_header: true,
- },
- ];
-
- createComponent({
- section: collapsibleSectionOpened,
- jobLogEndpoint,
- searchResults: mockSearchResults,
- });
-
- expect(findLogLineHeader().props('isHighlighted')).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/ci/job_details/components/log/line_header_spec.js b/spec/frontend/ci/job_details/components/log/line_header_spec.js
index c75f5fa30d5..0ac33f5aa5a 100644
--- a/spec/frontend/ci/job_details/components/log/line_header_spec.js
+++ b/spec/frontend/ci/job_details/components/log/line_header_spec.js
@@ -95,12 +95,14 @@ describe('Job Log Header Line', () => {
});
describe('with duration', () => {
- beforeEach(() => {
+ it('renders the duration badge', () => {
createComponent({ ...defaultProps, duration: '00:10' });
+ expect(wrapper.findComponent(DurationBadge).exists()).toBe(true);
});
- it('renders the duration badge', () => {
- expect(wrapper.findComponent(DurationBadge).exists()).toBe(true);
+ it('does not render the duration badge with hidden duration', () => {
+ createComponent({ ...defaultProps, hideDuration: true, duration: '00:10' });
+ expect(wrapper.findComponent(DurationBadge).exists()).toBe(false);
});
});
diff --git a/spec/frontend/ci/job_details/components/log/log_spec.js b/spec/frontend/ci/job_details/components/log/log_spec.js
index 1931d5046dc..de02c7aad6d 100644
--- a/spec/frontend/ci/job_details/components/log/log_spec.js
+++ b/spec/frontend/ci/job_details/components/log/log_spec.js
@@ -6,9 +6,12 @@ import waitForPromises from 'helpers/wait_for_promises';
import { scrollToElement } from '~/lib/utils/common_utils';
import Log from '~/ci/job_details/components/log/log.vue';
import LogLineHeader from '~/ci/job_details/components/log/line_header.vue';
+import LineNumber from '~/ci/job_details/components/log/line_number.vue';
import { logLinesParser } from '~/ci/job_details/store/utils';
import { mockJobLog, mockJobLogLineCount } from './mock_data';
+const mockPagePath = 'project/-/jobs/99';
+
jest.mock('~/lib/utils/common_utils', () => ({
...jest.requireActual('~/lib/utils/common_utils'),
scrollToElement: jest.fn(),
@@ -24,7 +27,12 @@ describe('Job Log', () => {
Vue.use(Vuex);
const createComponent = (props) => {
+ store = new Vuex.Store({ actions, state });
+
wrapper = mount(Log, {
+ provide: {
+ pagePath: mockPagePath,
+ },
propsData: {
...props,
},
@@ -36,39 +44,34 @@ describe('Job Log', () => {
toggleCollapsibleLineMock = jest.fn();
actions = {
toggleCollapsibleLine: toggleCollapsibleLineMock,
+ setupFullScreenListeners: jest.fn(),
};
+ const { lines, sections } = logLinesParser(mockJobLog);
+
state = {
- jobLog: logLinesParser(mockJobLog),
- jobLogEndpoint: 'jobs/id',
+ jobLog: lines,
+ jobLogSections: sections,
};
-
- store = new Vuex.Store({
- actions,
- state,
- });
});
- const findCollapsibleLine = () => wrapper.findComponent(LogLineHeader);
- const findAllCollapsibleLines = () => wrapper.findAllComponents(LogLineHeader);
+ const findLineNumbers = () => wrapper.findAllComponents(LineNumber);
+ const findLineHeader = () => wrapper.findComponent(LogLineHeader);
+ const findLineHeaders = () => wrapper.findAllComponents(LogLineHeader);
describe('line numbers', () => {
beforeEach(() => {
createComponent();
});
- it.each([...Array(mockJobLogLineCount).keys()])(
- 'renders a line number for each line %d',
- (index) => {
- const lineNumber = wrapper
- .findAll('.js-log-line')
- .at(index)
- .find(`#L${index + 1}`);
+ it('renders a line number for each line %d with an href', () => {
+ for (let i = 0; i < mockJobLogLineCount; i += 1) {
+ const w = findLineNumbers().at(i);
- expect(lineNumber.text()).toBe(`${index + 1}`);
- expect(lineNumber.attributes('href')).toBe(`${state.jobLogEndpoint}#L${index + 1}`);
- },
- );
+ expect(w.text()).toBe(`${i + 1}`);
+ expect(w.attributes('href')).toBe(`${mockPagePath}#L${i + 1}`);
+ }
+ });
});
describe('collapsible sections', () => {
@@ -77,22 +80,54 @@ describe('Job Log', () => {
});
it('renders a clickable header section', () => {
- expect(findCollapsibleLine().attributes('role')).toBe('button');
+ expect(findLineHeader().attributes('role')).toBe('button');
});
it('renders an icon with the open state', () => {
- expect(findCollapsibleLine().find('[data-testid="chevron-lg-down-icon"]').exists()).toBe(
- true,
- );
+ expect(findLineHeader().find('[data-testid="chevron-lg-down-icon"]').exists()).toBe(true);
});
describe('on click header section', () => {
it('calls toggleCollapsibleLine', () => {
- findCollapsibleLine().trigger('click');
+ findLineHeader().trigger('click');
expect(toggleCollapsibleLineMock).toHaveBeenCalled();
});
});
+
+ describe('duration', () => {
+ it('shows duration', () => {
+ expect(findLineHeader().props('duration')).toBe('00:00');
+ expect(findLineHeader().props('hideDuration')).toBe(false);
+ });
+
+ it('hides duration', () => {
+ state.jobLogSections['resolve-secrets'].hideDuration = true;
+ createComponent();
+
+ expect(findLineHeader().props('duration')).toBe('00:00');
+ expect(findLineHeader().props('hideDuration')).toBe(true);
+ });
+ });
+
+ describe('when a section is collapsed', () => {
+ beforeEach(() => {
+ state.jobLogSections['prepare-executor'].isClosed = true;
+
+ createComponent();
+ });
+
+ it('hides lines in section', () => {
+ expect(findLineNumbers().wrappers.map((w) => w.text())).toEqual([
+ '1',
+ '2',
+ '3',
+ '4',
+ // closed section not shown
+ '7',
+ ]);
+ });
+ });
});
describe('anchor scrolling', () => {
@@ -119,19 +154,19 @@ describe('Job Log', () => {
it('scrolls to line number', async () => {
createComponent();
- state.jobLog = logLinesParser(mockJobLog, [], '#L6');
+ state.jobLog = logLinesParser(mockJobLog, [], '#L6').lines;
await waitForPromises();
expect(scrollToElement).toHaveBeenCalledTimes(1);
- state.jobLog = logLinesParser(mockJobLog, [], '#L7');
+ state.jobLog = logLinesParser(mockJobLog, [], '#L6').lines;
await waitForPromises();
expect(scrollToElement).toHaveBeenCalledTimes(1);
});
it('line number within collapsed section is visible', () => {
- state.jobLog = logLinesParser(mockJobLog, [], '#L6');
+ state.jobLog = logLinesParser(mockJobLog, [], '#L6').lines;
createComponent();
@@ -150,15 +185,14 @@ describe('Job Log', () => {
},
],
section: 'prepare-executor',
- section_header: true,
lineNumber: 3,
},
];
createComponent({ searchResults: mockSearchResults });
- expect(findAllCollapsibleLines().at(0).props('isHighlighted')).toBe(true);
- expect(findAllCollapsibleLines().at(1).props('isHighlighted')).toBe(false);
+ expect(findLineHeaders().at(0).props('isHighlighted')).toBe(true);
+ expect(findLineHeaders().at(1).props('isHighlighted')).toBe(false);
});
});
});
diff --git a/spec/frontend/ci/job_details/components/log/mock_data.js b/spec/frontend/ci/job_details/components/log/mock_data.js
index d9b1354f475..066f783586b 100644
--- a/spec/frontend/ci/job_details/components/log/mock_data.js
+++ b/spec/frontend/ci/job_details/components/log/mock_data.js
@@ -65,141 +65,182 @@ export const mockContentSection = [
},
];
-export const mockJobLog = [...mockJobLines, ...mockEmptySection, ...mockContentSection];
-
-export const mockJobLogLineCount = 6; // `text` entries in mockJobLog
-
-export const originalTrace = [
+export const mockJobLogEnd = [
{
- offset: 1,
- content: [
- {
- text: 'Downloading',
- },
- ],
+ offset: 1008,
+ content: [{ text: 'Job succeeded' }],
},
];
-export const regularIncremental = [
- {
- offset: 2,
- content: [
- {
- text: 'log line',
- },
- ],
- },
+export const mockJobLog = [
+ ...mockJobLines,
+ ...mockEmptySection,
+ ...mockContentSection,
+ ...mockJobLogEnd,
];
-export const regularIncrementalRepeated = [
+export const mockJobLogLineCount = 7; // `text` entries in mockJobLog
+
+export const mockContentSectionClosed = [
{
- offset: 1,
+ offset: 0,
content: [
{
- text: 'log line',
+ text: 'Using Docker executor with image dev.gitlab.org3',
},
],
+ section: 'mock-closed-section',
+ section_header: true,
+ section_options: { collapsed: true },
+ },
+ {
+ offset: 1003,
+ content: [{ text: 'Docker executor with image registry.gitlab.com ...' }],
+ section: 'mock-closed-section',
+ },
+ {
+ offset: 1004,
+ content: [{ text: 'Starting service ...', style: 'term-fg-l-green' }],
+ section: 'mock-closed-section',
+ },
+ {
+ offset: 1005,
+ content: [],
+ section: 'mock-closed-section',
+ section_footer: true,
+ section_duration: '00:09',
},
];
-export const headerTrace = [
+export const mockContentSectionHiddenDuration = [
{
- offset: 1,
+ offset: 0,
+ content: [{ text: 'Line 1' }],
+ section: 'mock-hidden-duration-section',
section_header: true,
- content: [
- {
- text: 'log line',
- },
- ],
- section: 'section',
+ section_options: { hide_duration: 'true' },
+ },
+ {
+ offset: 1001,
+ content: [{ text: 'Line 2' }],
+ section: 'mock-hidden-duration-section',
+ },
+ {
+ offset: 1002,
+ content: [],
+ section: 'mock-hidden-duration-section',
+ section_footer: true,
+ section_duration: '00:09',
},
];
-export const headerTraceIncremental = [
+export const mockContentSubsection = [
{
- offset: 1,
+ offset: 0,
+ content: [{ text: 'Line 1' }],
+ section: 'mock-section',
section_header: true,
- content: [
- {
- text: 'updated log line',
- },
- ],
- section: 'section',
},
-];
-
-export const collapsibleTrace = [
{
- offset: 1,
+ offset: 1002,
+ content: [{ text: 'Line 2 - section content' }],
+ section: 'mock-section',
+ },
+ {
+ offset: 1003,
+ content: [{ text: 'Line 3 - sub section header' }],
+ section: 'sub-section',
section_header: true,
- content: [
- {
- text: 'log line',
- },
- ],
- section: 'section',
},
{
- offset: 2,
- content: [
- {
- text: 'log line',
- },
- ],
- section: 'section',
+ offset: 1004,
+ content: [{ text: 'Line 4 - sub section content' }],
+ section: 'sub-section',
+ },
+ {
+ offset: 1005,
+ content: [{ text: 'Line 5 - sub sub section header with no content' }],
+ section: 'sub-sub-section',
+ section_header: true,
+ },
+ {
+ offset: 1006,
+ content: [],
+ section: 'sub-sub-section',
+ section_footer: true,
+ section_duration: '00:00',
+ },
+
+ {
+ offset: 1007,
+ content: [{ text: 'Line 6 - sub section content 2' }],
+ section: 'sub-section',
+ },
+ {
+ offset: 1008,
+ content: [],
+ section: 'sub-section',
+ section_footer: true,
+ section_duration: '00:29',
+ },
+ {
+ offset: 1009,
+ content: [{ text: 'Line 7 - section content' }],
+ section: 'mock-section',
+ },
+ {
+ offset: 1010,
+ content: [],
+ section: 'mock-section',
+ section_footer: true,
+ section_duration: '00:59',
+ },
+ {
+ offset: 1011,
+ content: [{ text: 'Job succeeded' }],
},
];
-export const collapsibleTraceIncremental = [
+export const mockTruncatedBottomSection = [
+ // only the top of a section is obtained, such as when a job gets cancelled
{
- offset: 2,
+ offset: 1004,
content: [
{
- text: 'updated log line',
+ text: 'Starting job',
},
],
- section: 'section',
+ section: 'mock-section',
+ section_header: true,
+ },
+ {
+ offset: 1005,
+ content: [{ text: 'Job interrupted' }],
+ section: 'mock-section',
},
];
-export const collapsibleSectionClosed = {
- offset: 5,
- section_header: true,
- isHeader: true,
- isClosed: true,
- line: {
- content: [{ text: 'foo' }],
- section: 'prepare-script',
- lineNumber: 1,
- },
- section_duration: '00:03',
- lines: [
- {
- offset: 80,
- content: [{ text: 'this is a collapsible nested section' }],
- section: 'prepare-script',
- lineNumber: 2,
- },
- ],
-};
-
-export const collapsibleSectionOpened = {
- offset: 5,
- section_header: true,
- isHeader: true,
- isClosed: false,
- line: {
- content: [{ text: 'foo' }],
- section: 'prepare-script',
- lineNumber: 1,
- },
- section_duration: '00:03',
- lines: [
- {
- offset: 80,
- content: [{ text: 'this is a collapsible nested section' }],
- section: 'prepare-script',
- lineNumber: 2,
- },
- ],
-};
+export const mockTruncatedTopSection = [
+ // only the bottom half of a section is obtained, such as when jobs are cut off due to large sizes
+ {
+ offset: 1008,
+ content: [{ text: 'Line N - incomplete section content' }],
+ section: 'mock-section',
+ },
+ {
+ offset: 1009,
+ content: [{ text: 'Line N+1 - incomplete section content' }],
+ section: 'mock-section',
+ },
+ {
+ offset: 1010,
+ content: [],
+ section: 'mock-section',
+ section_footer: true,
+ section_duration: '00:59',
+ },
+ {
+ offset: 1011,
+ content: [{ text: 'Job succeeded' }],
+ },
+];