summaryrefslogtreecommitdiff
path: root/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js')
-rw-r--r--spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js175
1 files changed, 175 insertions, 0 deletions
diff --git a/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
new file mode 100644
index 00000000000..d6b394a42c6
--- /dev/null
+++ b/spec/frontend/pages/import/bulk_imports/history/components/bulk_imports_history_app_spec.js
@@ -0,0 +1,175 @@
+import { GlEmptyState, GlLoadingIcon, GlTable } from '@gitlab/ui';
+import { mount, shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import PaginationBar from '~/import_entities/components/pagination_bar.vue';
+import BulkImportsHistoryApp from '~/pages/import/bulk_imports/history/components/bulk_imports_history_app.vue';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+
+describe('BulkImportsHistoryApp', () => {
+ const API_URL = '/api/v4/bulk_imports/entities';
+
+ const DEFAULT_HEADERS = {
+ 'x-page': 1,
+ 'x-per-page': 20,
+ 'x-next-page': 2,
+ 'x-total': 22,
+ 'x-total-pages': 2,
+ 'x-prev-page': null,
+ };
+ const DUMMY_RESPONSE = [
+ {
+ id: 1,
+ bulk_import_id: 1,
+ status: 'finished',
+ source_full_path: 'top-level-group-12',
+ destination_name: 'top-level-group-12',
+ destination_namespace: 'h5bp',
+ created_at: '2021-07-08T10:03:44.743Z',
+ failures: [],
+ },
+ {
+ id: 2,
+ bulk_import_id: 2,
+ status: 'failed',
+ source_full_path: 'autodevops-demo',
+ destination_name: 'autodevops-demo',
+ destination_namespace: 'flightjs',
+ parent_id: null,
+ namespace_id: null,
+ project_id: null,
+ created_at: '2021-07-13T12:52:26.664Z',
+ updated_at: '2021-07-13T13:34:49.403Z',
+ failures: [
+ {
+ pipeline_class: 'BulkImports::Groups::Pipelines::GroupPipeline',
+ pipeline_step: 'loader',
+ exception_class: 'ActiveRecord::RecordNotUnique',
+ correlation_id_value: '01FAFYSYZ7XPF3P9NSMTS693SZ',
+ created_at: '2021-07-13T13:34:49.344Z',
+ },
+ ],
+ },
+ ];
+
+ let wrapper;
+ let mock;
+
+ function createComponent({ shallow = true } = {}) {
+ const mountFn = shallow ? shallowMount : mount;
+ wrapper = mountFn(BulkImportsHistoryApp);
+ }
+
+ const originalApiVersion = gon.api_version;
+ beforeAll(() => {
+ gon.api_version = 'v4';
+ });
+
+ afterAll(() => {
+ gon.api_version = originalApiVersion;
+ });
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ wrapper.destroy();
+ });
+
+ describe('general behavior', () => {
+ it('renders loading state when loading', () => {
+ createComponent();
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ });
+
+ it('renders empty state when no data is available', async () => {
+ mock.onGet(API_URL).reply(200, [], DEFAULT_HEADERS);
+ createComponent();
+ await axios.waitForAll();
+
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.find(GlEmptyState).exists()).toBe(true);
+ });
+
+ it('renders table with data when history is available', async () => {
+ mock.onGet(API_URL).reply(200, DUMMY_RESPONSE, DEFAULT_HEADERS);
+ createComponent();
+ await axios.waitForAll();
+
+ const table = wrapper.find(GlTable);
+ expect(table.exists()).toBe(true);
+ // can't use .props() or .attributes() here
+ expect(table.vm.$attrs.items).toHaveLength(DUMMY_RESPONSE.length);
+ });
+
+ it('changes page when requested by pagination bar', async () => {
+ const NEW_PAGE = 4;
+
+ mock.onGet(API_URL).reply(200, DUMMY_RESPONSE, DEFAULT_HEADERS);
+ createComponent();
+ await axios.waitForAll();
+ mock.resetHistory();
+
+ wrapper.findComponent(PaginationBar).vm.$emit('set-page', NEW_PAGE);
+ await axios.waitForAll();
+
+ expect(mock.history.get.length).toBe(1);
+ expect(mock.history.get[0].params).toStrictEqual(expect.objectContaining({ page: NEW_PAGE }));
+ });
+ });
+
+ it('changes page size when requested by pagination bar', async () => {
+ const NEW_PAGE_SIZE = 4;
+
+ mock.onGet(API_URL).reply(200, DUMMY_RESPONSE, DEFAULT_HEADERS);
+ createComponent();
+ await axios.waitForAll();
+ mock.resetHistory();
+
+ wrapper.findComponent(PaginationBar).vm.$emit('set-page-size', NEW_PAGE_SIZE);
+ await axios.waitForAll();
+
+ expect(mock.history.get.length).toBe(1);
+ expect(mock.history.get[0].params).toStrictEqual(
+ expect.objectContaining({ per_page: NEW_PAGE_SIZE }),
+ );
+ });
+
+ describe('details button', () => {
+ beforeEach(() => {
+ mock.onGet(API_URL).reply(200, DUMMY_RESPONSE, DEFAULT_HEADERS);
+ createComponent({ shallow: false });
+ return axios.waitForAll();
+ });
+
+ it('renders details button if relevant item has failures', async () => {
+ expect(
+ extendedWrapper(wrapper.find('tbody').findAll('tr').at(1)).findByText('Details').exists(),
+ ).toBe(true);
+ });
+
+ it('does not render details button if relevant item has no failures', () => {
+ expect(
+ extendedWrapper(wrapper.find('tbody').findAll('tr').at(0)).findByText('Details').exists(),
+ ).toBe(false);
+ });
+
+ it('expands details when details button is clicked', async () => {
+ const ORIGINAL_ROW_INDEX = 1;
+ await extendedWrapper(wrapper.find('tbody').findAll('tr').at(ORIGINAL_ROW_INDEX))
+ .findByText('Details')
+ .trigger('click');
+
+ const detailsRowContent = wrapper
+ .find('tbody')
+ .findAll('tr')
+ .at(ORIGINAL_ROW_INDEX + 1)
+ .find('pre');
+
+ expect(detailsRowContent.exists()).toBe(true);
+ expect(JSON.parse(detailsRowContent.text())).toStrictEqual(DUMMY_RESPONSE[1].failures);
+ });
+ });
+});