Commit 0bd45c56 authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch 'jivanvl-fix-collapsible-sections' into 'master'

Make collapsible sections infinitely nested

See merge request gitlab-org/gitlab!65496
parents a02bb29b fdc13baf
<script> <script>
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF } from '../../constants';
import LogLine from './line.vue'; import LogLine from './line.vue';
import LogLineHeader from './line_header.vue'; import LogLineHeader from './line_header.vue';
...@@ -7,7 +9,9 @@ export default { ...@@ -7,7 +9,9 @@ export default {
components: { components: {
LogLine, LogLine,
LogLineHeader, LogLineHeader,
CollapsibleLogSection: () => import('./collapsible_section.vue'),
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
section: { section: {
type: Object, type: Object,
...@@ -22,6 +26,9 @@ export default { ...@@ -22,6 +26,9 @@ export default {
badgeDuration() { badgeDuration() {
return this.section.line && this.section.line.section_duration; return this.section.line && this.section.line.section_duration;
}, },
infinitelyCollapsibleSectionsFlag() {
return this.glFeatures?.[INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF];
},
}, },
methods: { methods: {
handleOnClickCollapsibleLine(section) { handleOnClickCollapsibleLine(section) {
...@@ -40,12 +47,26 @@ export default { ...@@ -40,12 +47,26 @@ export default {
@toggleLine="handleOnClickCollapsibleLine(section)" @toggleLine="handleOnClickCollapsibleLine(section)"
/> />
<template v-if="!section.isClosed"> <template v-if="!section.isClosed">
<log-line <template v-if="infinitelyCollapsibleSectionsFlag">
v-for="line in section.lines" <template v-for="line in section.lines">
:key="line.offset" <collapsible-log-section
:line="line" v-if="line.isHeader"
:path="traceEndpoint" :key="line.line.offset"
/> :section="line"
:trace-endpoint="traceEndpoint"
@onClickCollapsibleLine="handleOnClickCollapsibleLine"
/>
<log-line v-else :key="line.offset" :line="line" :path="traceEndpoint" />
</template>
</template>
<template v-else>
<log-line
v-for="line in section.lines"
:key="line.offset"
:line="line"
:path="traceEndpoint"
/>
</template>
</template> </template>
</div> </div>
</template> </template>
<script> <script>
import { INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF } from '../../constants';
export default { export default {
functional: true, functional: true,
props: { props: {
...@@ -14,7 +16,9 @@ export default { ...@@ -14,7 +16,9 @@ export default {
render(h, { props }) { render(h, { props }) {
const { lineNumber, path } = props; const { lineNumber, path } = props;
const parsedLineNumber = lineNumber + 1; const parsedLineNumber = gon.features?.[INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF]
? lineNumber
: lineNumber + 1;
const lineId = `L${parsedLineNumber}`; const lineId = `L${parsedLineNumber}`;
const lineHref = `${path}#${lineId}`; const lineHref = `${path}#${lineId}`;
......
...@@ -24,3 +24,5 @@ export const JOB_RETRY_FORWARD_DEPLOYMENT_MODAL = { ...@@ -24,3 +24,5 @@ export const JOB_RETRY_FORWARD_DEPLOYMENT_MODAL = {
}; };
export const SUCCESS_STATUS = 'SUCCESS'; export const SUCCESS_STATUS = 'SUCCESS';
export const INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF = 'infinitelyCollapsibleSections';
import Vue from 'vue'; import Vue from 'vue';
import { INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF } from '../constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { logLinesParser, updateIncrementalTrace } from './utils'; import { logLinesParser, logLinesParserLegacy, updateIncrementalTrace } from './utils';
export default { export default {
[types.SET_JOB_ENDPOINT](state, endpoint) { [types.SET_JOB_ENDPOINT](state, endpoint) {
...@@ -20,12 +21,26 @@ export default { ...@@ -20,12 +21,26 @@ export default {
}, },
[types.RECEIVE_TRACE_SUCCESS](state, log = {}) { [types.RECEIVE_TRACE_SUCCESS](state, log = {}) {
const infinitelyCollapsibleSectionsFlag =
gon.features?.[INFINITELY_NESTED_COLLAPSIBLE_SECTIONS_FF];
if (log.state) { if (log.state) {
state.traceState = log.state; state.traceState = log.state;
} }
if (log.append) { if (log.append) {
state.trace = log.lines ? updateIncrementalTrace(log.lines, state.trace) : state.trace; if (infinitelyCollapsibleSectionsFlag) {
if (log.lines) {
const parsedResult = logLinesParser(
log.lines,
state.auxiliaryPartialTraceHelpers,
state.trace,
);
state.trace = parsedResult.parsedLines;
state.auxiliaryPartialTraceHelpers = parsedResult.auxiliaryPartialTraceHelpers;
}
} else {
state.trace = log.lines ? updateIncrementalTrace(log.lines, state.trace) : state.trace;
}
state.traceSize += log.size; state.traceSize += log.size;
} else { } else {
...@@ -33,7 +48,14 @@ export default { ...@@ -33,7 +48,14 @@ export default {
// the trace response will not have a defined // the trace response will not have a defined
// html or size. We keep the old value otherwise these // html or size. We keep the old value otherwise these
// will be set to `null` // will be set to `null`
state.trace = log.lines ? logLinesParser(log.lines) : state.trace;
if (infinitelyCollapsibleSectionsFlag) {
const parsedResult = logLinesParser(log.lines);
state.trace = parsedResult.parsedLines;
state.auxiliaryPartialTraceHelpers = parsedResult.auxiliaryPartialTraceHelpers;
} else {
state.trace = log.lines ? logLinesParserLegacy(log.lines) : state.trace;
}
state.traceSize = log.size || state.traceSize; state.traceSize = log.size || state.traceSize;
} }
......
...@@ -30,4 +30,7 @@ export default () => ({ ...@@ -30,4 +30,7 @@ export default () => ({
selectedStage: '', selectedStage: '',
stages: [], stages: [],
jobs: [], jobs: [],
// to parse partial logs
auxiliaryPartialTraceHelpers: {},
}); });
...@@ -104,7 +104,7 @@ export const getIncrementalLineNumber = (acc) => { ...@@ -104,7 +104,7 @@ export const getIncrementalLineNumber = (acc) => {
* @param Array accumulator * @param Array accumulator
* @returns Array parsed log lines * @returns Array parsed log lines
*/ */
export const logLinesParser = (lines = [], accumulator = []) => export const logLinesParserLegacy = (lines = [], accumulator = []) =>
lines.reduce( lines.reduce(
(acc, line, index) => { (acc, line, index) => {
const lineNumber = accumulator.length > 0 ? getIncrementalLineNumber(acc) : index; const lineNumber = accumulator.length > 0 ? getIncrementalLineNumber(acc) : index;
...@@ -131,6 +131,77 @@ export const logLinesParser = (lines = [], accumulator = []) => ...@@ -131,6 +131,77 @@ export const logLinesParser = (lines = [], accumulator = []) =>
[...accumulator], [...accumulator],
); );
export const logLinesParser = (lines = [], previousTraceState = {}, prevParsedLines = []) => {
let currentLine = previousTraceState?.prevLineCount ?? 0;
let currentHeader = previousTraceState?.currentHeader;
let isPreviousLineHeader = previousTraceState?.isPreviousLineHeader ?? false;
const parsedLines = prevParsedLines.length > 0 ? prevParsedLines : [];
const sectionsQueue = previousTraceState?.sectionsQueue ?? [];
for (let i = 0; i < lines.length; i += 1) {
const line = lines[i];
// First run we can use the current index, later runs we have to retrieve the last number of lines
currentLine = previousTraceState?.prevLineCount ? currentLine + 1 : i + 1;
if (line.section_header && !isPreviousLineHeader) {
// If there's no previous line header that means we're at the root of the log
isPreviousLineHeader = true;
parsedLines.push(parseHeaderLine(line, currentLine));
currentHeader = { index: parsedLines.length - 1 };
} else if (line.section_header && isPreviousLineHeader) {
// If there's a current section, we can't push to the parsedLines array
sectionsQueue.push(currentHeader);
currentHeader = parseHeaderLine(line, currentLine); // Let's parse the incoming header line
} else if (line.section && !line.section_duration) {
// We're inside a collapsible section and want to parse a standard line
if (currentHeader?.index) {
// If the current section header is only an index, add the line as part of the lines
// array of the current collapsible section
parsedLines[currentHeader.index].lines.push(parseLine(line, currentLine));
} else {
// Otherwise add it to the innermost collapsible section lines array
currentHeader.lines.push(parseLine(line, currentLine));
}
} else if (line.section && line.section_duration) {
// NOTE: This marks the end of a section_header
const previousSection = sectionsQueue.pop();
// Add the duration to section header
// If at the root, just push the end to the current parsedLine,
// otherwise, push it to the previous sections queue
if (currentHeader?.index) {
parsedLines[currentHeader.index].line.section_duration = line.section_duration;
isPreviousLineHeader = false;
currentHeader = null;
} else {
currentHeader.line.section_duration = line.section_duration;
if (previousSection && previousSection?.index) {
// Is the previous section on root?
parsedLines[previousSection.index].lines.push(currentHeader);
} else if (previousSection && !previousSection?.index) {
previousSection.lines.push(currentHeader);
}
currentHeader = previousSection;
}
} else {
parsedLines.push(parseLine(line, currentLine));
}
}
return {
parsedLines,
auxiliaryPartialTraceHelpers: {
isPreviousLineHeader,
currentHeader,
sectionsQueue,
prevLineCount: lines.length,
},
};
};
/** /**
* Finds the repeated offset, removes the old one * Finds the repeated offset, removes the old one
* *
...@@ -177,5 +248,5 @@ export const findOffsetAndRemove = (newLog = [], oldParsed = []) => { ...@@ -177,5 +248,5 @@ export const findOffsetAndRemove = (newLog = [], oldParsed = []) => {
export const updateIncrementalTrace = (newLog = [], oldParsed = []) => { export const updateIncrementalTrace = (newLog = [], oldParsed = []) => {
const parsedLog = findOffsetAndRemove(newLog, oldParsed); const parsedLog = findOffsetAndRemove(newLog, oldParsed);
return logLinesParser(newLog, parsedLog); return logLinesParserLegacy(newLog, parsedLog);
}; };
...@@ -17,6 +17,10 @@ class Projects::JobsController < Projects::ApplicationController ...@@ -17,6 +17,10 @@ class Projects::JobsController < Projects::ApplicationController
before_action :verify_proxy_request!, only: :proxy_websocket_authorize before_action :verify_proxy_request!, only: :proxy_websocket_authorize
before_action :push_jobs_table_vue, only: [:index] before_action :push_jobs_table_vue, only: [:index]
before_action do
push_frontend_feature_flag(:infinitely_collapsible_sections, @project, default_enabled: :yaml)
end
layout 'project' layout 'project'
feature_category :continuous_integration feature_category :continuous_integration
......
---
name: infinitely_collapsible_sections
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/65496
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/335297
milestone: '14.1'
type: development
group: group::pipeline execution
default_enabled: false
...@@ -24,6 +24,7 @@ describe('Job App', () => { ...@@ -24,6 +24,7 @@ describe('Job App', () => {
let store; let store;
let wrapper; let wrapper;
let mock; let mock;
let origGon;
const initSettings = { const initSettings = {
endpoint: `${TEST_HOST}jobs/123.json`, endpoint: `${TEST_HOST}jobs/123.json`,
...@@ -85,11 +86,17 @@ describe('Job App', () => { ...@@ -85,11 +86,17 @@ describe('Job App', () => {
beforeEach(() => { beforeEach(() => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
store = createStore(); store = createStore();
origGon = window.gon;
window.gon = { features: { infinitelyCollapsibleSections: false } }; // NOTE: All of this passes with the feature flag
}); });
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
mock.restore(); mock.restore();
window.gon = origGon;
}); });
describe('while loading', () => { describe('while loading', () => {
......
...@@ -4,6 +4,7 @@ import { collapsibleSectionClosed, collapsibleSectionOpened } from './mock_data' ...@@ -4,6 +4,7 @@ import { collapsibleSectionClosed, collapsibleSectionOpened } from './mock_data'
describe('Job Log Collapsible Section', () => { describe('Job Log Collapsible Section', () => {
let wrapper; let wrapper;
let origGon;
const traceEndpoint = 'jobs/335'; const traceEndpoint = 'jobs/335';
...@@ -18,8 +19,16 @@ describe('Job Log Collapsible Section', () => { ...@@ -18,8 +19,16 @@ describe('Job Log Collapsible Section', () => {
}); });
}; };
beforeEach(() => {
origGon = window.gon;
window.gon = { features: { infinitelyCollapsibleSections: false } }; // NOTE: This also works with true
});
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
window.gon = origGon;
}); });
describe('with closed section', () => { describe('with closed section', () => {
......
import { mount, createLocalVue } from '@vue/test-utils'; import { mount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Log from '~/jobs/components/log/log.vue'; import Log from '~/jobs/components/log/log.vue';
import { logLinesParser } from '~/jobs/store/utils'; import { logLinesParserLegacy, logLinesParser } from '~/jobs/store/utils';
import { jobLog } from './mock_data'; import { jobLog } from './mock_data';
describe('Job Log', () => { describe('Job Log', () => {
...@@ -9,6 +9,7 @@ describe('Job Log', () => { ...@@ -9,6 +9,7 @@ describe('Job Log', () => {
let actions; let actions;
let state; let state;
let store; let store;
let origGon;
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
...@@ -25,8 +26,12 @@ describe('Job Log', () => { ...@@ -25,8 +26,12 @@ describe('Job Log', () => {
toggleCollapsibleLine: () => {}, toggleCollapsibleLine: () => {},
}; };
origGon = window.gon;
window.gon = { features: { infinitelyCollapsibleSections: false } };
state = { state = {
trace: logLinesParser(jobLog), trace: logLinesParserLegacy(jobLog),
traceEndpoint: 'jobs/id', traceEndpoint: 'jobs/id',
}; };
...@@ -40,6 +45,88 @@ describe('Job Log', () => { ...@@ -40,6 +45,88 @@ describe('Job Log', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
window.gon = origGon;
});
const findCollapsibleLine = () => wrapper.find('.collapsible-line');
describe('line numbers', () => {
it('renders a line number for each open line', () => {
expect(wrapper.find('#L1').text()).toBe('1');
expect(wrapper.find('#L2').text()).toBe('2');
expect(wrapper.find('#L3').text()).toBe('3');
});
it('links to the provided path and correct line number', () => {
expect(wrapper.find('#L1').attributes('href')).toBe(`${state.traceEndpoint}#L1`);
});
});
describe('collapsible sections', () => {
it('renders a clickable header section', () => {
expect(findCollapsibleLine().attributes('role')).toBe('button');
});
it('renders an icon with the open state', () => {
expect(findCollapsibleLine().find('[data-testid="angle-down-icon"]').exists()).toBe(true);
});
describe('on click header section', () => {
it('calls toggleCollapsibleLine', () => {
jest.spyOn(wrapper.vm, 'toggleCollapsibleLine');
findCollapsibleLine().trigger('click');
expect(wrapper.vm.toggleCollapsibleLine).toHaveBeenCalled();
});
});
});
});
describe('Job Log, infinitelyCollapsibleSections feature flag enabled', () => {
let wrapper;
let actions;
let state;
let store;
let origGon;
const localVue = createLocalVue();
localVue.use(Vuex);
const createComponent = () => {
wrapper = mount(Log, {
localVue,
store,
});
};
beforeEach(() => {
actions = {
toggleCollapsibleLine: () => {},
};
origGon = window.gon;
window.gon = { features: { infinitelyCollapsibleSections: true } };
state = {
trace: logLinesParser(jobLog).parsedLines,
traceEndpoint: 'jobs/id',
};
store = new Vuex.Store({
actions,
state,
});
createComponent();
});
afterEach(() => {
wrapper.destroy();
window.gon = origGon;
}); });
const findCollapsibleLine = () => wrapper.find('.collapsible-line'); const findCollapsibleLine = () => wrapper.find('.collapsible-line');
......
...@@ -58,6 +58,71 @@ export const utilsMockData = [ ...@@ -58,6 +58,71 @@ export const utilsMockData = [
}, },
]; ];
export const multipleCollapsibleSectionsMockData = [
{
offset: 1001,
content: [{ text: ' on docker-auto-scale-com 8a6210b8' }],
},
{
offset: 1002,
content: [
{
text: 'Executing "step_script" stage of the job script',
},
],
section: 'step-script',
section_header: true,
},
{
offset: 1003,
content: [{ text: 'sleep 60' }],
section: 'step-script',
},
{
offset: 1004,
content: [
{
text:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam lorem dolor, congue ac condimentum vitae',
},
],
section: 'step-script',
},
{
offset: 1005,
content: [{ text: 'executing...' }],
section: 'step-script',
},
{
offset: 1006,
content: [{ text: '1st collapsible section' }],
section: 'collapsible-1',
section_header: true,
},
{
offset: 1007,
content: [
{
text:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam lorem dolor, congue ac condimentum vitae',
},
],
section: 'collapsible-1',
},
{
offset: 1008,
content: [],
section: 'collapsible-1',
section_duration: '01:00',
},
{
offset: 1009,
content: [],
section: 'step-script',
section_duration: '10:00',
},
];
export const originalTrace = [ export const originalTrace = [
{ {
offset: 1, offset: 1,
......
...@@ -4,12 +4,21 @@ import state from '~/jobs/store/state'; ...@@ -4,12 +4,21 @@ import state from '~/jobs/store/state';
describe('Jobs Store Mutations', () => { describe('Jobs Store Mutations', () => {
let stateCopy; let stateCopy;
let origGon;
const html = const html =
'I, [2018-08-17T22:57:45.707325 #1841] INFO -- : Writing /builds/ab89e95b0fa0b9272ea0c797b76908f24d36992630e9325273a4ce3.png<br>I'; 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- : Writing /builds/ab89e95b0fa0b9272ea0c797b76908f24d36992630e9325273a4ce3.png<br>I';
beforeEach(() => { beforeEach(() => {
stateCopy = state(); stateCopy = state();
origGon = window.gon;
window.gon = { features: { infinitelyCollapsibleSections: false } };
});
afterEach(() => {
window.gon = origGon;
}); });
describe('SET_JOB_ENDPOINT', () => { describe('SET_JOB_ENDPOINT', () => {
...@@ -267,3 +276,88 @@ describe('Jobs Store Mutations', () => { ...@@ -267,3 +276,88 @@ describe('Jobs Store Mutations', () => {
}); });
}); });
}); });
describe('Job Store mutations, feature flag ON', () => {
let stateCopy;
let origGon;
const html =
'I, [2018-08-17T22:57:45.707325 #1841] INFO -- : Writing /builds/ab89e95b0fa0b9272ea0c797b76908f24d36992630e9325273a4ce3.png<br>I';
beforeEach(() => {
stateCopy = state();
origGon = window.gon;
window.gon = { features: { infinitelyCollapsibleSections: true } };
});
afterEach(() => {
window.gon = origGon;
});
describe('RECEIVE_TRACE_SUCCESS', () => {
describe('with new job log', () => {
describe('log.lines', () => {
describe('when append is true', () => {
it('sets the parsed log ', () => {
mutations[types.RECEIVE_TRACE_SUCCESS](stateCopy, {
append: true,
size: 511846,
complete: true,
lines: [
{
offset: 1,
content: [{ text: 'Running with gitlab-runner 11.12.1 (5a147c92)' }],
},
],
});
expect(stateCopy.trace).toEqual([
{
offset: 1,
content: [{ text: 'Running with gitlab-runner 11.12.1 (5a147c92)' }],
lineNumber: 1,
},
]);
});
});
describe('when lines are defined', () => {
it('sets the parsed log ', () => {
mutations[types.RECEIVE_TRACE_SUCCESS](stateCopy, {
append: false,
size: 511846,
complete: true,
lines: [
{ offset: 0, content: [{ text: 'Running with gitlab-runner 11.11.1 (5a147c92)' }] },
],
});
expect(stateCopy.trace).toEqual([
{
offset: 0,
content: [{ text: 'Running with gitlab-runner 11.11.1 (5a147c92)' }],
lineNumber: 1,
},
]);
});
});
describe('when lines are null', () => {
it('sets the default value', () => {
mutations[types.RECEIVE_TRACE_SUCCESS](stateCopy, {
append: true,
html,
size: 511846,
complete: false,
lines: null,
});
expect(stateCopy.trace).toEqual([]);
});
});
});
});
});
});
import { import {
logLinesParser, logLinesParser,
logLinesParserLegacy,
updateIncrementalTrace, updateIncrementalTrace,
parseHeaderLine, parseHeaderLine,
parseLine, parseLine,
...@@ -17,6 +18,7 @@ import { ...@@ -17,6 +18,7 @@ import {
headerTraceIncremental, headerTraceIncremental,
collapsibleTrace, collapsibleTrace,
collapsibleTraceIncremental, collapsibleTraceIncremental,
multipleCollapsibleSectionsMockData,
} from '../components/log/mock_data'; } from '../components/log/mock_data';
describe('Jobs Store Utils', () => { describe('Jobs Store Utils', () => {
...@@ -175,11 +177,11 @@ describe('Jobs Store Utils', () => { ...@@ -175,11 +177,11 @@ describe('Jobs Store Utils', () => {
expect(isCollapsibleSection()).toEqual(false); expect(isCollapsibleSection()).toEqual(false);
}); });
}); });
describe('logLinesParser', () => { describe('logLinesParserLegacy', () => {
let result; let result;
beforeEach(() => { beforeEach(() => {
result = logLinesParser(utilsMockData); result = logLinesParserLegacy(utilsMockData);
}); });
describe('regular line', () => { describe('regular line', () => {
...@@ -216,6 +218,87 @@ describe('Jobs Store Utils', () => { ...@@ -216,6 +218,87 @@ describe('Jobs Store Utils', () => {
}); });
}); });
describe('logLinesParser', () => {
let result;
beforeEach(() => {
result = logLinesParser(utilsMockData);
});
describe('regular line', () => {
it('adds a lineNumber property with correct index', () => {
expect(result.parsedLines[0].lineNumber).toEqual(1);
expect(result.parsedLines[1].line.lineNumber).toEqual(2);
});
});
describe('collapsible section', () => {
it('adds a `isClosed` property', () => {
expect(result.parsedLines[1].isClosed).toEqual(false);
});
it('adds a `isHeader` property', () => {
expect(result.parsedLines[1].isHeader).toEqual(true);
});
it('creates a lines array property with the content of the collapsible section', () => {
expect(result.parsedLines[1].lines.length).toEqual(2);
expect(result.parsedLines[1].lines[0].content).toEqual(utilsMockData[2].content);
expect(result.parsedLines[1].lines[1].content).toEqual(utilsMockData[3].content);
});
});
describe('section duration', () => {
it('adds the section information to the header section', () => {
expect(result.parsedLines[1].line.section_duration).toEqual(
utilsMockData[4].section_duration,
);
});
it('does not add section duration as a line', () => {
expect(result.parsedLines[1].lines.includes(utilsMockData[4])).toEqual(false);
});
});
describe('multiple collapsible sections', () => {
beforeEach(() => {
result = logLinesParser(multipleCollapsibleSectionsMockData);
});
it('should contain a section inside another section', () => {
const innerSection = [
{
isClosed: false,
isHeader: true,
line: {
content: [{ text: '1st collapsible section' }],
lineNumber: 6,
offset: 1006,
section: 'collapsible-1',
section_duration: '01:00',
section_header: true,
},
lines: [
{
content: [
{
text:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam lorem dolor, congue ac condimentum vitae',
},
],
lineNumber: 7,
offset: 1007,
section: 'collapsible-1',
},
],
},
];
expect(result.parsedLines[1].lines).toEqual(expect.arrayContaining(innerSection));
});
});
});
describe('findOffsetAndRemove', () => { describe('findOffsetAndRemove', () => {
describe('when last item is header', () => { describe('when last item is header', () => {
const existingLog = [ const existingLog = [
...@@ -391,7 +474,7 @@ describe('Jobs Store Utils', () => { ...@@ -391,7 +474,7 @@ describe('Jobs Store Utils', () => {
describe('updateIncrementalTrace', () => { describe('updateIncrementalTrace', () => {
describe('without repeated section', () => { describe('without repeated section', () => {
it('concats and parses both arrays', () => { it('concats and parses both arrays', () => {
const oldLog = logLinesParser(originalTrace); const oldLog = logLinesParserLegacy(originalTrace);
const result = updateIncrementalTrace(regularIncremental, oldLog); const result = updateIncrementalTrace(regularIncremental, oldLog);
expect(result).toEqual([ expect(result).toEqual([
...@@ -419,7 +502,7 @@ describe('Jobs Store Utils', () => { ...@@ -419,7 +502,7 @@ describe('Jobs Store Utils', () => {
describe('with regular line repeated offset', () => { describe('with regular line repeated offset', () => {
it('updates the last line and formats with the incremental part', () => { it('updates the last line and formats with the incremental part', () => {
const oldLog = logLinesParser(originalTrace); const oldLog = logLinesParserLegacy(originalTrace);
const result = updateIncrementalTrace(regularIncrementalRepeated, oldLog); const result = updateIncrementalTrace(regularIncrementalRepeated, oldLog);
expect(result).toEqual([ expect(result).toEqual([
...@@ -438,7 +521,7 @@ describe('Jobs Store Utils', () => { ...@@ -438,7 +521,7 @@ describe('Jobs Store Utils', () => {
describe('with header line repeated', () => { describe('with header line repeated', () => {
it('updates the header line and formats with the incremental part', () => { it('updates the header line and formats with the incremental part', () => {
const oldLog = logLinesParser(headerTrace); const oldLog = logLinesParserLegacy(headerTrace);
const result = updateIncrementalTrace(headerTraceIncremental, oldLog); const result = updateIncrementalTrace(headerTraceIncremental, oldLog);
expect(result).toEqual([ expect(result).toEqual([
...@@ -464,7 +547,7 @@ describe('Jobs Store Utils', () => { ...@@ -464,7 +547,7 @@ describe('Jobs Store Utils', () => {
describe('with collapsible line repeated', () => { describe('with collapsible line repeated', () => {
it('updates the collapsible line and formats with the incremental part', () => { it('updates the collapsible line and formats with the incremental part', () => {
const oldLog = logLinesParser(collapsibleTrace); const oldLog = logLinesParserLegacy(collapsibleTrace);
const result = updateIncrementalTrace(collapsibleTraceIncremental, oldLog); const result = updateIncrementalTrace(collapsibleTraceIncremental, oldLog);
expect(result).toEqual([ expect(result).toEqual([
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment