diff options
Diffstat (limited to 'spec/frontend')
-rw-r--r-- | spec/frontend/alert_management/components/alert_details_spec.js | 98 | ||||
-rw-r--r-- | spec/frontend/alert_management/components/alert_summary_row_spec.js | 40 | ||||
-rw-r--r-- | spec/frontend/helpers/vue_test_utils_helper.js | 7 | ||||
-rw-r--r-- | spec/frontend/invite_members/components/invite_members_modal_spec.js | 115 | ||||
-rw-r--r-- | spec/frontend/invite_members/components/invite_members_trigger_spec.js | 58 | ||||
-rw-r--r-- | spec/frontend/registry/settings/graphql/cache_updated_spec.js | 56 | ||||
-rw-r--r-- | spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap | 101 | ||||
-rw-r--r-- | spec/frontend/registry/shared/utils_spec.js | 27 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/alert_details_table_spec.js (renamed from spec/frontend/vue_shared/components/alert_detail_table_spec.js) | 8 |
9 files changed, 470 insertions, 40 deletions
diff --git a/spec/frontend/alert_management/components/alert_details_spec.js b/spec/frontend/alert_management/components/alert_details_spec.js index 8aa26dbca3b..910bb31b573 100644 --- a/spec/frontend/alert_management/components/alert_details_spec.js +++ b/spec/frontend/alert_management/components/alert_details_spec.js @@ -2,8 +2,10 @@ import { mount, shallowMount } from '@vue/test-utils'; import { GlAlert, GlLoadingIcon } from '@gitlab/ui'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue'; import AlertDetails from '~/alert_management/components/alert_details.vue'; +import AlertSummaryRow from '~/alert_management/components/alert_summary_row.vue'; import createIssueMutation from '~/alert_management/graphql/mutations/create_issue_from_alert.mutation.graphql'; import { joinPaths } from '~/lib/utils/url_utility'; import { @@ -24,31 +26,36 @@ describe('AlertDetails', () => { const $router = { replace: jest.fn() }; function mountComponent({ data, loading = false, mountMethod = shallowMount, stubs = {} } = {}) { - wrapper = mountMethod(AlertDetails, { - provide: { - alertId: 'alertId', - projectPath, - projectIssuesPath, - projectId, - }, - data() { - return { alert: { ...mockAlert }, sidebarStatus: false, ...data }; - }, - mocks: { - $apollo: { - mutate: jest.fn(), - queries: { - alert: { - loading, + wrapper = extendedWrapper( + mountMethod(AlertDetails, { + provide: { + alertId: 'alertId', + projectPath, + projectIssuesPath, + projectId, + }, + data() { + return { alert: { ...mockAlert }, sidebarStatus: false, ...data }; + }, + mocks: { + $apollo: { + mutate: jest.fn(), + queries: { + alert: { + loading, + }, + sidebarStatus: {}, }, - sidebarStatus: {}, }, + $router, + $route: { params: {} }, }, - $router, - $route: { params: {} }, - }, - stubs, - }); + stubs: { + ...stubs, + AlertSummaryRow, + }, + }), + ); } beforeEach(() => { @@ -62,9 +69,10 @@ describe('AlertDetails', () => { mock.restore(); }); - const findCreateIncidentBtn = () => wrapper.find('[data-testid="createIncidentBtn"]'); - const findViewIncidentBtn = () => wrapper.find('[data-testid="viewIncidentBtn"]'); - const findIncidentCreationAlert = () => wrapper.find('[data-testid="incidentCreationError"]'); + const findCreateIncidentBtn = () => wrapper.findByTestId('createIncidentBtn'); + const findViewIncidentBtn = () => wrapper.findByTestId('viewIncidentBtn'); + const findIncidentCreationAlert = () => wrapper.findByTestId('incidentCreationError'); + const findEnvironmentLink = () => wrapper.findByTestId('environmentUrl'); const findDetailsTable = () => wrapper.find(AlertDetailsTable); describe('Alert details', () => { @@ -74,7 +82,7 @@ describe('AlertDetails', () => { }); it('shows an empty state', () => { - expect(wrapper.find('[data-testid="alertDetailsTabs"]').exists()).toBe(false); + expect(wrapper.findByTestId('alertDetailsTabs').exists()).toBe(false); }); }); @@ -84,28 +92,26 @@ describe('AlertDetails', () => { }); it('renders a tab with overview information', () => { - expect(wrapper.find('[data-testid="overview"]').exists()).toBe(true); + expect(wrapper.findByTestId('overview').exists()).toBe(true); }); it('renders a tab with an activity feed', () => { - expect(wrapper.find('[data-testid="activity"]').exists()).toBe(true); + expect(wrapper.findByTestId('activity').exists()).toBe(true); }); it('renders severity', () => { - expect(wrapper.find('[data-testid="severity"]').text()).toBe( + expect(wrapper.findByTestId('severity').text()).toBe( ALERTS_SEVERITY_LABELS[mockAlert.severity], ); }); it('renders a title', () => { - expect(wrapper.find('[data-testid="title"]').text()).toBe(mockAlert.title); + expect(wrapper.findByTestId('title').text()).toBe(mockAlert.title); }); it('renders a start time', () => { - expect(wrapper.find('[data-testid="startTimeItem"]').exists()).toBe(true); - expect(wrapper.find('[data-testid="startTimeItem"]').props().time).toBe( - mockAlert.startedAt, - ); + expect(wrapper.findByTestId('startTimeItem').exists()).toBe(true); + expect(wrapper.findByTestId('startTimeItem').props('time')).toBe(mockAlert.startedAt); }); }); @@ -114,6 +120,8 @@ describe('AlertDetails', () => { field | data | isShown ${'eventCount'} | ${1} | ${true} ${'eventCount'} | ${undefined} | ${false} + ${'environment'} | ${undefined} | ${false} + ${'environment'} | ${'Production'} | ${true} ${'monitoringTool'} | ${'New Relic'} | ${true} ${'monitoringTool'} | ${undefined} | ${false} ${'service'} | ${'Prometheus'} | ${true} @@ -126,15 +134,29 @@ describe('AlertDetails', () => { }); it(`${field} is ${isShown ? 'displayed' : 'hidden'} correctly`, () => { + const element = wrapper.findByTestId(field); if (isShown) { - expect(wrapper.find(`[data-testid="${field}"]`).text()).toBe(data.toString()); + expect(element.text()).toContain(data.toString()); } else { - expect(wrapper.find(`[data-testid="${field}"]`).exists()).toBe(false); + expect(wrapper.findByTestId(field).exists()).toBe(false); } }); }); }); + describe('environment URL fields', () => { + it('should show the environment URL when available', () => { + const environment = 'Production'; + const environmentUrl = 'fake/url'; + mountComponent({ + data: { alert: { ...mockAlert, environment, environmentUrl } }, + }); + + expect(findEnvironmentLink().text()).toBe(environment); + expect(findEnvironmentLink().attributes('href')).toBe(environmentUrl); + }); + }); + describe('Create incident from alert', () => { it('should display "View incident" button that links the incident page when incident exists', () => { const issueIid = '3'; @@ -222,7 +244,7 @@ describe('AlertDetails', () => { mountComponent({ data: { errored: true, sidebarErrorMessage: '<span data-testid="htmlError" />' }, }); - expect(wrapper.find('[data-testid="htmlError"]').exists()).toBe(true); + expect(wrapper.findByTestId('htmlError').exists()).toBe(true); }); it('does not display an error when dismissed', () => { @@ -232,7 +254,7 @@ describe('AlertDetails', () => { }); describe('header', () => { - const findHeader = () => wrapper.find('[data-testid="alert-header"]'); + const findHeader = () => wrapper.findByTestId('alert-header'); const stubs = { TimeAgoTooltip: { template: '<span>now</span>' } }; describe('individual header fields', () => { diff --git a/spec/frontend/alert_management/components/alert_summary_row_spec.js b/spec/frontend/alert_management/components/alert_summary_row_spec.js new file mode 100644 index 00000000000..47c715c089a --- /dev/null +++ b/spec/frontend/alert_management/components/alert_summary_row_spec.js @@ -0,0 +1,40 @@ +import { shallowMount } from '@vue/test-utils'; +import AlertSummaryRow from '~/alert_management/components/alert_summary_row.vue'; + +const label = 'a label'; +const value = 'a value'; + +describe('AlertSummaryRow', () => { + let wrapper; + + function mountComponent({ mountMethod = shallowMount, props, defaultSlot } = {}) { + wrapper = mountMethod(AlertSummaryRow, { + propsData: props, + scopedSlots: { + default: defaultSlot, + }, + }); + } + + afterEach(() => { + if (wrapper) { + wrapper.destroy(); + wrapper = null; + } + }); + + describe('Alert Summary Row', () => { + beforeEach(() => { + mountComponent({ + props: { + label, + }, + defaultSlot: `<span class="value">${value}</span>`, + }); + }); + + it('should display a label and a value', () => { + expect(wrapper.text()).toBe(`${label} ${value}`); + }); + }); +}); diff --git a/spec/frontend/helpers/vue_test_utils_helper.js b/spec/frontend/helpers/vue_test_utils_helper.js index 68326e37ae7..ead898f04d3 100644 --- a/spec/frontend/helpers/vue_test_utils_helper.js +++ b/spec/frontend/helpers/vue_test_utils_helper.js @@ -33,3 +33,10 @@ export const waitForMutation = (store, expectedMutationType) => } }); }); + +export const extendedWrapper = wrapper => + Object.defineProperty(wrapper, 'findByTestId', { + value(id) { + return this.find(`[data-testid="${id}"]`); + }, + }); diff --git a/spec/frontend/invite_members/components/invite_members_modal_spec.js b/spec/frontend/invite_members/components/invite_members_modal_spec.js new file mode 100644 index 00000000000..0be0fbbde2d --- /dev/null +++ b/spec/frontend/invite_members/components/invite_members_modal_spec.js @@ -0,0 +1,115 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlDropdown, GlDropdownItem, GlDatepicker, GlSprintf, GlLink } from '@gitlab/ui'; +import Api from '~/api'; +import InviteMembersModal from '~/invite_members/components/invite_members_modal.vue'; + +const groupId = '1'; +const groupName = 'testgroup'; +const accessLevels = { Guest: 10, Reporter: 20, Developer: 30, Maintainer: 40, Owner: 50 }; +const defaultAccessLevel = '10'; +const helpLink = 'https://example.com'; + +const createComponent = () => { + return shallowMount(InviteMembersModal, { + propsData: { + groupId, + groupName, + accessLevels, + defaultAccessLevel, + helpLink, + }, + stubs: { + GlSprintf, + 'gl-modal': '<div><slot name="modal-footer"></slot><slot></slot></div>', + }, + }); +}; + +describe('InviteMembersModal', () => { + let wrapper; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + const findDropdown = () => wrapper.find(GlDropdown); + const findDropdownItems = () => wrapper.findAll(GlDropdownItem); + const findDatepicker = () => wrapper.find(GlDatepicker); + const findLink = () => wrapper.find(GlLink); + const findCancelButton = () => wrapper.find({ ref: 'cancelButton' }); + const findInviteButton = () => wrapper.find({ ref: 'inviteButton' }); + + describe('rendering the modal', () => { + beforeEach(() => { + wrapper = createComponent(); + }); + + it('renders the modal with the correct title', () => { + expect(wrapper.attributes('title')).toBe('Invite team members'); + }); + + it('renders the Cancel button text correctly', () => { + expect(findCancelButton().text()).toBe('Cancel'); + }); + + it('renders the Invite button text correctly', () => { + expect(findInviteButton().text()).toBe('Invite'); + }); + + describe('rendering the access levels dropdown', () => { + it('sets the default dropdown text to the default access level name', () => { + expect(findDropdown().attributes('text')).toBe('Guest'); + }); + + it('renders dropdown items for each accessLevel', () => { + expect(findDropdownItems()).toHaveLength(5); + }); + }); + + describe('rendering the help link', () => { + it('renders the correct link', () => { + expect(findLink().attributes('href')).toBe(helpLink); + }); + }); + + describe('rendering the access expiration date field', () => { + it('renders the datepicker', () => { + expect(findDatepicker()).toExist(); + }); + }); + }); + + describe('submitting the invite form', () => { + const postData = { + user_id: '1', + access_level: '10', + expires_at: new Date(), + format: 'json', + }; + + beforeEach(() => { + wrapper = createComponent(); + + jest.spyOn(Api, 'inviteGroupMember').mockResolvedValue({ data: postData }); + wrapper.vm.$toast = { show: jest.fn() }; + + wrapper.vm.submitForm(postData); + }); + + it('calls Api inviteGroupMember with the correct params', () => { + expect(Api.inviteGroupMember).toHaveBeenCalledWith(groupId, postData); + }); + + describe('when the invite was sent successfully', () => { + const toastMessageSuccessful = 'Users were succesfully added'; + + it('displays the successful toastMessage', () => { + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith( + toastMessageSuccessful, + wrapper.vm.toastOptions, + ); + }); + }); + }); +}); diff --git a/spec/frontend/invite_members/components/invite_members_trigger_spec.js b/spec/frontend/invite_members/components/invite_members_trigger_spec.js new file mode 100644 index 00000000000..450d37a9748 --- /dev/null +++ b/spec/frontend/invite_members/components/invite_members_trigger_spec.js @@ -0,0 +1,58 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlIcon, GlLink } from '@gitlab/ui'; +import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue'; + +const displayText = 'Invite team members'; +const icon = 'plus'; + +const createComponent = (props = {}) => { + return shallowMount(InviteMembersTrigger, { + propsData: { + displayText, + ...props, + }, + }); +}; + +describe('InviteMembersTrigger', () => { + let wrapper; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + describe('displayText', () => { + const findLink = () => wrapper.find(GlLink); + + beforeEach(() => { + wrapper = createComponent(); + }); + + it('includes the correct displayText for the link', () => { + expect(findLink().text()).toBe(displayText); + }); + }); + + describe('icon', () => { + const findIcon = () => wrapper.find(GlIcon); + + it('includes the correct icon when an icon is sent', () => { + wrapper = createComponent({ icon }); + + expect(findIcon().attributes('name')).toBe(icon); + }); + + it('does not include an icon when icon is not sent', () => { + wrapper = createComponent(); + + expect(findIcon().exists()).toBe(false); + }); + + it('does not include an icon when empty string is sent', () => { + wrapper = createComponent({ icon: '' }); + + expect(findIcon().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/registry/settings/graphql/cache_updated_spec.js b/spec/frontend/registry/settings/graphql/cache_updated_spec.js new file mode 100644 index 00000000000..e5f69a08285 --- /dev/null +++ b/spec/frontend/registry/settings/graphql/cache_updated_spec.js @@ -0,0 +1,56 @@ +import { updateContainerExpirationPolicy } from '~/registry/settings/graphql/utils/cache_update'; +import expirationPolicyQuery from '~/registry/settings/graphql/queries/get_expiration_policy.graphql'; + +describe('Registry settings cache update', () => { + let client; + + const payload = { + data: { + updateContainerExpirationPolicy: { + containerExpirationPolicy: { + enabled: true, + }, + }, + }, + }; + + const cacheMock = { + project: { + containerExpirationPolicy: { + enabled: false, + }, + }, + }; + + const queryAndVariables = { + query: expirationPolicyQuery, + variables: { projectPath: 'foo' }, + }; + + beforeEach(() => { + client = { + readQuery: jest.fn().mockReturnValue(cacheMock), + writeQuery: jest.fn(), + }; + }); + describe('Registry settings cache update', () => { + it('calls readQuery', () => { + updateContainerExpirationPolicy('foo')(client, payload); + expect(client.readQuery).toHaveBeenCalledWith(queryAndVariables); + }); + + it('writes the correct result in the cache', () => { + updateContainerExpirationPolicy('foo')(client, payload); + expect(client.writeQuery).toHaveBeenCalledWith({ + ...queryAndVariables, + data: { + project: { + containerExpirationPolicy: { + enabled: true, + }, + }, + }, + }); + }); + }); +}); diff --git a/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap b/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap new file mode 100644 index 00000000000..1c52249fbf7 --- /dev/null +++ b/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap @@ -0,0 +1,101 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Utils formOptionsGenerator returns an object containing cadence 1`] = ` +Array [ + Object { + "default": true, + "key": "EVERY_DAY", + "label": "Every day", + }, + Object { + "default": false, + "key": "EVERY_WEEK", + "label": "Every week", + }, + Object { + "default": false, + "key": "EVERY_TWO_WEEKS", + "label": "Every two weeks", + }, + Object { + "default": false, + "key": "EVERY_MONTH", + "label": "Every month", + }, + Object { + "default": false, + "key": "EVERY_THREE_MONTHS", + "label": "Every three months", + }, +] +`; + +exports[`Utils formOptionsGenerator returns an object containing keepN 1`] = ` +Array [ + Object { + "default": false, + "key": "ONE_TAG", + "label": "1 tag per image name", + "variable": 1, + }, + Object { + "default": false, + "key": "FIVE_TAGS", + "label": "5 tags per image name", + "variable": 5, + }, + Object { + "default": true, + "key": "TEN_TAGS", + "label": "10 tags per image name", + "variable": 10, + }, + Object { + "default": false, + "key": "TWENTY_FIVE_TAGS", + "label": "25 tags per image name", + "variable": 25, + }, + Object { + "default": false, + "key": "FIFTY_TAGS", + "label": "50 tags per image name", + "variable": 50, + }, + Object { + "default": false, + "key": "ONE_HUNDRED_TAGS", + "label": "100 tags per image name", + "variable": 100, + }, +] +`; + +exports[`Utils formOptionsGenerator returns an object containing olderThan 1`] = ` +Array [ + Object { + "default": false, + "key": "SEVEN_DAYS", + "label": "7 day until tags are automatically removed", + "variable": 7, + }, + Object { + "default": false, + "key": "FOURTEEN_DAYS", + "label": "14 day until tags are automatically removed", + "variable": 14, + }, + Object { + "default": false, + "key": "THIRTY_DAYS", + "label": "30 day until tags are automatically removed", + "variable": 30, + }, + Object { + "default": true, + "key": "NINETY_DAYS", + "label": "90 day until tags are automatically removed", + "variable": 90, + }, +] +`; diff --git a/spec/frontend/registry/shared/utils_spec.js b/spec/frontend/registry/shared/utils_spec.js new file mode 100644 index 00000000000..a6133fa96d6 --- /dev/null +++ b/spec/frontend/registry/shared/utils_spec.js @@ -0,0 +1,27 @@ +import { formOptionsGenerator, optionLabelGenerator } from '~/registry/shared/utils'; + +describe('Utils', () => { + describe('optionLabelGenerator', () => { + it('returns an array with a set label', () => { + const result = optionLabelGenerator([{ variable: 1 }, { variable: 2 }], '%d day', '%d days'); + expect(result).toEqual([{ variable: 1, label: '1 day' }, { variable: 2, label: '2 days' }]); + }); + }); + + describe('formOptionsGenerator', () => { + it('returns an object containing olderThan', () => { + expect(formOptionsGenerator().olderThan).toBeDefined(); + expect(formOptionsGenerator().olderThan).toMatchSnapshot(); + }); + + it('returns an object containing cadence', () => { + expect(formOptionsGenerator().cadence).toBeDefined(); + expect(formOptionsGenerator().cadence).toMatchSnapshot(); + }); + + it('returns an object containing keepN', () => { + expect(formOptionsGenerator().keepN).toBeDefined(); + expect(formOptionsGenerator().keepN).toMatchSnapshot(); + }); + }); +}); diff --git a/spec/frontend/vue_shared/components/alert_detail_table_spec.js b/spec/frontend/vue_shared/components/alert_details_table_spec.js index 608a93d11fd..dbdb7705d3c 100644 --- a/spec/frontend/vue_shared/components/alert_detail_table_spec.js +++ b/spec/frontend/vue_shared/components/alert_details_table_spec.js @@ -1,5 +1,5 @@ +import { GlLoadingIcon, GlTable } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; -import { GlTable, GlLoadingIcon } from '@gitlab/ui'; import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue'; const mockAlert = { @@ -61,8 +61,10 @@ describe('AlertDetails', () => { }); describe('with table data', () => { + const environment = 'myEnvironment'; + const environmentUrl = 'fake/url'; beforeEach(() => { - mountComponent(); + mountComponent({ alert: { ...mockAlert, environment, environmentUrl } }); }); it('renders a table', () => { @@ -80,6 +82,7 @@ describe('AlertDetails', () => { expect(findTableField(fields, 'Title').exists()).toBe(true); expect(findTableField(fields, 'Severity').exists()).toBe(true); expect(findTableField(fields, 'Status').exists()).toBe(true); + expect(findTableField(fields, 'Environment').exists()).toBe(true); }); it('should not show disallowed alert fields', () => { @@ -89,6 +92,7 @@ describe('AlertDetails', () => { expect(findTableField(fields, 'Todos').exists()).toBe(false); expect(findTableField(fields, 'Notes').exists()).toBe(false); expect(findTableField(fields, 'Assignees').exists()).toBe(false); + expect(findTableField(fields, 'EnvironmentUrl').exists()).toBe(false); }); }); }); |