From d18b7dc5eea84db5008986c6879a24ad7f6462a6 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 10 Mar 2022 18:09:14 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../__snapshots__/settings_form_spec.js.snap | 2 +- .../settings/components/settings_form_spec.js | 26 ++-- .../project/settings/graphql/cache_updated_spec.js | 25 ++- .../learn_gitlab/components/learn_gitlab_spec.js | 12 -- spec/frontend/search/topbar/components/app_spec.js | 33 +--- .../components/training_provider_list_spec.js | 7 +- spec/frontend/security_configuration/mock_data.js | 12 +- .../user_avatar/user_avatar_image_spec.js | 172 ++++++++++++++++----- 8 files changed, 180 insertions(+), 109 deletions(-) (limited to 'spec/frontend') diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/settings_form_spec.js.snap b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/settings_form_spec.js.snap index 9938357ed24..841a9bf8290 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/settings_form_spec.js.snap +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/settings_form_spec.js.snap @@ -58,7 +58,7 @@ exports[`Settings Form Remove regex matches snapshot 1`] = ` error="" label="Remove tags matching:" name="remove-regex" - placeholder=".*" + placeholder="" value="asdasdssssdfdf" /> `; diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js index 625aa37fc0f..266f953c3e0 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/settings_form_spec.js @@ -49,6 +49,11 @@ describe('Settings Form', () => { const findOlderThanDropdown = () => wrapper.find('[data-testid="older-than-dropdown"]'); const findRemoveRegexInput = () => wrapper.find('[data-testid="remove-regex-input"]'); + const submitForm = async () => { + findForm().trigger('submit'); + return waitForPromises(); + }; + const mountComponent = ({ props = defaultProps, data, @@ -318,27 +323,24 @@ describe('Settings Form', () => { mutationResolver: jest.fn().mockResolvedValue(expirationPolicyMutationPayload()), }); - findForm().trigger('submit'); - await waitForPromises(); - await nextTick(); + await submitForm(); expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_SUCCESS_MESSAGE); }); describe('when submit fails', () => { describe('user recoverable errors', () => { - it('when there is an error is shown in a toast', async () => { + it('when there is an error is shown in the nameRegex field t', async () => { mountComponentWithApollo({ mutationResolver: jest .fn() .mockResolvedValue(expirationPolicyMutationPayload({ errors: ['foo'] })), }); - findForm().trigger('submit'); - await waitForPromises(); - await nextTick(); + await submitForm(); - expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('foo'); + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_ERROR_MESSAGE); + expect(findRemoveRegexInput().props('error')).toBe('foo'); }); }); @@ -348,9 +350,7 @@ describe('Settings Form', () => { mutationResolver: jest.fn().mockRejectedValue(expirationPolicyMutationPayload()), }); - findForm().trigger('submit'); - await waitForPromises(); - await nextTick(); + await submitForm(); expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_ERROR_MESSAGE); }); @@ -367,9 +367,7 @@ describe('Settings Form', () => { }); mountComponent({ mocks: { $apollo: { mutate } } }); - findForm().trigger('submit'); - await waitForPromises(); - await nextTick(); + await submitForm(); expect(findKeepRegexInput().props('error')).toEqual('baz'); }); diff --git a/spec/frontend/packages_and_registries/settings/project/settings/graphql/cache_updated_spec.js b/spec/frontend/packages_and_registries/settings/project/settings/graphql/cache_updated_spec.js index 4d6bd65bd93..76d5f8a6659 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/graphql/cache_updated_spec.js +++ b/spec/frontend/packages_and_registries/settings/project/settings/graphql/cache_updated_spec.js @@ -4,15 +4,15 @@ import { updateContainerExpirationPolicy } from '~/packages_and_registries/setti describe('Registry settings cache update', () => { let client; - const payload = { + const payload = (value) => ({ data: { updateContainerExpirationPolicy: { containerExpirationPolicy: { - enabled: true, + ...value, }, }, }, - }; + }); const cacheMock = { project: { @@ -35,12 +35,12 @@ describe('Registry settings cache update', () => { }); describe('Registry settings cache update', () => { it('calls readQuery', () => { - updateContainerExpirationPolicy('foo')(client, payload); + updateContainerExpirationPolicy('foo')(client, payload({ enabled: true })); expect(client.readQuery).toHaveBeenCalledWith(queryAndVariables); }); it('writes the correct result in the cache', () => { - updateContainerExpirationPolicy('foo')(client, payload); + updateContainerExpirationPolicy('foo')(client, payload({ enabled: true })); expect(client.writeQuery).toHaveBeenCalledWith({ ...queryAndVariables, data: { @@ -52,5 +52,20 @@ describe('Registry settings cache update', () => { }, }); }); + + it('with an empty update preserves the state', () => { + updateContainerExpirationPolicy('foo')(client, payload()); + + expect(client.writeQuery).toHaveBeenCalledWith({ + ...queryAndVariables, + data: { + project: { + containerExpirationPolicy: { + enabled: false, + }, + }, + }, + }); + }); }); }); diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js index ee682b18af3..5f1aff99578 100644 --- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js +++ b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_spec.js @@ -9,7 +9,6 @@ import { testActions, testSections, testProject } from './mock_data'; describe('Learn GitLab', () => { let wrapper; let sidebar; - let inviteMembers = false; const createWrapper = () => { wrapper = mount(LearnGitlab, { @@ -17,7 +16,6 @@ describe('Learn GitLab', () => { actions: testActions, sections: testSections, project: testProject, - inviteMembers, }, }); }; @@ -38,7 +36,6 @@ describe('Learn GitLab', () => { afterEach(() => { wrapper.destroy(); wrapper = null; - inviteMembers = false; sidebar.remove(); }); @@ -73,7 +70,6 @@ describe('Learn GitLab', () => { }); it('emits openModal', () => { - inviteMembers = true; Cookies.set(INVITE_MODAL_OPEN_COOKIE, true); createWrapper(); @@ -86,19 +82,11 @@ describe('Learn GitLab', () => { }); it('does not emit openModal when cookie is not set', () => { - inviteMembers = true; - createWrapper(); expect(spy).not.toHaveBeenCalled(); expect(cookieSpy).toHaveBeenCalledWith(INVITE_MODAL_OPEN_COOKIE); }); - - it('does not emit openModal when inviteMembers is false', () => { - createWrapper(); - - expect(spy).not.toHaveBeenCalled(); - }); }); describe('when the showSuccessfulInvitationsAlert event is fired', () => { diff --git a/spec/frontend/search/topbar/components/app_spec.js b/spec/frontend/search/topbar/components/app_spec.js index 7ce5efb3c52..0a44688bfe0 100644 --- a/spec/frontend/search/topbar/components/app_spec.js +++ b/spec/frontend/search/topbar/components/app_spec.js @@ -1,4 +1,4 @@ -import { GlForm, GlSearchBoxByType, GlButton } from '@gitlab/ui'; +import { GlSearchBoxByClick } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import Vuex from 'vuex'; @@ -36,40 +36,19 @@ describe('GlobalSearchTopbar', () => { wrapper.destroy(); }); - const findTopbarForm = () => wrapper.find(GlForm); - const findGlSearchBox = () => wrapper.find(GlSearchBoxByType); + const findGlSearchBox = () => wrapper.find(GlSearchBoxByClick); const findGroupFilter = () => wrapper.find(GroupFilter); const findProjectFilter = () => wrapper.find(ProjectFilter); - const findSearchButton = () => wrapper.find(GlButton); describe('template', () => { beforeEach(() => { createComponent(); }); - it('renders Topbar Form always', () => { - expect(findTopbarForm().exists()).toBe(true); - }); - describe('Search box', () => { it('renders always', () => { expect(findGlSearchBox().exists()).toBe(true); }); - - describe('onSearch', () => { - const testSearch = 'test search'; - - beforeEach(() => { - findGlSearchBox().vm.$emit('input', testSearch); - }); - - it('calls setQuery when input event is fired from GlSearchBoxByType', () => { - expect(actionSpies.setQuery).toHaveBeenCalledWith(expect.any(Object), { - key: 'search', - value: testSearch, - }); - }); - }); }); describe.each` @@ -92,10 +71,6 @@ describe('GlobalSearchTopbar', () => { expect(findProjectFilter().exists()).toBe(showFilters); }); }); - - it('renders SearchButton always', () => { - expect(findSearchButton().exists()).toBe(true); - }); }); describe('actions', () => { @@ -103,8 +78,8 @@ describe('GlobalSearchTopbar', () => { createComponent(); }); - it('clicking SearchButton calls applyQuery', () => { - findTopbarForm().vm.$emit('submit', { preventDefault: () => {} }); + it('clicking search button inside search box calls applyQuery', () => { + findGlSearchBox().vm.$emit('submit', { preventDefault: () => {} }); expect(actionSpies.applyQuery).toHaveBeenCalled(); }); diff --git a/spec/frontend/security_configuration/components/training_provider_list_spec.js b/spec/frontend/security_configuration/components/training_provider_list_spec.js index 08ba4bcbf69..5e2efa2425c 100644 --- a/spec/frontend/security_configuration/components/training_provider_list_spec.js +++ b/spec/frontend/security_configuration/components/training_provider_list_spec.js @@ -26,6 +26,7 @@ import { updateSecurityTrainingProvidersErrorResponse, testProjectPath, testProviderIds, + testProviderName, tempProviderLogos, } from '../mock_data'; @@ -207,9 +208,13 @@ describe('TrainingProviderList component', () => { expect(findLogos().at(provider).attributes('width')).toBe('18'); }); + it.each(providerIndexArray)('has a11y decorative attribute for provider %s', (provider) => { + expect(findLogos().at(provider).attributes('role')).toBe('presentation'); + }); + it.each(providerIndexArray)('displays the correct svg path for provider %s', (provider) => { expect(findLogos().at(provider).attributes('src')).toBe( - tempProviderLogos[testProviderIds[provider]].svg, + tempProviderLogos[testProviderName[provider]].svg, ); }); }); diff --git a/spec/frontend/security_configuration/mock_data.js b/spec/frontend/security_configuration/mock_data.js index 588fac11987..3bad687740c 100644 --- a/spec/frontend/security_configuration/mock_data.js +++ b/spec/frontend/security_configuration/mock_data.js @@ -1,11 +1,11 @@ export const testProjectPath = 'foo/bar'; - export const testProviderIds = [101, 102, 103]; +export const testProviderName = ['Vendor Name 1', 'Vendor Name 2', 'Vendor Name 3']; const createSecurityTrainingProviders = ({ providerOverrides = {} }) => [ { id: testProviderIds[0], - name: 'Vendor Name 1', + name: testProviderName[0], description: 'Interactive developer security education', url: 'https://www.example.org/security/training', isEnabled: false, @@ -14,7 +14,7 @@ const createSecurityTrainingProviders = ({ providerOverrides = {} }) => [ }, { id: testProviderIds[1], - name: 'Vendor Name 2', + name: testProviderName[1], description: 'Security training with guide and learning pathways.', url: 'https://www.vendornametwo.com/', isEnabled: false, @@ -23,7 +23,7 @@ const createSecurityTrainingProviders = ({ providerOverrides = {} }) => [ }, { id: testProviderIds[2], - name: 'Vendor Name 3', + name: testProviderName[2], description: 'Security training for the everyday developer.', url: 'https://www.vendornamethree.com/', isEnabled: false, @@ -99,10 +99,10 @@ export const updateSecurityTrainingProvidersErrorResponse = { // Will remove once this issue is resolved where the svg path will be available in the GraphQL query // https://gitlab.com/gitlab-org/gitlab/-/issues/346899 export const tempProviderLogos = { - [testProviderIds[0]]: { + [testProviderName[0]]: { svg: '/assets/illustrations/vulnerability/vendor-1.svg', }, - [testProviderIds[1]]: { + [testProviderName[1]]: { svg: '/assets/illustrations/vulnerability/vendor-2.svg', }, }; diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js index 2c3fc70e116..64ce210b6c8 100644 --- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js +++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_image_spec.js @@ -1,12 +1,13 @@ import { shallowMount } from '@vue/test-utils'; +import { GlAvatar, GlTooltip } from '@gitlab/ui'; import defaultAvatarUrl from 'images/no_avatar.png'; import { placeholderImage } from '~/lazy_loader'; import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; jest.mock('images/no_avatar.png', () => 'default-avatar-url'); -const DEFAULT_PROPS = { - size: 99, +const PROVIDED_PROPS = { + size: 32, imgSrc: 'myavatarurl.com', imgAlt: 'mydisplayname', cssClasses: 'myextraavatarclass', @@ -14,6 +15,10 @@ const DEFAULT_PROPS = { tooltipPlacement: 'bottom', }; +const DEFAULT_PROPS = { + size: 20, +}; + describe('User Avatar Image Component', () => { let wrapper; @@ -21,64 +26,149 @@ describe('User Avatar Image Component', () => { wrapper.destroy(); }); - describe('Initialization', () => { - beforeEach(() => { - wrapper = shallowMount(UserAvatarImage, { - propsData: { - ...DEFAULT_PROPS, - }, + describe('`glAvatarForAllUserAvatars` feature flag enabled', () => { + describe('Initialization', () => { + beforeEach(() => { + wrapper = shallowMount(UserAvatarImage, { + propsData: { + ...PROVIDED_PROPS, + }, + provide: { + glFeatures: { + glAvatarForAllUserAvatars: true, + }, + }, + }); + }); + + it('should render `GlAvatar` and provide correct properties to it', () => { + const avatar = wrapper.findComponent(GlAvatar); + + expect(avatar.attributes('data-src')).toBe( + `${PROVIDED_PROPS.imgSrc}?width=${PROVIDED_PROPS.size}`, + ); + expect(avatar.props()).toMatchObject({ + src: `${PROVIDED_PROPS.imgSrc}?width=${PROVIDED_PROPS.size}`, + alt: PROVIDED_PROPS.imgAlt, + }); + }); + + it('should add correct CSS classes', () => { + const classes = wrapper.findComponent(GlAvatar).classes(); + expect(classes).toContain(PROVIDED_PROPS.cssClasses); + expect(classes).not.toContain('lazy'); }); }); - it('should have as a child element', () => { - const imageElement = wrapper.find('img'); + describe('Initialization when lazy', () => { + beforeEach(() => { + wrapper = shallowMount(UserAvatarImage, { + propsData: { + ...PROVIDED_PROPS, + lazy: true, + }, + provide: { + glFeatures: { + glAvatarForAllUserAvatars: true, + }, + }, + }); + }); + + it('should add lazy attributes', () => { + const avatar = wrapper.findComponent(GlAvatar); - expect(imageElement.exists()).toBe(true); - expect(imageElement.attributes('src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`); - expect(imageElement.attributes('data-src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`); - expect(imageElement.attributes('alt')).toBe(DEFAULT_PROPS.imgAlt); + expect(avatar.classes()).toContain('lazy'); + expect(avatar.attributes()).toMatchObject({ + src: placeholderImage, + 'data-src': `${PROVIDED_PROPS.imgSrc}?width=${PROVIDED_PROPS.size}`, + }); + }); }); - it('should properly render img css', () => { - const classes = wrapper.find('img').classes(); - expect(classes).toEqual(expect.arrayContaining(['avatar', 's99', DEFAULT_PROPS.cssClasses])); - expect(classes).not.toContain('lazy'); + describe('Initialization without src', () => { + beforeEach(() => { + wrapper = shallowMount(UserAvatarImage); + }); + + it('should have default avatar image', () => { + const imageElement = wrapper.find('img'); + + expect(imageElement.attributes('src')).toBe( + `${defaultAvatarUrl}?width=${DEFAULT_PROPS.size}`, + ); + }); }); }); - describe('Initialization when lazy', () => { - beforeEach(() => { - wrapper = shallowMount(UserAvatarImage, { - propsData: { - ...DEFAULT_PROPS, - lazy: true, - }, + describe('`glAvatarForAllUserAvatars` feature flag disabled', () => { + describe('Initialization', () => { + beforeEach(() => { + wrapper = shallowMount(UserAvatarImage, { + propsData: { + ...PROVIDED_PROPS, + }, + }); }); - }); - it('should add lazy attributes', () => { - const imageElement = wrapper.find('img'); + it('should have as a child element', () => { + const imageElement = wrapper.find('img'); + + expect(imageElement.exists()).toBe(true); + expect(imageElement.attributes('src')).toBe( + `${PROVIDED_PROPS.imgSrc}?width=${PROVIDED_PROPS.size}`, + ); + expect(imageElement.attributes('data-src')).toBe( + `${PROVIDED_PROPS.imgSrc}?width=${PROVIDED_PROPS.size}`, + ); + expect(imageElement.attributes('alt')).toBe(PROVIDED_PROPS.imgAlt); + }); - expect(imageElement.classes()).toContain('lazy'); - expect(imageElement.attributes('src')).toBe(placeholderImage); - expect(imageElement.attributes('data-src')).toBe(`${DEFAULT_PROPS.imgSrc}?width=99`); + it('should properly render img css', () => { + const classes = wrapper.find('img').classes(); + expect(classes).toEqual(['avatar', 's32', PROVIDED_PROPS.cssClasses]); + expect(classes).not.toContain('lazy'); + }); }); - }); - describe('Initialization without src', () => { - beforeEach(() => { - wrapper = shallowMount(UserAvatarImage); + describe('Initialization when lazy', () => { + beforeEach(() => { + wrapper = shallowMount(UserAvatarImage, { + propsData: { + ...PROVIDED_PROPS, + lazy: true, + }, + }); + }); + + it('should add lazy attributes', () => { + const imageElement = wrapper.find('img'); + + expect(imageElement.classes()).toContain('lazy'); + expect(imageElement.attributes('src')).toBe(placeholderImage); + expect(imageElement.attributes('data-src')).toBe( + `${PROVIDED_PROPS.imgSrc}?width=${PROVIDED_PROPS.size}`, + ); + }); }); - it('should have default avatar image', () => { - const imageElement = wrapper.find('img'); + describe('Initialization without src', () => { + beforeEach(() => { + wrapper = shallowMount(UserAvatarImage); + }); + + it('should have default avatar image', () => { + const imageElement = wrapper.find('img'); - expect(imageElement.attributes('src')).toBe(`${defaultAvatarUrl}?width=20`); + expect(imageElement.attributes('src')).toBe( + `${defaultAvatarUrl}?width=${DEFAULT_PROPS.size}`, + ); + }); }); }); describe('dynamic tooltip content', () => { - const props = DEFAULT_PROPS; + const props = PROVIDED_PROPS; const slots = { default: ['Action!'], }; @@ -91,11 +181,11 @@ describe('User Avatar Image Component', () => { }); it('renders the tooltip slot', () => { - expect(wrapper.find('.js-user-avatar-image-tooltip').exists()).toBe(true); + expect(wrapper.findComponent(GlTooltip).exists()).toBe(true); }); it('renders the tooltip content', () => { - expect(wrapper.find('.js-user-avatar-image-tooltip').text()).toContain(slots.default[0]); + expect(wrapper.findComponent(GlTooltip).text()).toContain(slots.default[0]); }); it('does not render tooltip data attributes for on avatar image', () => { -- cgit v1.2.3