diff options
Diffstat (limited to 'spec/frontend/ref/components/ref_selector_spec.js')
-rw-r--r-- | spec/frontend/ref/components/ref_selector_spec.js | 246 |
1 files changed, 81 insertions, 165 deletions
diff --git a/spec/frontend/ref/components/ref_selector_spec.js b/spec/frontend/ref/components/ref_selector_spec.js index 4997c13bbb2..40d3a291074 100644 --- a/spec/frontend/ref/components/ref_selector_spec.js +++ b/spec/frontend/ref/components/ref_selector_spec.js @@ -1,5 +1,4 @@ -import { GlLoadingIcon, GlSearchBoxByType, GlDropdownItem, GlDropdown, GlIcon } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; +import { GlLoadingIcon, GlCollapsibleListbox, GlListboxItem } from '@gitlab/ui'; import Vue, { nextTick } from 'vue'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; @@ -8,8 +7,13 @@ import Vuex from 'vuex'; import commit from 'test_fixtures/api/commits/commit.json'; import branches from 'test_fixtures/api/branches/branches.json'; import tags from 'test_fixtures/api/tags/tags.json'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; import { trimText } from 'helpers/text_helper'; -import { ENTER_KEY } from '~/lib/utils/keys'; +import { + HTTP_STATUS_INTERNAL_SERVER_ERROR, + HTTP_STATUS_NOT_FOUND, + HTTP_STATUS_OK, +} from '~/lib/utils/http_status'; import { sprintf } from '~/locale'; import RefSelector from '~/ref/components/ref_selector.vue'; import { @@ -37,7 +41,7 @@ describe('Ref selector component', () => { let requestSpies; const createComponent = (mountOverrides = {}, propsData = {}) => { - wrapper = mount( + wrapper = mountExtended( RefSelector, merge( { @@ -52,9 +56,6 @@ describe('Ref selector component', () => { wrapper.setProps({ value: selectedRef }); }, }, - stubs: { - GlSearchBoxByType: true, - }, store: createStore(), }, mountOverrides, @@ -68,9 +69,11 @@ describe('Ref selector component', () => { branchesApiCallSpy = jest .fn() - .mockReturnValue([200, fixtures.branches, { [X_TOTAL_HEADER]: '123' }]); - tagsApiCallSpy = jest.fn().mockReturnValue([200, fixtures.tags, { [X_TOTAL_HEADER]: '456' }]); - commitApiCallSpy = jest.fn().mockReturnValue([200, fixtures.commit]); + .mockReturnValue([HTTP_STATUS_OK, fixtures.branches, { [X_TOTAL_HEADER]: '123' }]); + tagsApiCallSpy = jest + .fn() + .mockReturnValue([HTTP_STATUS_OK, fixtures.tags, { [X_TOTAL_HEADER]: '456' }]); + commitApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_OK, fixtures.commit]); requestSpies = { branchesApiCallSpy, tagsApiCallSpy, commitApiCallSpy }; mock @@ -84,76 +87,63 @@ describe('Ref selector component', () => { .reply((config) => commitApiCallSpy(config)); }); - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - // // Finders // - const findButtonContent = () => wrapper.find('button'); + const findListbox = () => wrapper.findComponent(GlCollapsibleListbox); + + const findButtonToggle = () => wrapper.findByTestId('base-dropdown-toggle'); - const findNoResults = () => wrapper.find('[data-testid="no-results"]'); + const findNoResults = () => wrapper.findByTestId('listbox-no-results-text'); const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); - const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); + const findListBoxSection = (section) => { + const foundSections = wrapper + .findAll('[role="group"]') + .filter((ul) => ul.text().includes(section)); + return foundSections.length > 0 ? foundSections.at(0) : foundSections; + }; + + const findErrorListWrapper = () => wrapper.findByTestId('red-selector-error-list'); - const findBranchesSection = () => wrapper.find('[data-testid="branches-section"]'); - const findBranchDropdownItems = () => findBranchesSection().findAllComponents(GlDropdownItem); - const findFirstBranchDropdownItem = () => findBranchDropdownItems().at(0); + const findBranchesSection = () => findListBoxSection('Branches'); + const findBranchDropdownItems = () => wrapper.findAllComponents(GlListboxItem); - const findTagsSection = () => wrapper.find('[data-testid="tags-section"]'); - const findTagDropdownItems = () => findTagsSection().findAllComponents(GlDropdownItem); - const findFirstTagDropdownItem = () => findTagDropdownItems().at(0); + const findTagsSection = () => findListBoxSection('Tags'); - const findCommitsSection = () => wrapper.find('[data-testid="commits-section"]'); - const findCommitDropdownItems = () => findCommitsSection().findAllComponents(GlDropdownItem); - const findFirstCommitDropdownItem = () => findCommitDropdownItems().at(0); + const findCommitsSection = () => findListBoxSection('Commits'); - const findHiddenInputField = () => wrapper.find('[data-testid="selected-ref-form-field"]'); + const findHiddenInputField = () => wrapper.findByTestId('selected-ref-form-field'); // // Expecters // - const branchesSectionContainsErrorMessage = () => { - const branchesSection = findBranchesSection(); + const sectionContainsErrorMessage = (message) => { + const errorSection = findErrorListWrapper(); - return branchesSection.text().includes(DEFAULT_I18N.branchesErrorMessage); - }; - - const tagsSectionContainsErrorMessage = () => { - const tagsSection = findTagsSection(); - - return tagsSection.text().includes(DEFAULT_I18N.tagsErrorMessage); - }; - - const commitsSectionContainsErrorMessage = () => { - const commitsSection = findCommitsSection(); - - return commitsSection.text().includes(DEFAULT_I18N.commitsErrorMessage); + return errorSection ? errorSection.text().includes(message) : false; }; // // Convenience methods // const updateQuery = (newQuery) => { - findSearchBox().vm.$emit('input', newQuery); + findListbox().vm.$emit('search', newQuery); }; const selectFirstBranch = async () => { - findFirstBranchDropdownItem().vm.$emit('click'); + findListbox().vm.$emit('select', fixtures.branches[0].name); await nextTick(); }; const selectFirstTag = async () => { - findFirstTagDropdownItem().vm.$emit('click'); + findListbox().vm.$emit('select', fixtures.tags[0].name); await nextTick(); }; const selectFirstCommit = async () => { - findFirstCommitDropdownItem().vm.$emit('click'); + findListbox().vm.$emit('select', fixtures.commit.id); await nextTick(); }; @@ -188,7 +178,7 @@ describe('Ref selector component', () => { }); describe('when name property is provided', () => { - it('renders an forrm input hidden field', () => { + it('renders an form input hidden field', () => { const name = 'default_tag'; createComponent({ propsData: { name } }); @@ -198,7 +188,7 @@ describe('Ref selector component', () => { }); describe('when name property is not provided', () => { - it('renders an forrm input hidden field', () => { + it('renders an form input hidden field', () => { createComponent(); expect(findHiddenInputField().exists()).toBe(false); @@ -217,7 +207,7 @@ describe('Ref selector component', () => { }); it('adds the provided ID to the GlDropdown instance', () => { - expect(wrapper.findComponent(GlDropdown).attributes().id).toBe(id); + expect(findListbox().attributes().id).toBe(id); }); }); @@ -231,7 +221,7 @@ describe('Ref selector component', () => { }); it('renders the pre-selected ref name', () => { - expect(findButtonContent().text()).toBe(preselectedRef); + expect(findButtonToggle().text()).toBe(preselectedRef); }); it('binds hidden input field to the pre-selected ref', () => { @@ -252,7 +242,7 @@ describe('Ref selector component', () => { wrapper.setProps({ value: updatedRef }); await nextTick(); - expect(findButtonContent().text()).toBe(updatedRef); + expect(findButtonToggle().text()).toBe(updatedRef); }); }); @@ -289,28 +279,13 @@ describe('Ref selector component', () => { }); }); - describe('when the Enter is pressed', () => { - beforeEach(() => { - createComponent(); - - return waitForRequests({ andClearMocks: true }); - }); - - it('requeries the endpoints when Enter is pressed', () => { - findSearchBox().vm.$emit('keydown', new KeyboardEvent({ key: ENTER_KEY })); - - return waitForRequests().then(() => { - expect(branchesApiCallSpy).toHaveBeenCalledTimes(1); - expect(tagsApiCallSpy).toHaveBeenCalledTimes(1); - }); - }); - }); - describe('when no results are found', () => { beforeEach(() => { - branchesApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]); - tagsApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]); - commitApiCallSpy = jest.fn().mockReturnValue([404]); + branchesApiCallSpy = jest + .fn() + .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]); + tagsApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]); + commitApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_NOT_FOUND]); createComponent(); @@ -348,27 +323,10 @@ describe('Ref selector component', () => { it('renders the branches section in the dropdown', () => { expect(findBranchesSection().exists()).toBe(true); - expect(findBranchesSection().props('shouldShowCheck')).toBe(true); - }); - - it('renders the "Branches" heading with a total number indicator', () => { - expect( - findBranchesSection().find('[data-testid="section-header"]').text(), - ).toMatchInterpolatedText('Branches 123'); }); it("does not render an error message in the branches section's body", () => { - expect(branchesSectionContainsErrorMessage()).toBe(false); - }); - - it('renders each non-default branch as a selectable item', () => { - const dropdownItems = findBranchDropdownItems(); - - fixtures.branches.forEach((b, i) => { - if (!b.default) { - expect(dropdownItems.at(i).text()).toBe(b.name); - } - }); + expect(findErrorListWrapper().exists()).toBe(false); }); it('renders the default branch as a selectable item with a "default" badge', () => { @@ -385,7 +343,9 @@ describe('Ref selector component', () => { describe('when the branches search returns no results', () => { beforeEach(() => { - branchesApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]); + branchesApiCallSpy = jest + .fn() + .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]); createComponent(); @@ -399,7 +359,7 @@ describe('Ref selector component', () => { describe('when the branches search returns an error', () => { beforeEach(() => { - branchesApiCallSpy = jest.fn().mockReturnValue([500]); + branchesApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_INTERNAL_SERVER_ERROR]); createComponent(); @@ -407,11 +367,11 @@ describe('Ref selector component', () => { }); it('renders the branches section in the dropdown', () => { - expect(findBranchesSection().exists()).toBe(true); + expect(findBranchesSection().exists()).toBe(false); }); it("renders an error message in the branches section's body", () => { - expect(branchesSectionContainsErrorMessage()).toBe(true); + expect(sectionContainsErrorMessage(DEFAULT_I18N.branchesErrorMessage)).toBe(true); }); }); }); @@ -426,31 +386,24 @@ describe('Ref selector component', () => { it('renders the tags section in the dropdown', () => { expect(findTagsSection().exists()).toBe(true); - expect(findTagsSection().props('shouldShowCheck')).toBe(true); }); it('renders the "Tags" heading with a total number indicator', () => { - expect( - findTagsSection().find('[data-testid="section-header"]').text(), - ).toMatchInterpolatedText('Tags 456'); + expect(findTagsSection().find('[role="presentation"]').text()).toMatchInterpolatedText( + `Tags ${fixtures.tags.length}`, + ); }); it("does not render an error message in the tags section's body", () => { - expect(tagsSectionContainsErrorMessage()).toBe(false); - }); - - it('renders each tag as a selectable item', () => { - const dropdownItems = findTagDropdownItems(); - - fixtures.tags.forEach((t, i) => { - expect(dropdownItems.at(i).text()).toBe(t.name); - }); + expect(findErrorListWrapper().exists()).toBe(false); }); }); describe('when the tags search returns no results', () => { beforeEach(() => { - tagsApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]); + tagsApiCallSpy = jest + .fn() + .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]); createComponent(); @@ -464,7 +417,7 @@ describe('Ref selector component', () => { describe('when the tags search returns an error', () => { beforeEach(() => { - tagsApiCallSpy = jest.fn().mockReturnValue([500]); + tagsApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_INTERNAL_SERVER_ERROR]); createComponent(); @@ -472,11 +425,11 @@ describe('Ref selector component', () => { }); it('renders the tags section in the dropdown', () => { - expect(findTagsSection().exists()).toBe(true); + expect(findTagsSection().exists()).toBe(false); }); it("renders an error message in the tags section's body", () => { - expect(tagsSectionContainsErrorMessage()).toBe(true); + expect(sectionContainsErrorMessage(DEFAULT_I18N.tagsErrorMessage)).toBe(true); }); }); }); @@ -496,25 +449,19 @@ describe('Ref selector component', () => { }); it('renders the "Commits" heading with a total number indicator', () => { - expect( - findCommitsSection().find('[data-testid="section-header"]').text(), - ).toMatchInterpolatedText('Commits 1'); - }); - - it("does not render an error message in the comits section's body", () => { - expect(commitsSectionContainsErrorMessage()).toBe(false); + expect(findCommitsSection().find('[role="presentation"]').text()).toMatchInterpolatedText( + `Commits 1`, + ); }); - it('renders each commit as a selectable item with the short SHA and commit title', () => { - const dropdownItems = findCommitDropdownItems(); - - expect(dropdownItems.at(0).text()).toBe(`${commit.short_id} ${commit.title}`); + it("does not render an error message in the commits section's body", () => { + expect(findErrorListWrapper().exists()).toBe(false); }); }); describe('when the commit search returns no results (i.e. a 404)', () => { beforeEach(() => { - commitApiCallSpy = jest.fn().mockReturnValue([404]); + commitApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_NOT_FOUND]); createComponent(); @@ -530,7 +477,7 @@ describe('Ref selector component', () => { describe('when the commit search returns an error (other than a 404)', () => { beforeEach(() => { - commitApiCallSpy = jest.fn().mockReturnValue([500]); + commitApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_INTERNAL_SERVER_ERROR]); createComponent(); @@ -540,11 +487,11 @@ describe('Ref selector component', () => { }); it('renders the commits section in the dropdown', () => { - expect(findCommitsSection().exists()).toBe(true); + expect(findCommitsSection().exists()).toBe(false); }); it("renders an error message in the commits section's body", () => { - expect(commitsSectionContainsErrorMessage()).toBe(true); + expect(sectionContainsErrorMessage(DEFAULT_I18N.commitsErrorMessage)).toBe(true); }); }); }); @@ -558,26 +505,13 @@ describe('Ref selector component', () => { return waitForRequests(); }); - it('renders a checkmark by the selected item', async () => { - expect(findFirstBranchDropdownItem().findComponent(GlIcon).element).toHaveClass( - 'gl-visibility-hidden', - ); - - await selectFirstBranch(); - - expect(findFirstBranchDropdownItem().findComponent(GlIcon).element).not.toHaveClass( - 'gl-visibility-hidden', - ); - }); - - describe('when a branch is seleceted', () => { + describe('when a branch is selected', () => { it("displays the branch name in the dropdown's button", async () => { - expect(findButtonContent().text()).toBe(DEFAULT_I18N.noRefSelected); + expect(findButtonToggle().text()).toBe(DEFAULT_I18N.noRefSelected); await selectFirstBranch(); - await nextTick(); - expect(findButtonContent().text()).toBe(fixtures.branches[0].name); + expect(findButtonToggle().text()).toBe(fixtures.branches[0].name); }); it("updates the v-model binding with the branch's name", async () => { @@ -591,12 +525,11 @@ describe('Ref selector component', () => { describe('when a tag is seleceted', () => { it("displays the tag name in the dropdown's button", async () => { - expect(findButtonContent().text()).toBe(DEFAULT_I18N.noRefSelected); + expect(findButtonToggle().text()).toBe(DEFAULT_I18N.noRefSelected); await selectFirstTag(); - await nextTick(); - expect(findButtonContent().text()).toBe(fixtures.tags[0].name); + expect(findButtonToggle().text()).toBe(fixtures.tags[0].name); }); it("updates the v-model binding with the tag's name", async () => { @@ -610,12 +543,11 @@ describe('Ref selector component', () => { describe('when a commit is selected', () => { it("displays the full SHA in the dropdown's button", async () => { - expect(findButtonContent().text()).toBe(DEFAULT_I18N.noRefSelected); + expect(findButtonToggle().text()).toBe(DEFAULT_I18N.noRefSelected); await selectFirstCommit(); - await nextTick(); - expect(findButtonContent().text()).toBe(fixtures.commit.id); + expect(findButtonToggle().text()).toBe(fixtures.commit.id); }); it("updates the v-model binding with the commit's full SHA", async () => { @@ -675,21 +607,6 @@ describe('Ref selector component', () => { expect(tagsApiCallSpy).toHaveBeenCalledTimes(1); }); - it('if a ref type becomes disabled, its section is hidden, even if it had some results in store', async () => { - createComponent({ propsData: { enabledRefTypes: [REF_TYPE_BRANCHES, REF_TYPE_COMMITS] } }); - updateQuery('abcd1234'); - await waitForRequests(); - - expect(findBranchesSection().exists()).toBe(true); - expect(findCommitsSection().exists()).toBe(true); - - wrapper.setProps({ enabledRefTypes: [REF_TYPE_COMMITS] }); - await waitForRequests(); - - expect(findBranchesSection().exists()).toBe(false); - expect(findCommitsSection().exists()).toBe(true); - }); - it.each` enabledRefType | findVisibleSection | findHiddenSections ${REF_TYPE_BRANCHES} | ${findBranchesSection} | ${[findTagsSection, findCommitsSection]} @@ -713,8 +630,7 @@ describe('Ref selector component', () => { describe('validation state', () => { const invalidClass = 'gl-inset-border-1-red-500!'; - const isInvalidClassApplied = () => - wrapper.findComponent(GlDropdown).props('toggleClass')[invalidClass]; + const isInvalidClassApplied = () => findListbox().props('toggleClass')[0][invalidClass]; describe('valid state', () => { describe('when the state prop is not provided', () => { |