diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-29 00:10:46 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-29 00:10:46 +0300 |
commit | 0e2a219d6a82935ec564dfb68a1d721d7a24cd6a (patch) | |
tree | f3ef106082cd32a6e10d0540f2c1e553257eebf5 /spec | |
parent | 7c5f1bfac791045e54386b9c9bb56ee24afc68ca (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
16 files changed, 328 insertions, 111 deletions
diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb index 47a90efab1e..d03f8b18b3e 100644 --- a/spec/fast_spec_helper.rb +++ b/spec/fast_spec_helper.rb @@ -32,3 +32,5 @@ ActiveSupport::XmlMini.backend = 'Nokogiri' # Consider tweaking configuration in `spec/support/rspec.rb` which is also # used by `spec/spec_helper.rb`. + +require_relative('../jh/spec/fast_spec_helper') if Gitlab.jh? diff --git a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb index 1990526b5fc..cd7601aa94e 100644 --- a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb +++ b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb @@ -25,8 +25,6 @@ RSpec.describe 'User follows pipeline suggest nudge spec when feature is enabled end it 'displays suggest_gitlab_ci_yml popover' do - page.find(:css, '.gitlab-ci-yml-selector').click - popover_selector = '.suggest-gitlab-ci-yml' expect(page).to have_css(popover_selector, visible: true) diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb index a74cde35be6..55b15ad95d1 100644 --- a/spec/features/projects/files/dockerfile_dropdown_spec.rb +++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb @@ -12,20 +12,16 @@ RSpec.describe 'Projects > Files > User wants to add a Dockerfile file', :js, fe end it 'user can pick a Dockerfile file from the dropdown' do - expect(page).to have_css('.dockerfile-selector') + click_button 'Apply a template' - find('.js-dockerfile-selector').click - - wait_for_requests - - within '.dockerfile-selector' do - find('.dropdown-input-field').set('HTTPd') - find('.dropdown-content li', text: 'HTTPd').click + within '.gl-new-dropdown-panel' do + find('.gl-listbox-search-input').set('HTTPd') + find('.gl-new-dropdown-contents li', text: 'HTTPd').click end wait_for_requests - expect(page).to have_css('.dockerfile-selector .dropdown-toggle-text', text: 'Apply a template') + expect(page).to have_css('.gl-new-dropdown-button-text', text: 'HTTPd') expect(find('.monaco-editor')).to have_content('COPY ./ /usr/local/apache2/htdocs/') end end diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb index 36b02b9b948..b1f7f1c5716 100644 --- a/spec/features/projects/files/gitignore_dropdown_spec.rb +++ b/spec/features/projects/files/gitignore_dropdown_spec.rb @@ -12,20 +12,16 @@ RSpec.describe 'Projects > Files > User wants to add a .gitignore file', :js, fe end it 'user can pick a .gitignore file from the dropdown' do - expect(page).to have_css('.gitignore-selector') + click_button 'Apply a template' - find('.js-gitignore-selector').click - - wait_for_requests - - within '.gitignore-selector' do - find('.dropdown-input-field').set('rails') - find('.dropdown-content li', text: 'Rails').click + within '.gl-new-dropdown-panel' do + find('.gl-listbox-search-input').set('rails') + find('.gl-new-dropdown-contents li', text: 'Rails').click end wait_for_requests - expect(page).to have_css('.gitignore-selector .dropdown-toggle-text', text: 'Apply a template') + expect(page).to have_css('.gl-new-dropdown-button-text', text: 'Rails') expect(find('.monaco-editor')).to have_content('/.bundle') expect(find('.monaco-editor')).to have_content('config/initializers/secret_token.rb') end diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb index 929554ff0d6..7bfff6b68e8 100644 --- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb +++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb @@ -16,20 +16,16 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js end it 'user can pick a template from the dropdown' do - expect(page).to have_css('.gitlab-ci-yml-selector') + click_button 'Apply a template' - find('.js-gitlab-ci-yml-selector').click - - wait_for_requests - - within '.gitlab-ci-yml-selector' do - find('.dropdown-input-field').set('Jekyll') - find('.dropdown-content li', text: 'Jekyll').click + within '.gl-new-dropdown-panel' do + find('.gl-listbox-search-input').set('Jekyll') + find('.gl-new-dropdown-contents li', text: 'Jekyll').click end wait_for_requests - expect(page).to have_css('.gitlab-ci-yml-selector .dropdown-toggle-text', text: 'Apply a template') + expect(page).to have_css('.gl-new-dropdown-button-text', text: 'Jekyll') expect(find('.monaco-editor')).to have_content('This file is a template, and might need editing before it works on your project') expect(find('.monaco-editor')).to have_content('jekyll build -d test') end @@ -40,7 +36,7 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js it 'uses the given template' do wait_for_requests - expect(page).to have_css('.gitlab-ci-yml-selector .dropdown-toggle-text', text: 'Apply a template') + expect(page).to have_css('.gl-new-dropdown-button-text', text: 'Jekyll') expect(find('.monaco-editor')).to have_content('This file is a template, and might need editing before it works on your project') expect(find('.monaco-editor')).to have_content('jekyll build -d test') end @@ -52,7 +48,7 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js it 'leaves the editor empty' do wait_for_requests - expect(page).to have_css('.gitlab-ci-yml-selector .dropdown-toggle-text', text: 'Apply a template') + expect(page).to have_css('.gl-new-dropdown-button-text', text: 'Apply a template') expect(find('.monaco-editor')).to have_content('') end end diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index 8ec9adaeb9a..95e96159744 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -20,8 +20,6 @@ RSpec.describe 'Projects > Files > Project owner creates a license file', :js, f fill_in :file_name, with: 'LICENSE' - expect(page).to have_selector('.license-selector') - select_template('MIT License') file_content = first('.file-editor') @@ -44,7 +42,6 @@ RSpec.describe 'Projects > Files > Project owner creates a license file', :js, f expect(page).to have_current_path( project_new_blob_path(project, 'master'), ignore_query: true) expect(find('#file_name').value).to eq('LICENSE') - expect(page).to have_selector('.license-selector') select_template('MIT License') @@ -62,9 +59,9 @@ RSpec.describe 'Projects > Files > Project owner creates a license file', :js, f end def select_template(template) - page.within('.js-license-selector-wrap') do + page.within('.gl-new-dropdown') do click_button 'Apply a template' - click_link template + find('.gl-new-dropdown-contents li', text: template).click wait_for_requests end end diff --git a/spec/features/projects/files/template_selector_menu_spec.rb b/spec/features/projects/files/template_selector_menu_spec.rb index 46c4b69bc89..920da6e72ce 100644 --- a/spec/features/projects/files/template_selector_menu_spec.rb +++ b/spec/features/projects/files/template_selector_menu_spec.rb @@ -58,7 +58,7 @@ end def check_template_selector_menu_display(is_visible) count = is_visible ? 1 : 0 - expect(page).to have_css('.template-selectors-menu', count: count) + expect(page).to have_css('[data-testid="template-selector"]', count: count) end def create_and_edit_file(file_name) diff --git a/spec/features/projects/files/undo_template_spec.rb b/spec/features/projects/files/undo_template_spec.rb index 4b6e6b7282c..d6f9acc68a0 100644 --- a/spec/features/projects/files/undo_template_spec.rb +++ b/spec/features/projects/files/undo_template_spec.rb @@ -13,7 +13,7 @@ RSpec.describe 'Projects > Files > Template Undo Button', :js, feature_category: context 'editing a matching file and applying a template' do before do visit project_edit_blob_path(project, File.join(project.default_branch, "LICENSE")) - select_file_template('.js-license-selector', 'Apache License 2.0') + select_file_template('Apache License 2.0') end it 'reverts template application' do @@ -42,8 +42,8 @@ def check_content_reverted(template_content) expect(page).not_to have_content(template_content) end -def select_file_template(template_selector_selector, template_name) - find(template_selector_selector).click - find('.dropdown-content li', text: template_name).click +def select_file_template(template_name) + click_button 'Apply a template' + find('.gl-new-dropdown-contents li', text: template_name).click wait_for_requests end diff --git a/spec/frontend/blob/file_template_mediator_spec.js b/spec/frontend/blob/file_template_mediator_spec.js index 907a3c97799..ece9ae27273 100644 --- a/spec/frontend/blob/file_template_mediator_spec.js +++ b/spec/frontend/blob/file_template_mediator_spec.js @@ -1,5 +1,5 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; -import TemplateSelectorMediator from '~/blob/file_template_mediator'; +import FilepathFormMediator from '~/blob/filepath_form_mediator'; describe('Template Selector Mediator', () => { let mediator; @@ -14,7 +14,7 @@ describe('Template Selector Mediator', () => { beforeEach(() => { setHTMLFixture('<div class="file-editor"><input class="js-file-path-name-input" /></div>'); input = document.querySelector('.js-file-path-name-input'); - mediator = new TemplateSelectorMediator({ + mediator = new FilepathFormMediator({ editor, currentAction: jest.fn(), projectId: jest.fn(), @@ -44,7 +44,7 @@ describe('Template Selector Mediator', () => { ({ name, newName, shouldDispatch }) => { input.value = name; const eventHandler = jest.fn(); - input.addEventListener('change', eventHandler); + input.addEventListener('input', eventHandler); mediator.setFilename(newName); if (shouldDispatch) { diff --git a/spec/frontend/blob/file_template_selector_spec.js b/spec/frontend/blob/file_template_selector_spec.js deleted file mode 100644 index 123475f8d62..00000000000 --- a/spec/frontend/blob/file_template_selector_spec.js +++ /dev/null @@ -1,64 +0,0 @@ -import FileTemplateSelector from '~/blob/file_template_selector'; -import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; - -describe('FileTemplateSelector', () => { - let subject; - - const dropdown = '.dropdown'; - const wrapper = '.wrapper'; - - const createSubject = () => { - subject = new FileTemplateSelector({}); - subject.config = { - dropdown, - wrapper, - }; - subject.initDropdown = jest.fn(); - }; - - afterEach(() => { - subject = null; - resetHTMLFixture(); - }); - - describe('show method', () => { - beforeEach(() => { - setHTMLFixture(` - <div class="wrapper hidden"> - <div class="dropdown"></div> - </div> - `); - createSubject(); - }); - - it('calls init on first call', () => { - jest.spyOn(subject, 'init'); - subject.show(); - - expect(subject.init).toHaveBeenCalledTimes(1); - }); - - it('does not call init on subsequent calls', () => { - jest.spyOn(subject, 'init'); - subject.show(); - - expect(subject.init).toHaveBeenCalledTimes(1); - }); - - it('removes hidden class from wrapper', () => { - subject.init(); - expect(subject.wrapper.classList.contains('hidden')).toBe(true); - - subject.show(); - expect(subject.wrapper.classList.contains('hidden')).toBe(false); - }); - - it('sets the focus on the dropdown', () => { - subject.show(); - jest.spyOn(subject.dropdown, 'focus'); - jest.runAllTimers(); - - expect(subject.dropdown.focus).toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/frontend/blob/filepath_form/components/filepath_form_spec.js b/spec/frontend/blob/filepath_form/components/filepath_form_spec.js new file mode 100644 index 00000000000..8a890cdc75a --- /dev/null +++ b/spec/frontend/blob/filepath_form/components/filepath_form_spec.js @@ -0,0 +1,70 @@ +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import { GlFormInput } from '@gitlab/ui'; +import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; +import FilepathForm from '~/blob/filepath_form/components/filepath_form.vue'; +import TemplateSelector from '~/blob/filepath_form/components/template_selector.vue'; +import { Templates as TemplatesMock } from './mock_data'; + +describe('Filepath Form component', () => { + let wrapper; + + const findNavLinks = () => document.querySelector('.nav-links'); + const findNavLinkWrite = () => findNavLinks().querySelector('#edit'); + const findNavLinkPreview = () => findNavLinks().querySelector('#preview'); + + const findInput = () => wrapper.findComponent(GlFormInput); + const findTemplateSelector = () => wrapper.findComponent(TemplateSelector); + + const createComponent = (props = {}) => { + wrapper = shallowMount(FilepathForm, { + propsData: { + templates: TemplatesMock, + inputOptions: {}, + ...props, + }, + }); + }; + + beforeEach(() => { + setHTMLFixture(` + <div class="file-editor"> + <ul class="nav-links"> + <a class="nav-link" id="edit" href="#editor">Write</a> + <a class="nav-link" id="preview" href="#preview">Preview</a> + </ul> + </div> + `); + createComponent(); + }); + + afterEach(() => { + resetHTMLFixture(); + }); + + it('renders input with correct attributes', () => { + createComponent({ inputOptions: { name: 'foo', value: 'bar' } }); + expect(findInput().attributes()).toMatchObject({ + name: 'foo', + value: 'bar', + }); + }); + + describe('when write button is clicked', () => { + it('renders template selector', async () => { + findNavLinkWrite().click(); + await nextTick(); + + expect(findTemplateSelector().exists()).toBe(true); + }); + }); + + describe('when preview button is clicked', () => { + it('hides template selector', async () => { + findNavLinkPreview().click(); + await nextTick(); + + expect(findTemplateSelector().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/blob/filepath_form/components/mock_data.js b/spec/frontend/blob/filepath_form/components/mock_data.js new file mode 100644 index 00000000000..fc19d6f1887 --- /dev/null +++ b/spec/frontend/blob/filepath_form/components/mock_data.js @@ -0,0 +1,57 @@ +export const SuggestCiYmlData = { + trackLabel: 'suggest_gitlab_ci_yml', + dismissKey: '10', + mergeRequestPath: 'mr_path', + humanAccess: 'owner', +}; + +export const Templates = { + licenses: { + Other: [ + { + name: 'GNU Affero General Public License v3.0', + id: 'agpl-3.0', + key: 'agpl-3.0', + project_id: 10, + }, + ], + Popular: [ + { + name: 'Apache License 2.0', + id: 'apache-2.0', + key: 'apache-2.0', + project_id: 10, + }, + ], + }, + gitignore_names: { + Languages: [ + { + name: 'Actionscript', + id: 'Actionscript', + key: 'Actionscript', + project_id: 10, + }, + ], + }, + gitlab_ci_ymls: { + General: [ + { + name: '5-Minute-Production-App', + id: '5-Minute-Production-App', + key: '5-Minute-Production-App', + project_id: 10, + }, + ], + }, + dockerfile_names: { + General: [ + { + name: 'Binary', + id: 'Binary', + key: 'Binary', + project_id: 10, + }, + ], + }, +}; diff --git a/spec/frontend/blob/filepath_form/components/template_selector_spec.js b/spec/frontend/blob/filepath_form/components/template_selector_spec.js new file mode 100644 index 00000000000..b1419320e1e --- /dev/null +++ b/spec/frontend/blob/filepath_form/components/template_selector_spec.js @@ -0,0 +1,167 @@ +import { GlCollapsibleListbox } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { nextTick } from 'vue'; +import TemplateSelector from '~/blob/filepath_form/components/template_selector.vue'; +import SuggestGitlabCiYml from '~/blob/suggest_gitlab_ci_yml/components/popover.vue'; +import { Templates as TemplatesMock, SuggestCiYmlData as SuggestCiYmlDataMock } from './mock_data'; + +describe('Template Selector component', () => { + let wrapper; + + const findListbox = () => wrapper.findComponent(GlCollapsibleListbox); + const findSuggestCiYmlPopover = () => wrapper.findComponent(SuggestGitlabCiYml); + const findDisplayedTemplates = () => + findListbox() + .props('items') + .reduce((acc, item) => [...acc, ...item.options], []) + .map((template) => template.value); + + const getTemplateKeysFromMock = (key) => + Object.values(TemplatesMock[key]) + .reduce((acc, items) => [...acc, ...items], []) + .map((template) => template.key); + + const createComponent = (props = {}) => { + wrapper = shallowMount(TemplateSelector, { + propsData: { + filename: '', + templates: TemplatesMock, + ...props, + }, + }); + }; + + describe('when filename input is empty', () => { + beforeEach(() => { + createComponent(); + }); + + it('does not render listbox', () => { + expect(findListbox().exists()).toBe(false); + }); + + it('does not render suggest-ci-yml popover', () => { + expect(findSuggestCiYmlPopover().exists()).toBe(false); + }); + }); + + describe.each` + filename | key + ${'LICENSE'} | ${'licenses'} + ${'Dockerfile'} | ${'dockerfile_names'} + ${'.gitignore'} | ${'gitignore_names'} + ${'.gitlab-ci.yml'} | ${'gitlab_ci_ymls'} + `('when filename is $filename', ({ filename, key }) => { + beforeEach(() => { + createComponent({ filename }); + }); + + it('renders listbox with correct props', () => { + expect(findListbox().exists()).toBe(true); + expect(findListbox().props('toggleText')).toBe('Apply a template'); + expect(findListbox().props('searchPlaceholder')).toBe('Filter'); + expect(findDisplayedTemplates()).toEqual(getTemplateKeysFromMock(key)); + }); + + it('does not render suggest-ci-yml popover', () => { + expect(findSuggestCiYmlPopover().exists()).toBe(false); + }); + }); + + describe('when filename input is .gitlab-ci.yml with suggestCiYmlData prop', () => { + beforeEach(() => { + createComponent({ filename: '.gitlab-ci.yml', suggestCiYmlData: SuggestCiYmlDataMock }); + }); + + it('renders listbox with correct props', () => { + expect(findListbox().exists()).toBe(true); + expect(findListbox().props('toggleText')).toBe('Apply a template'); + expect(findListbox().props('searchPlaceholder')).toBe('Filter'); + }); + + it('renders suggest-ci-yml popover', () => { + expect(findSuggestCiYmlPopover().exists()).toBe(true); + }); + }); + + describe('has filename that matches template pattern', () => { + const filename = 'LICENSE'; + const templates = TemplatesMock.licenses.Other; + + describe('has initial template prop', () => { + const initialTemplate = TemplatesMock.licenses.Other[0]; + + beforeEach(() => { + createComponent({ filename, initialTemplate: initialTemplate.key }); + }); + + it('renders listbox toggle button with selected template name', () => { + expect(findListbox().props('toggleText')).toBe(initialTemplate.name); + }); + + it('selected template is checked', () => { + expect(findListbox().props('selected')).toBe(initialTemplate.key); + }); + }); + + describe('when template is selected', () => { + beforeEach(() => { + createComponent({ filename }); + findListbox().vm.$emit('select', templates[0].key); + }); + + it('emit `selected` event with selected template', () => { + const licenseSelectorType = { + key: 'licenses', + name: 'LICENSE', + pattern: /^(.+\/)?(licen[sc]e|copying)($|\.)/i, + type: 'licenses', + }; + + const { template, type } = wrapper.emitted('selected')[0][0]; + expect(template).toBe(templates[0]); + expect(type).toMatchObject(licenseSelectorType); + }); + + it('set loading state to true', () => { + expect(findListbox().props('loading')).toBe(true); + }); + + describe('when stopLoading callback from `selected` event is called', () => { + it('set loading state to false', async () => { + const { stopLoading } = wrapper.emitted('selected')[0][0]; + + stopLoading(); + await nextTick(); + + expect(findListbox().props('loading')).toBe(false); + }); + }); + }); + + describe('when searching for filter', () => { + const searchTerm = 'GNU'; + + beforeEach(() => { + createComponent({ filename: 'LICENSE' }); + findListbox().vm.$emit('search', searchTerm); + }); + + it('shows matching templates', () => { + const displayedTemplates = findDisplayedTemplates(); + const matchingTemplate = templates.find((template) => + template.name.toLowerCase().includes(searchTerm.toLowerCase()), + ); + expect(displayedTemplates).toContain(matchingTemplate?.key); + }); + + it('hides non-matching templates', () => { + const displayedTemplates = findDisplayedTemplates(); + const nonMatchingTemplate = templates.find( + (template) => !template.name.includes(searchTerm), + ); + expect(displayedTemplates).not.toContain(nonMatchingTemplate?.key); + }); + }); + }); +}); diff --git a/spec/frontend/blob_edit/blob_bundle_spec.js b/spec/frontend/blob_edit/blob_bundle_spec.js index 6a7ca3288cb..f72380f211d 100644 --- a/spec/frontend/blob_edit/blob_bundle_spec.js +++ b/spec/frontend/blob_edit/blob_bundle_spec.js @@ -96,9 +96,10 @@ describe('BlobBundle', () => { $('#commit-changes').click(); expect(trackingSpy).toHaveBeenCalledTimes(1); - expect(trackingSpy).toHaveBeenCalledWith(undefined, undefined, { - label: 'suggest_gitlab_ci_yml', + expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_button', { + label: 'suggest_gitlab_ci_yml_commit_changes', property: 'owner', + value: '20', }); }); }); diff --git a/spec/frontend/blob_edit/edit_blob_spec.js b/spec/frontend/blob_edit/edit_blob_spec.js index 1bdc54723ce..e58ad4040a9 100644 --- a/spec/frontend/blob_edit/edit_blob_spec.js +++ b/spec/frontend/blob_edit/edit_blob_spec.js @@ -45,6 +45,7 @@ describe('Blob Editing', () => { getValue: jest.fn().mockReturnValue('test value'), focus: jest.fn(), onDidChangeModelLanguage: emitter.event, + updateModelLanguage: jest.fn(), }; beforeEach(() => { mock = new MockAdapter(axios); diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index ac28ce05463..34447e12d11 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -3940,7 +3940,7 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and end it 'updates emails_disabled' do - project_param = { emails_enabled: false } + project_param = { emails_disabled: true } put api("/projects/#{project3.id}", user), params: project_param |