diff options
Diffstat (limited to 'spec/frontend/vue_mr_widget')
6 files changed, 412 insertions, 0 deletions
diff --git a/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js b/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js new file mode 100644 index 00000000000..49ed796d9a8 --- /dev/null +++ b/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js @@ -0,0 +1,121 @@ +import { mount, createLocalVue } from '@vue/test-utils'; +import Vuex from 'vuex'; +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; +import { GlLoadingIcon } from '@gitlab/ui'; +import { TEST_HOST } from 'helpers/test_constants'; +import ArtifactsListApp from '~/vue_merge_request_widget/components/artifacts_list_app.vue'; +import createStore from '~/vue_merge_request_widget/stores/artifacts_list'; +import { artifactsList } from './mock_data'; + +describe('Merge Requests Artifacts list app', () => { + let wrapper; + let mock; + const store = createStore(); + const localVue = createLocalVue(); + localVue.use(Vuex); + + const actionSpies = { + fetchArtifacts: jest.fn(), + }; + + beforeEach(() => { + mock = new MockAdapter(axios); + }); + + afterEach(() => { + wrapper.destroy(); + mock.restore(); + }); + + const createComponent = () => { + wrapper = mount(localVue.extend(ArtifactsListApp), { + propsData: { + endpoint: TEST_HOST, + }, + store, + methods: { + ...actionSpies, + }, + localVue, + sync: false, + }); + }; + + const findButtons = () => wrapper.findAll('button'); + const findTitle = () => wrapper.find('.js-title'); + const findTableRows = () => wrapper.findAll('tbody tr'); + + describe('while loading', () => { + beforeEach(() => { + createComponent(); + store.dispatch('requestArtifacts'); + return wrapper.vm.$nextTick(); + }); + + it('renders a loading icon', () => { + const loadingIcon = wrapper.find(GlLoadingIcon); + expect(loadingIcon.exists()).toBe(true); + }); + + it('renders loading text', () => { + expect(findTitle().text()).toBe('Loading artifacts'); + }); + + it('renders disabled buttons', () => { + const buttons = findButtons(); + expect(buttons.at(0).attributes('disabled')).toBe('disabled'); + expect(buttons.at(1).attributes('disabled')).toBe('disabled'); + }); + }); + + describe('with results', () => { + beforeEach(() => { + createComponent(); + mock.onGet(wrapper.vm.$store.state.endpoint).reply(200, artifactsList, {}); + store.dispatch('receiveArtifactsSuccess', { + data: artifactsList, + status: 200, + }); + return wrapper.vm.$nextTick(); + }); + + it('renders a title with the number of artifacts', () => { + expect(findTitle().text()).toBe('View 2 exposed artifacts'); + }); + + it('renders both buttons enabled', () => { + const buttons = findButtons(); + expect(buttons.at(0).attributes('disabled')).toBe(undefined); + expect(buttons.at(1).attributes('disabled')).toBe(undefined); + }); + + describe('on click', () => { + it('renders the list of artifacts', () => { + findTitle().trigger('click'); + wrapper.vm.$nextTick(() => { + expect(findTableRows().length).toEqual(2); + }); + }); + }); + }); + + describe('with error', () => { + beforeEach(() => { + createComponent(); + mock.onGet(wrapper.vm.$store.state.endpoint).reply(500, {}, {}); + store.dispatch('receiveArtifactsError'); + return wrapper.vm.$nextTick(); + }); + + it('renders the error state', () => { + expect(findTitle().text()).toBe('An error occurred while fetching the artifacts'); + }); + + it('renders disabled buttons', () => { + const buttons = findButtons(); + expect(buttons.at(0).attributes('disabled')).toBe('disabled'); + expect(buttons.at(1).attributes('disabled')).toBe('disabled'); + }); + }); +}); diff --git a/spec/frontend/vue_mr_widget/components/artifacts_list_spec.js b/spec/frontend/vue_mr_widget/components/artifacts_list_spec.js new file mode 100644 index 00000000000..8c805faf574 --- /dev/null +++ b/spec/frontend/vue_mr_widget/components/artifacts_list_spec.js @@ -0,0 +1,61 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import { GlLink } from '@gitlab/ui'; +import ArtifactsList from '~/vue_merge_request_widget/components/artifacts_list.vue'; +import { artifactsList } from './mock_data'; + +describe('Artifacts List', () => { + let wrapper; + const localVue = createLocalVue(); + + const data = { + artifacts: artifactsList, + }; + + const mountComponent = props => { + wrapper = shallowMount(localVue.extend(ArtifactsList), { + propsData: { + ...props, + }, + sync: false, + localVue, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + beforeEach(() => { + mountComponent(data); + }); + + it('renders list of artifacts', () => { + expect(wrapper.findAll('tbody tr').length).toEqual(data.artifacts.length); + }); + + it('renders link for the artifact', () => { + expect(wrapper.find(GlLink).attributes('href')).toEqual(data.artifacts[0].url); + }); + + it('renders artifact name', () => { + expect(wrapper.find(GlLink).text()).toEqual(data.artifacts[0].text); + }); + + it('renders job url', () => { + expect( + wrapper + .findAll(GlLink) + .at(1) + .attributes('href'), + ).toEqual(data.artifacts[0].job_path); + }); + + it('renders job name', () => { + expect( + wrapper + .findAll(GlLink) + .at(1) + .text(), + ).toEqual(data.artifacts[0].job_name); + }); +}); diff --git a/spec/frontend/vue_mr_widget/components/mock_data.js b/spec/frontend/vue_mr_widget/components/mock_data.js new file mode 100644 index 00000000000..39c7d75cda5 --- /dev/null +++ b/spec/frontend/vue_mr_widget/components/mock_data.js @@ -0,0 +1,15 @@ +// eslint-disable-next-line import/prefer-default-export +export const artifactsList = [ + { + text: 'result.txt', + url: 'bar', + job_name: 'generate-artifact', + job_path: 'bar', + }, + { + text: 'foo.txt', + url: 'foo', + job_name: 'foo-artifact', + job_path: 'foo', + }, +]; diff --git a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js new file mode 100644 index 00000000000..4c9507223a1 --- /dev/null +++ b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js @@ -0,0 +1,105 @@ +import { mount } from '@vue/test-utils'; +import MrCollapsibleSection from '~/vue_merge_request_widget/components/mr_collapsible_extension.vue'; +import { GlLoadingIcon } from '@gitlab/ui'; + +describe('Merge Request Collapsible Extension', () => { + let wrapper; + const data = { + title: 'View artifacts', + }; + + const mountComponent = props => { + wrapper = mount(MrCollapsibleSection, { + propsData: { + ...props, + }, + slots: { + default: '<div class="js-slot">Foo</div>', + }, + }); + }; + + const findTitle = () => wrapper.find('.js-title'); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('while collapsed', () => { + beforeEach(() => { + mountComponent(data); + }); + + it('renders provided title', () => { + expect(findTitle().text()).toBe(data.title); + }); + + it('renders angle-right icon', () => { + expect(wrapper.vm.arrowIconName).toBe('angle-right'); + }); + + describe('onClick', () => { + beforeEach(() => { + wrapper.find('button').trigger('click'); + }); + + it('rendes the provided slot', () => { + expect(wrapper.find('.js-slot').isVisible()).toBe(true); + }); + + it('renders `Collapse` as the title', () => { + expect(findTitle().text()).toBe('Collapse'); + }); + + it('renders angle-down icon', () => { + expect(wrapper.vm.arrowIconName).toBe('angle-down'); + }); + }); + }); + + describe('while loading', () => { + beforeEach(() => { + mountComponent(Object.assign({}, data, { isLoading: true })); + }); + + it('renders the buttons disabled', () => { + expect( + wrapper + .findAll('button') + .at(0) + .attributes('disabled'), + ).toEqual('disabled'); + expect( + wrapper + .findAll('button') + .at(1) + .attributes('disabled'), + ).toEqual('disabled'); + }); + + it('renders loading spinner', () => { + expect(wrapper.find(GlLoadingIcon).isVisible()).toBe(true); + }); + }); + + describe('with error', () => { + beforeEach(() => { + mountComponent(Object.assign({}, data, { hasError: true })); + }); + + it('renders the buttons disabled', () => { + expect( + wrapper + .findAll('button') + .at(0) + .attributes('disabled'), + ).toEqual('disabled'); + expect( + wrapper + .findAll('button') + .at(1) + .attributes('disabled'), + ).toEqual('disabled'); + }); + }); +}); diff --git a/spec/frontend/vue_mr_widget/stores/artifacts_list/getters_spec.js b/spec/frontend/vue_mr_widget/stores/artifacts_list/getters_spec.js new file mode 100644 index 00000000000..62ee6f5f189 --- /dev/null +++ b/spec/frontend/vue_mr_widget/stores/artifacts_list/getters_spec.js @@ -0,0 +1,32 @@ +import { title } from '~/vue_merge_request_widget/stores/artifacts_list/getters'; +import state from '~/vue_merge_request_widget/stores/artifacts_list/state'; +import { artifactsList } from '../../components/mock_data'; + +describe('Artifacts Store Getters', () => { + let localState; + + beforeEach(() => { + localState = state(); + }); + + describe('title', () => { + describe('when is loading', () => { + it('returns loading message', () => { + localState.isLoading = true; + expect(title(localState)).toBe('Loading artifacts'); + }); + }); + describe('when has error', () => { + it('returns error message', () => { + localState.hasError = true; + expect(title(localState)).toBe('An error occurred while fetching the artifacts'); + }); + }); + describe('when it has artifacts', () => { + it('returns artifacts message', () => { + localState.artifacts = artifactsList; + expect(title(localState)).toBe('View 2 exposed artifacts'); + }); + }); + }); +}); diff --git a/spec/frontend/vue_mr_widget/stores/artifacts_list/mutations_spec.js b/spec/frontend/vue_mr_widget/stores/artifacts_list/mutations_spec.js new file mode 100644 index 00000000000..ea89fdb72e9 --- /dev/null +++ b/spec/frontend/vue_mr_widget/stores/artifacts_list/mutations_spec.js @@ -0,0 +1,78 @@ +import state from '~/vue_merge_request_widget/stores/artifacts_list/state'; +import mutations from '~/vue_merge_request_widget/stores/artifacts_list/mutations'; +import * as types from '~/vue_merge_request_widget/stores/artifacts_list/mutation_types'; + +describe('Artifacts Store Mutations', () => { + let stateCopy; + + beforeEach(() => { + stateCopy = state(); + }); + + describe('SET_ENDPOINT', () => { + it('should set endpoint', () => { + mutations[types.SET_ENDPOINT](stateCopy, 'endpoint.json'); + + expect(stateCopy.endpoint).toEqual('endpoint.json'); + }); + }); + + describe('REQUEST_ARTIFACTS', () => { + it('should set isLoading to true', () => { + mutations[types.REQUEST_ARTIFACTS](stateCopy); + + expect(stateCopy.isLoading).toEqual(true); + }); + }); + + describe('REECEIVE_ARTIFACTS_SUCCESS', () => { + const artifacts = [ + { + text: 'result.txt', + url: 'asda', + job_name: 'generate-artifact', + job_path: 'asda', + }, + { + text: 'file.txt', + url: 'asda', + job_name: 'generate-artifact', + job_path: 'asda', + }, + ]; + + beforeEach(() => { + mutations[types.RECEIVE_ARTIFACTS_SUCCESS](stateCopy, artifacts); + }); + + it('should set isLoading to false', () => { + expect(stateCopy.isLoading).toEqual(false); + }); + + it('should set hasError to false', () => { + expect(stateCopy.hasError).toEqual(false); + }); + + it('should set list of artifacts', () => { + expect(stateCopy.artifacts).toEqual(artifacts); + }); + }); + + describe('RECEIVE_ARTIFACTS_ERROR', () => { + beforeEach(() => { + mutations[types.RECEIVE_ARTIFACTS_ERROR](stateCopy); + }); + + it('should set isLoading to false', () => { + expect(stateCopy.isLoading).toEqual(false); + }); + + it('should set hasError to true', () => { + expect(stateCopy.hasError).toEqual(true); + }); + + it('should set list of artifacts as empty array', () => { + expect(stateCopy.artifacts).toEqual([]); + }); + }); +}); |