diff options
Diffstat (limited to 'spec/frontend/pipelines/test_reports')
11 files changed, 0 insertions, 1199 deletions
diff --git a/spec/frontend/pipelines/test_reports/empty_state_spec.js b/spec/frontend/pipelines/test_reports/empty_state_spec.js deleted file mode 100644 index ee0f8a90a11..00000000000 --- a/spec/frontend/pipelines/test_reports/empty_state_spec.js +++ /dev/null @@ -1,45 +0,0 @@ -import { GlEmptyState } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import EmptyState, { i18n } from '~/pipelines/components/test_reports/empty_state.vue'; - -describe('Test report empty state', () => { - let wrapper; - - const findEmptyState = () => wrapper.findComponent(GlEmptyState); - - const createComponent = ({ hasTestReport = true } = {}) => { - wrapper = shallowMount(EmptyState, { - provide: { - emptyStateImagePath: '/image/path', - hasTestReport, - }, - stubs: { - GlEmptyState, - }, - }); - }; - - describe('when pipeline has a test report', () => { - it('should render empty test report message', () => { - createComponent(); - - expect(findEmptyState().props()).toMatchObject({ - primaryButtonText: i18n.noTestsButton, - description: i18n.noTestsDescription, - title: i18n.noTestsTitle, - }); - }); - }); - - describe('when pipeline does not have a test report', () => { - it('should render no test report message', () => { - createComponent({ hasTestReport: false }); - - expect(findEmptyState().props()).toMatchObject({ - primaryButtonText: i18n.noReportsButton, - description: i18n.noReportsDescription, - title: i18n.noReportsTitle, - }); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/mock_data.js b/spec/frontend/pipelines/test_reports/mock_data.js deleted file mode 100644 index c3ca1429842..00000000000 --- a/spec/frontend/pipelines/test_reports/mock_data.js +++ /dev/null @@ -1,31 +0,0 @@ -import { TestStatus } from '~/pipelines/constants'; - -export default [ - { - classname: 'spec.test_spec', - file: 'spec/trace_spec.rb', - execution_time: 0, - name: 'Test#skipped text', - stack_trace: null, - status: TestStatus.SKIPPED, - system_output: null, - }, - { - classname: 'spec.test_spec', - file: 'spec/trace_spec.rb', - execution_time: 0, - name: 'Test#error text', - stack_trace: null, - status: TestStatus.ERROR, - system_output: null, - }, - { - classname: 'spec.test_spec', - file: 'spec/trace_spec.rb', - execution_time: 0, - name: 'Test#unknown text', - stack_trace: null, - status: TestStatus.UNKNOWN, - system_output: null, - }, -]; diff --git a/spec/frontend/pipelines/test_reports/stores/actions_spec.js b/spec/frontend/pipelines/test_reports/stores/actions_spec.js deleted file mode 100644 index e05d2151f0a..00000000000 --- a/spec/frontend/pipelines/test_reports/stores/actions_spec.js +++ /dev/null @@ -1,149 +0,0 @@ -import MockAdapter from 'axios-mock-adapter'; -import testReports from 'test_fixtures/pipelines/test_report.json'; -import { TEST_HOST } from 'helpers/test_constants'; -import testAction from 'helpers/vuex_action_helper'; -import { createAlert } from '~/alert'; -import axios from '~/lib/utils/axios_utils'; -import { HTTP_STATUS_OK } from '~/lib/utils/http_status'; -import * as actions from '~/pipelines/stores/test_reports/actions'; -import * as types from '~/pipelines/stores/test_reports/mutation_types'; - -jest.mock('~/alert'); - -describe('Actions TestReports Store', () => { - let mock; - let state; - - const summary = { total_count: 1 }; - - const suiteEndpoint = `${TEST_HOST}/tests/suite.json`; - const summaryEndpoint = `${TEST_HOST}/test_reports/summary.json`; - const defaultState = { - suiteEndpoint, - summaryEndpoint, - testReports: {}, - selectedSuite: null, - }; - - beforeEach(() => { - mock = new MockAdapter(axios); - state = { ...defaultState }; - }); - - afterEach(() => { - mock.restore(); - }); - - describe('fetch report summary', () => { - beforeEach(() => { - mock.onGet(summaryEndpoint).replyOnce(HTTP_STATUS_OK, summary, {}); - }); - - it('sets testReports and shows tests', () => { - return testAction( - actions.fetchSummary, - null, - state, - [{ type: types.SET_SUMMARY, payload: summary }], - [{ type: 'toggleLoading' }, { type: 'toggleLoading' }], - ); - }); - - it('should create alert on API error', async () => { - await testAction( - actions.fetchSummary, - null, - { summaryEndpoint: null }, - [], - [{ type: 'toggleLoading' }, { type: 'toggleLoading' }], - ); - expect(createAlert).toHaveBeenCalled(); - }); - }); - - describe('fetch test suite', () => { - beforeEach(() => { - const buildIds = [1]; - testReports.test_suites[0].build_ids = buildIds; - mock - .onGet(suiteEndpoint, { params: { build_ids: buildIds } }) - .replyOnce(HTTP_STATUS_OK, testReports.test_suites[0], {}); - }); - - it('sets test suite and shows tests', () => { - const suite = testReports.test_suites[0]; - const index = 0; - - return testAction( - actions.fetchTestSuite, - index, - { ...state, testReports }, - [{ type: types.SET_SUITE, payload: { suite, index } }], - [{ type: 'toggleLoading' }, { type: 'toggleLoading' }], - ); - }); - - it('should call SET_SUITE_ERROR on error', () => { - const index = 0; - - return testAction( - actions.fetchTestSuite, - index, - { ...state, testReports, suiteEndpoint: null }, - [{ type: types.SET_SUITE_ERROR, payload: expect.any(Error) }], - [{ type: 'toggleLoading' }, { type: 'toggleLoading' }], - ); - }); - - describe('when we already have the suite data', () => { - it('should not fetch suite', () => { - const index = 0; - testReports.test_suites[0].hasFullSuite = true; - - return testAction(actions.fetchTestSuite, index, { ...state, testReports }, [], []); - }); - }); - }); - - describe('set selected suite index', () => { - it('sets selectedSuiteIndex', () => { - const selectedSuiteIndex = 0; - - return testAction( - actions.setSelectedSuiteIndex, - selectedSuiteIndex, - { ...state, hasFullReport: true }, - [{ type: types.SET_SELECTED_SUITE_INDEX, payload: selectedSuiteIndex }], - [], - ); - }); - }); - - describe('remove selected suite index', () => { - it('sets selectedSuiteIndex to null', () => { - return testAction( - actions.removeSelectedSuiteIndex, - {}, - state, - [{ type: types.SET_SELECTED_SUITE_INDEX, payload: null }], - [], - ); - }); - }); - - describe('toggles loading', () => { - it('sets isLoading to true', () => { - return testAction(actions.toggleLoading, {}, state, [{ type: types.TOGGLE_LOADING }], []); - }); - - it('toggles isLoading to false', () => { - return testAction( - actions.toggleLoading, - {}, - { ...state, isLoading: true }, - [{ type: types.TOGGLE_LOADING }], - [], - ); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/stores/getters_spec.js b/spec/frontend/pipelines/test_reports/stores/getters_spec.js deleted file mode 100644 index 70e3a01dbf1..00000000000 --- a/spec/frontend/pipelines/test_reports/stores/getters_spec.js +++ /dev/null @@ -1,171 +0,0 @@ -import testReports from 'test_fixtures/pipelines/test_report.json'; -import * as getters from '~/pipelines/stores/test_reports/getters'; -import { - iconForTestStatus, - formatFilePath, - formattedTime, -} from '~/pipelines/stores/test_reports/utils'; - -describe('Getters TestReports Store', () => { - let state; - - const defaultState = { - blobPath: '/test/blob/path', - testReports, - selectedSuiteIndex: 0, - pageInfo: { - page: 1, - perPage: 2, - }, - }; - - const emptyState = { - blobPath: '', - testReports: {}, - selectedSuite: null, - pageInfo: { - page: 1, - perPage: 2, - }, - }; - - beforeEach(() => { - state = { - testReports, - }; - }); - - const setupState = (testState = defaultState) => { - state = testState; - }; - - describe('getTestSuites', () => { - it('should return the test suites', () => { - setupState(); - - const suites = getters.getTestSuites(state); - const expected = testReports.test_suites.map((x) => ({ - ...x, - formattedTime: formattedTime(x.total_time), - })); - - expect(suites).toEqual(expected); - }); - - it('should return an empty array when testReports is empty', () => { - setupState(emptyState); - - expect(getters.getTestSuites(state)).toEqual([]); - }); - }); - - describe('getSelectedSuite', () => { - it('should return the selected suite', () => { - setupState(); - - const selectedSuite = getters.getSelectedSuite(state); - const expected = testReports.test_suites[state.selectedSuiteIndex]; - - expect(selectedSuite).toEqual(expected); - }); - }); - - describe('getSuiteTests', () => { - it('should return the current page of test cases inside the suite', () => { - setupState(); - - const cases = getters.getSuiteTests(state); - const expected = testReports.test_suites[0].test_cases - .map((x) => ({ - ...x, - filePath: `${state.blobPath}/${formatFilePath(x.file)}`, - formattedTime: formattedTime(x.execution_time), - icon: iconForTestStatus(x.status), - })) - .slice(0, state.pageInfo.perPage); - - expect(cases).toEqual(expected); - }); - - it('should return an empty array when testReports is empty', () => { - setupState(emptyState); - - expect(getters.getSuiteTests(state)).toEqual([]); - }); - - describe('when a test case classname property is null', () => { - it('should return an empty string value for the classname property', () => { - const testCases = testReports.test_suites[0].test_cases; - setupState({ - ...defaultState, - testReports: { - ...testReports, - test_suites: [ - { - test_cases: testCases.map((testCase) => ({ - ...testCase, - classname: null, - })), - }, - ], - }, - }); - - const expected = testCases - .map((x) => ({ - ...x, - classname: '', - filePath: `${state.blobPath}/${formatFilePath(x.file)}`, - formattedTime: formattedTime(x.execution_time), - icon: iconForTestStatus(x.status), - })) - .slice(0, state.pageInfo.perPage); - - expect(getters.getSuiteTests(state)).toEqual(expected); - }); - }); - - describe('when a test case name property is null', () => { - it('should return an empty string value for the name property', () => { - const testCases = testReports.test_suites[0].test_cases; - setupState({ - ...defaultState, - testReports: { - ...testReports, - test_suites: [ - { - test_cases: testCases.map((testCase) => ({ - ...testCase, - name: null, - })), - }, - ], - }, - }); - - const expected = testCases - .map((x) => ({ - ...x, - name: '', - filePath: `${state.blobPath}/${formatFilePath(x.file)}`, - formattedTime: formattedTime(x.execution_time), - icon: iconForTestStatus(x.status), - })) - .slice(0, state.pageInfo.perPage); - - expect(getters.getSuiteTests(state)).toEqual(expected); - }); - }); - }); - - describe('getSuiteTestCount', () => { - it('should return the total number of test cases', () => { - setupState(); - - const testCount = getters.getSuiteTestCount(state); - const expected = testReports.test_suites[0].test_cases.length; - - expect(testCount).toEqual(expected); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js b/spec/frontend/pipelines/test_reports/stores/mutations_spec.js deleted file mode 100644 index 685ac6ea3e5..00000000000 --- a/spec/frontend/pipelines/test_reports/stores/mutations_spec.js +++ /dev/null @@ -1,114 +0,0 @@ -import testReports from 'test_fixtures/pipelines/test_report.json'; -import * as types from '~/pipelines/stores/test_reports/mutation_types'; -import mutations from '~/pipelines/stores/test_reports/mutations'; -import { createAlert } from '~/alert'; - -jest.mock('~/alert'); - -describe('Mutations TestReports Store', () => { - let mockState; - - const defaultState = { - endpoint: '', - testReports: {}, - selectedSuite: null, - isLoading: false, - pageInfo: { - page: 1, - perPage: 2, - }, - }; - - beforeEach(() => { - mockState = { ...defaultState }; - }); - - describe('set page', () => { - it('should set the current page to display', () => { - const pageToDisplay = 3; - mutations[types.SET_PAGE](mockState, pageToDisplay); - - expect(mockState.pageInfo.page).toEqual(pageToDisplay); - }); - }); - - describe('set suite', () => { - it('should set the suite at the given index', () => { - mockState.testReports = testReports; - const suite = { name: 'test_suite' }; - const index = 0; - const expectedState = { ...mockState }; - expectedState.testReports.test_suites[index] = { suite, hasFullSuite: true }; - mutations[types.SET_SUITE](mockState, { suite, index }); - - expect(mockState.testReports.test_suites[index]).toEqual( - expectedState.testReports.test_suites[index], - ); - }); - }); - - describe('set suite error', () => { - it('should set the error message in state if provided', () => { - const message = 'Test report artifacts not found'; - - mutations[types.SET_SUITE_ERROR](mockState, { - response: { data: { errors: message } }, - }); - - expect(mockState.errorMessage).toBe(message); - }); - - it('should show an alert otherwise', () => { - mutations[types.SET_SUITE_ERROR](mockState, {}); - - expect(createAlert).toHaveBeenCalled(); - }); - }); - - describe('set selected suite index', () => { - it('should set selectedSuiteIndex', () => { - const selectedSuiteIndex = 0; - mutations[types.SET_SELECTED_SUITE_INDEX](mockState, selectedSuiteIndex); - - expect(mockState.selectedSuiteIndex).toEqual(selectedSuiteIndex); - }); - }); - - describe('set summary', () => { - it('should set summary', () => { - const summary = { - total: { time: 0, count: 10, success: 1, failed: 2, skipped: 3, error: 4 }, - }; - const expectedSummary = { - ...summary, - total_time: 0, - total_count: 10, - success_count: 1, - failed_count: 2, - skipped_count: 3, - error_count: 4, - }; - mutations[types.SET_SUMMARY](mockState, summary); - - expect(mockState.testReports).toEqual(expectedSummary); - }); - }); - - describe('toggle loading', () => { - it('should set to true', () => { - const expectedState = { ...mockState, isLoading: true }; - mutations[types.TOGGLE_LOADING](mockState); - - expect(mockState.isLoading).toEqual(expectedState.isLoading); - }); - - it('should toggle back to false', () => { - const expectedState = { ...mockState, isLoading: false }; - mockState.isLoading = true; - - mutations[types.TOGGLE_LOADING](mockState); - - expect(mockState.isLoading).toEqual(expectedState.isLoading); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/stores/utils_spec.js b/spec/frontend/pipelines/test_reports/stores/utils_spec.js deleted file mode 100644 index 703fe69026c..00000000000 --- a/spec/frontend/pipelines/test_reports/stores/utils_spec.js +++ /dev/null @@ -1,40 +0,0 @@ -import { formatFilePath, formattedTime } from '~/pipelines/stores/test_reports/utils'; - -describe('Test reports utils', () => { - describe('formatFilePath', () => { - it.each` - file | expected - ${'./test.js'} | ${'test.js'} - ${'/test.js'} | ${'test.js'} - ${'.//////////////test.js'} | ${'test.js'} - ${'test.js'} | ${'test.js'} - ${'mock/path./test.js'} | ${'mock/path./test.js'} - ${'./mock/path./test.js'} | ${'mock/path./test.js'} - `('should format $file to be $expected', ({ file, expected }) => { - expect(formatFilePath(file)).toBe(expected); - }); - }); - - describe('formattedTime', () => { - describe('when time is smaller than a second', () => { - it('should return time in milliseconds fixed to 2 decimals', () => { - const result = formattedTime(0.4815162342); - expect(result).toBe('481.52ms'); - }); - }); - - describe('when time is equal to a second', () => { - it('should return time in seconds fixed to 2 decimals', () => { - const result = formattedTime(1); - expect(result).toBe('1.00s'); - }); - }); - - describe('when time is greater than a second', () => { - it('should return time in seconds fixed to 2 decimals', () => { - const result = formattedTime(4.815162342); - expect(result).toBe('4.82s'); - }); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/test_case_details_spec.js b/spec/frontend/pipelines/test_reports/test_case_details_spec.js deleted file mode 100644 index f8663408817..00000000000 --- a/spec/frontend/pipelines/test_reports/test_case_details_spec.js +++ /dev/null @@ -1,149 +0,0 @@ -import { GlModal, GlLink } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import { extendedWrapper } from 'helpers/vue_test_utils_helper'; -import TestCaseDetails from '~/pipelines/components/test_reports/test_case_details.vue'; -import CodeBlock from '~/vue_shared/components/code_block.vue'; -import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue'; - -describe('Test case details', () => { - let wrapper; - const defaultTestCase = { - classname: 'spec.test_spec', - name: 'Test#something cool', - file: '~/index.js', - filePath: '/src/javascripts/index.js', - formattedTime: '10.04ms', - recent_failures: { - count: 2, - base_branch: 'main', - }, - system_output: 'Line 42 is broken', - }; - - const findCopyFileBtn = () => wrapper.findComponent(ModalCopyButton); - const findModal = () => wrapper.findComponent(GlModal); - const findName = () => wrapper.findByTestId('test-case-name'); - const findFile = () => wrapper.findByTestId('test-case-file'); - const findFileLink = () => wrapper.findComponent(GlLink); - const findDuration = () => wrapper.findByTestId('test-case-duration'); - const findRecentFailures = () => wrapper.findByTestId('test-case-recent-failures'); - const findAttachmentUrl = () => wrapper.findByTestId('test-case-attachment-url'); - const findSystemOutput = () => wrapper.findByTestId('test-case-trace'); - - const createComponent = (testCase = {}) => { - wrapper = extendedWrapper( - shallowMount(TestCaseDetails, { - propsData: { - modalId: 'my-modal', - testCase: { - ...defaultTestCase, - ...testCase, - }, - }, - stubs: { CodeBlock, GlModal }, - }), - ); - }; - - describe('required details', () => { - beforeEach(() => { - createComponent(); - }); - - it('renders the test case classname as modal title', () => { - expect(findModal().props('title')).toBe(defaultTestCase.classname); - }); - - it('renders the test case name', () => { - expect(findName().text()).toBe(defaultTestCase.name); - }); - - it('renders the test case file', () => { - expect(findFile().text()).toBe(defaultTestCase.file); - expect(findFileLink().attributes('href')).toBe(defaultTestCase.filePath); - }); - - it('renders copy button for test case file', () => { - expect(findCopyFileBtn().attributes('text')).toBe(defaultTestCase.file); - }); - - it('renders the test case duration', () => { - expect(findDuration().text()).toBe(defaultTestCase.formattedTime); - }); - }); - - describe('when test case has execution time instead of formatted time', () => { - beforeEach(() => { - createComponent({ ...defaultTestCase, formattedTime: null, execution_time: 17 }); - }); - - it('renders the test case duration', () => { - expect(findDuration().text()).toBe('17 s'); - }); - }); - - describe('when test case has recent failures', () => { - describe('has only 1 recent failure', () => { - it('renders the recent failure', () => { - createComponent({ recent_failures: { ...defaultTestCase.recent_failures, count: 1 } }); - - expect(findRecentFailures().text()).toContain( - `Failed 1 time in ${defaultTestCase.recent_failures.base_branch} in the last 14 days`, - ); - }); - }); - - describe('has more than 1 recent failure', () => { - it('renders the recent failures', () => { - createComponent(); - - expect(findRecentFailures().text()).toContain( - `Failed ${defaultTestCase.recent_failures.count} times in ${defaultTestCase.recent_failures.base_branch} in the last 14 days`, - ); - }); - }); - }); - - describe('when test case does not have recent failures', () => { - it('does not render the recent failures', () => { - createComponent({ recent_failures: null }); - - expect(findRecentFailures().exists()).toBe(false); - }); - }); - - describe('when test case has attachment URL', () => { - it('renders the attachment URL as a link', () => { - const expectedUrl = '/my/path.jpg'; - createComponent({ attachment_url: expectedUrl }); - const attachmentUrl = findAttachmentUrl(); - - expect(attachmentUrl.exists()).toBe(true); - expect(attachmentUrl.attributes('href')).toBe(expectedUrl); - }); - }); - - describe('when test case does not have attachment URL', () => { - it('does not render the attachment URL', () => { - createComponent({ attachment_url: null }); - - expect(findAttachmentUrl().exists()).toBe(false); - }); - }); - - describe('when test case has system output', () => { - it('renders the test case system output', () => { - createComponent(); - - expect(findSystemOutput().text()).toContain(defaultTestCase.system_output); - }); - }); - - describe('when test case does not have system output', () => { - it('does not render the test case system output', () => { - createComponent({ system_output: null }); - - expect(findSystemOutput().exists()).toBe(false); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/test_reports_spec.js b/spec/frontend/pipelines/test_reports/test_reports_spec.js deleted file mode 100644 index de16f496eff..00000000000 --- a/spec/frontend/pipelines/test_reports/test_reports_spec.js +++ /dev/null @@ -1,125 +0,0 @@ -import { GlLoadingIcon } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; -import Vue from 'vue'; -// eslint-disable-next-line no-restricted-imports -import Vuex from 'vuex'; -import testReports from 'test_fixtures/pipelines/test_report.json'; -import { extendedWrapper } from 'helpers/vue_test_utils_helper'; -import EmptyState from '~/pipelines/components/test_reports/empty_state.vue'; -import TestReports from '~/pipelines/components/test_reports/test_reports.vue'; -import TestSummary from '~/pipelines/components/test_reports/test_summary.vue'; -import TestSummaryTable from '~/pipelines/components/test_reports/test_summary_table.vue'; -import * as getters from '~/pipelines/stores/test_reports/getters'; - -Vue.use(Vuex); - -describe('Test reports app', () => { - let wrapper; - let store; - - const loadingSpinner = () => wrapper.findComponent(GlLoadingIcon); - const testsDetail = () => wrapper.findByTestId('tests-detail'); - const emptyState = () => wrapper.findComponent(EmptyState); - const testSummary = () => wrapper.findComponent(TestSummary); - const testSummaryTable = () => wrapper.findComponent(TestSummaryTable); - - const actionSpies = { - fetchTestSuite: jest.fn(), - fetchSummary: jest.fn(), - setSelectedSuiteIndex: jest.fn(), - removeSelectedSuiteIndex: jest.fn(), - }; - - const createComponent = ({ state = {} } = {}) => { - store = new Vuex.Store({ - modules: { - testReports: { - namespaced: true, - state: { - isLoading: false, - selectedSuiteIndex: null, - testReports, - ...state, - }, - actions: actionSpies, - getters, - }, - }, - }); - - jest.spyOn(store, 'registerModule').mockReturnValue(null); - - wrapper = extendedWrapper( - shallowMount(TestReports, { - provide: { - blobPath: '/blob/path', - summaryEndpoint: '/summary.json', - suiteEndpoint: '/suite.json', - }, - store, - }), - ); - }; - - describe('when component is created', () => { - it('should call fetchSummary when pipeline has test report', () => { - createComponent(); - - expect(actionSpies.fetchSummary).toHaveBeenCalled(); - }); - }); - - describe('when loading', () => { - beforeEach(() => createComponent({ state: { isLoading: true } })); - - it('shows the loading spinner', () => { - expect(emptyState().exists()).toBe(false); - expect(testsDetail().exists()).toBe(false); - expect(loadingSpinner().exists()).toBe(true); - }); - }); - - describe('when the api returns no data', () => { - it('displays empty state component', () => { - createComponent({ state: { testReports: {} } }); - - expect(emptyState().exists()).toBe(true); - }); - }); - - describe('when the api returns data', () => { - beforeEach(() => createComponent()); - - it('sets testReports and shows tests', () => { - expect(wrapper.vm.testReports).toEqual(expect.any(Object)); - expect(wrapper.vm.showTests).toBe(true); - }); - - it('shows tests details', () => { - expect(testsDetail().exists()).toBe(true); - }); - }); - - describe('when a suite is clicked', () => { - beforeEach(() => { - createComponent({ state: { hasFullReport: true } }); - testSummaryTable().vm.$emit('row-click', 0); - }); - - it('should call setSelectedSuiteIndex and fetchTestSuite', () => { - expect(actionSpies.setSelectedSuiteIndex).toHaveBeenCalled(); - expect(actionSpies.fetchTestSuite).toHaveBeenCalled(); - }); - }); - - describe('when clicking back to summary', () => { - beforeEach(() => { - createComponent({ state: { selectedSuiteIndex: 0 } }); - testSummary().vm.$emit('on-back-click'); - }); - - it('should call removeSelectedSuiteIndex', () => { - expect(actionSpies.removeSelectedSuiteIndex).toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js deleted file mode 100644 index 08b430fa703..00000000000 --- a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js +++ /dev/null @@ -1,169 +0,0 @@ -import { GlButton, GlFriendlyWrap, GlLink, GlPagination, GlEmptyState } from '@gitlab/ui'; -import Vue from 'vue'; -// eslint-disable-next-line no-restricted-imports -import Vuex from 'vuex'; -import testReports from 'test_fixtures/pipelines/test_report.json'; -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import SuiteTable, { i18n } from '~/pipelines/components/test_reports/test_suite_table.vue'; -import { TestStatus } from '~/pipelines/constants'; -import * as getters from '~/pipelines/stores/test_reports/getters'; -import { formatFilePath } from '~/pipelines/stores/test_reports/utils'; -import { ARTIFACTS_EXPIRED_ERROR_MESSAGE } from '~/pipelines/stores/test_reports/constants'; -import skippedTestCases from './mock_data'; - -Vue.use(Vuex); - -describe('Test reports suite table', () => { - let wrapper; - let store; - - const { - test_suites: [testSuite], - } = testReports; - - testSuite.test_cases = [...testSuite.test_cases, ...skippedTestCases]; - const testCases = testSuite.test_cases; - const blobPath = '/test/blob/path'; - - const noCasesMessage = () => wrapper.findByTestId('no-test-cases'); - const artifactsExpiredMessage = () => wrapper.findByTestId('artifacts-expired'); - const artifactsExpiredEmptyState = () => wrapper.findComponent(GlEmptyState); - const allCaseRows = () => wrapper.findAllByTestId('test-case-row'); - const findCaseRowAtIndex = (index) => wrapper.findAllByTestId('test-case-row').at(index); - const findLinkForRow = (row) => row.findComponent(GlLink); - const findIconForRow = (row, status) => row.find(`.ci-status-icon-${status}`); - - const createComponent = ({ suite = testSuite, perPage = 20, errorMessage } = {}) => { - store = new Vuex.Store({ - modules: { - testReports: { - namespaced: true, - state: { - blobPath, - testReports: { - test_suites: [suite], - }, - selectedSuiteIndex: 0, - pageInfo: { - page: 1, - perPage, - }, - errorMessage, - }, - getters, - }, - }, - }); - - wrapper = shallowMountExtended(SuiteTable, { - provide: { - blobPath: '/blob/path', - summaryEndpoint: '/summary.json', - suiteEndpoint: '/suite.json', - }, - store, - stubs: { GlFriendlyWrap }, - }); - }; - - it('should render a message when there are no test cases', () => { - createComponent({ suite: [] }); - - expect(noCasesMessage().exists()).toBe(true); - expect(artifactsExpiredMessage().exists()).toBe(false); - }); - - it('should render an empty state when artifacts have expired', () => { - createComponent({ suite: [], errorMessage: ARTIFACTS_EXPIRED_ERROR_MESSAGE }); - const emptyState = artifactsExpiredEmptyState(); - - expect(noCasesMessage().exists()).toBe(false); - expect(artifactsExpiredMessage().exists()).toBe(true); - - expect(emptyState.exists()).toBe(true); - expect(emptyState.props('title')).toBe(i18n.expiredArtifactsTitle); - }); - - describe('when a test suite is supplied', () => { - beforeEach(() => createComponent()); - - it('renders the correct number of rows', () => { - expect(allCaseRows()).toHaveLength(testCases.length); - }); - - it.each([ - TestStatus.ERROR, - TestStatus.FAILED, - TestStatus.SKIPPED, - TestStatus.SUCCESS, - 'unknown', - ])('renders the correct icon for test case with %s status', (status) => { - const test = testCases.findIndex((x) => x.status === status); - const row = findCaseRowAtIndex(test); - - expect(findIconForRow(row, status).exists()).toBe(true); - }); - - it('renders the file name for the test with a copy button', () => { - const { file } = testCases[0]; - const relativeFile = formatFilePath(file); - const filePath = `${blobPath}/${relativeFile}`; - const row = findCaseRowAtIndex(0); - const fileLink = findLinkForRow(row); - const button = row.findComponent(GlButton); - - expect(fileLink.attributes('href')).toBe(filePath); - expect(row.text()).toContain(file); - expect(button.exists()).toBe(true); - expect(button.attributes('data-clipboard-text')).toBe(file); - }); - }); - - describe('when a test suite has more test cases than the pagination size', () => { - const perPage = 2; - - beforeEach(() => { - createComponent({ testSuite, perPage }); - }); - - it('renders one page of test cases', () => { - expect(allCaseRows().length).toBe(perPage); - }); - - it('renders a pagination component', () => { - expect(wrapper.findComponent(GlPagination).exists()).toBe(true); - }); - }); - - describe('when a test case classname property is null', () => { - it('still renders all test cases', () => { - createComponent({ - testSuite: { - ...testSuite, - test_cases: testSuite.test_cases.map((testCase) => ({ - ...testCase, - classname: null, - })), - }, - }); - - expect(allCaseRows()).toHaveLength(testCases.length); - }); - }); - - describe('when a test case name property is null', () => { - it('still renders all test cases', () => { - createComponent({ - testSuite: { - ...testSuite, - test_cases: testSuite.test_cases.map((testCase) => ({ - ...testCase, - name: null, - })), - }, - }); - - expect(allCaseRows()).toHaveLength(testCases.length); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/test_summary_spec.js b/spec/frontend/pipelines/test_reports/test_summary_spec.js deleted file mode 100644 index 7eed6671fb9..00000000000 --- a/spec/frontend/pipelines/test_reports/test_summary_spec.js +++ /dev/null @@ -1,106 +0,0 @@ -import { mount } from '@vue/test-utils'; -import testReports from 'test_fixtures/pipelines/test_report.json'; -import Summary from '~/pipelines/components/test_reports/test_summary.vue'; -import { formattedTime } from '~/pipelines/stores/test_reports/utils'; - -describe('Test reports summary', () => { - let wrapper; - - const { - test_suites: [testSuite], - } = testReports; - - const backButton = () => wrapper.find('.js-back-button'); - const totalTests = () => wrapper.find('.js-total-tests'); - const failedTests = () => wrapper.find('.js-failed-tests'); - const erroredTests = () => wrapper.find('.js-errored-tests'); - const successRate = () => wrapper.find('.js-success-rate'); - const duration = () => wrapper.find('.js-duration'); - - const defaultProps = { - report: testSuite, - showBack: false, - }; - - const createComponent = (props) => { - wrapper = mount(Summary, { - propsData: { - ...defaultProps, - ...props, - }, - }); - }; - - describe('should not render', () => { - beforeEach(() => { - createComponent(); - }); - - it('a back button by default', () => { - expect(backButton().exists()).toBe(false); - }); - }); - - describe('should render', () => { - beforeEach(() => { - createComponent(); - }); - - it('a back button and emit on-back-click event', () => { - createComponent({ - showBack: true, - }); - - expect(backButton().exists()).toBe(true); - }); - }); - - describe('when a report is supplied', () => { - beforeEach(() => { - createComponent(); - }); - - it('displays the correct total', () => { - expect(totalTests().text()).toBe('4 tests'); - }); - - it('displays the correct failure count', () => { - expect(failedTests().text()).toBe('2 failures'); - }); - - it('displays the correct error count', () => { - expect(erroredTests().text()).toBe('0 errors'); - }); - - it('calculates and displays percentages correctly', () => { - expect(successRate().text()).toBe('50% success rate'); - }); - - it('displays the correctly formatted duration', () => { - expect(duration().text()).toBe(formattedTime(testSuite.total_time)); - }); - }); - - describe('success percentage calculation', () => { - it.each` - name | successCount | totalCount | skippedCount | result - ${'displays 0 when there are no tests'} | ${0} | ${0} | ${0} | ${'0'} - ${'displays whole number when possible'} | ${10} | ${50} | ${0} | ${'20'} - ${'excludes skipped tests from total'} | ${10} | ${50} | ${5} | ${'22.22'} - ${'rounds to 0.01'} | ${1} | ${16604} | ${0} | ${'0.01'} - ${'correctly rounds to 50'} | ${8302} | ${16604} | ${0} | ${'50'} - ${'rounds down for large close numbers'} | ${16603} | ${16604} | ${0} | ${'99.99'} - ${'correctly displays 100'} | ${16604} | ${16604} | ${0} | ${'100'} - `('$name', ({ successCount, totalCount, skippedCount, result }) => { - createComponent({ - report: { - success_count: successCount, - skipped_count: skippedCount, - total_count: totalCount, - }, - }); - - expect(successRate().text()).toBe(`${result}% success rate`); - }); - }); -}); diff --git a/spec/frontend/pipelines/test_reports/test_summary_table_spec.js b/spec/frontend/pipelines/test_reports/test_summary_table_spec.js deleted file mode 100644 index a45946d5a03..00000000000 --- a/spec/frontend/pipelines/test_reports/test_summary_table_spec.js +++ /dev/null @@ -1,100 +0,0 @@ -import { mount } from '@vue/test-utils'; -import Vue from 'vue'; -// eslint-disable-next-line no-restricted-imports -import Vuex from 'vuex'; -import testReports from 'test_fixtures/pipelines/test_report.json'; -import SummaryTable from '~/pipelines/components/test_reports/test_summary_table.vue'; -import * as getters from '~/pipelines/stores/test_reports/getters'; - -Vue.use(Vuex); - -describe('Test reports summary table', () => { - let wrapper; - let store; - - const allSuitesRows = () => wrapper.findAll('.js-suite-row'); - const noSuitesToShow = () => wrapper.find('.js-no-tests-suites'); - - const defaultProps = { - testReports, - }; - - const createComponent = (reports = null) => { - store = new Vuex.Store({ - modules: { - testReports: { - namespaced: true, - state: { - testReports: reports || testReports, - }, - getters, - }, - }, - }); - - wrapper = mount(SummaryTable, { - provide: { - blobPath: '/blob/path', - summaryEndpoint: '/summary.json', - suiteEndpoint: '/suite.json', - }, - propsData: defaultProps, - store, - }); - }; - - describe('when test reports are supplied', () => { - beforeEach(() => createComponent()); - const findErrorIcon = () => wrapper.findComponent({ ref: 'suiteErrorIcon' }); - - it('renders the correct number of rows', () => { - expect(noSuitesToShow().exists()).toBe(false); - expect(allSuitesRows().length).toBe(testReports.test_suites.length); - }); - - describe('when there is a suite error', () => { - beforeEach(() => { - createComponent({ - test_suites: [ - { - ...testReports.test_suites[0], - suite_error: 'Suite Error', - }, - ], - }); - }); - - it('renders error icon', () => { - expect(findErrorIcon().exists()).toBe(true); - expect(findErrorIcon().attributes('title')).toEqual('Suite Error'); - }); - }); - - describe('when there is not a suite error', () => { - beforeEach(() => { - createComponent({ - test_suites: [ - { - ...testReports.test_suites[0], - suite_error: null, - }, - ], - }); - }); - - it('does not render error icon', () => { - expect(findErrorIcon().exists()).toBe(false); - }); - }); - }); - - describe('when there are no test suites', () => { - beforeEach(() => { - createComponent({ test_suites: [] }); - }); - - it('displays the no suites to show message', () => { - expect(noSuitesToShow().exists()).toBe(true); - }); - }); -}); |