diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-13 18:10:17 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-13 18:10:17 +0300 |
commit | effc12bf9dac4bf1e48f1397c25e0381ac1bd76f (patch) | |
tree | e2ff447fff4e156a94b684df6edddc108a767365 /spec/frontend/vue_shared | |
parent | c3eeb6a8d6a4b11f0bc5e5eb1ed43b0726f1ea26 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/vue_shared')
-rw-r--r-- | spec/frontend/vue_shared/components/actions_button_spec.js | 197 | ||||
-rw-r--r-- | spec/frontend/vue_shared/components/web_ide_link_spec.js | 145 |
2 files changed, 54 insertions, 288 deletions
diff --git a/spec/frontend/vue_shared/components/actions_button_spec.js b/spec/frontend/vue_shared/components/actions_button_spec.js index 8c2f2b52f8e..e7663e2adb2 100644 --- a/spec/frontend/vue_shared/components/actions_button_spec.js +++ b/spec/frontend/vue_shared/components/actions_button_spec.js @@ -1,12 +1,15 @@ -import { GlDropdown, GlDropdownDivider, GlButton, GlTooltip } from '@gitlab/ui'; -import { shallowMount } from '@vue/test-utils'; +import { + GlDisclosureDropdown, + GlDisclosureDropdownGroup, + GlDisclosureDropdownItem, +} from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import ActionsButton from '~/vue_shared/components/actions_button.vue'; const TEST_ACTION = { key: 'action1', text: 'Sample', secondaryText: 'Lorem ipsum.', - tooltip: '', href: '/sample', attrs: { 'data-test': '123', @@ -14,191 +17,75 @@ const TEST_ACTION = { href: '/sample', variant: 'default', }, + handle: jest.fn(), }; const TEST_ACTION_2 = { key: 'action2', text: 'Sample 2', secondaryText: 'Dolar sit amit.', - tooltip: 'Dolar sit amit.', href: '#', attrs: { 'data-test': '456' }, + handle: jest.fn(), }; -const TEST_TOOLTIP = 'Lorem ipsum dolar sit'; -describe('Actions button component', () => { +describe('vue_shared/components/actions_button', () => { let wrapper; function createComponent(props) { - wrapper = shallowMount(ActionsButton, { - propsData: { ...props }, + wrapper = shallowMountExtended(ActionsButton, { + propsData: { actions: [TEST_ACTION, TEST_ACTION_2], toggleText: 'Edit', ...props }, + stubs: { + GlDisclosureDropdownItem, + }, }); } + const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown); - const findButton = () => wrapper.findComponent(GlButton); - const findTooltip = () => wrapper.findComponent(GlTooltip); - const findDropdown = () => wrapper.findComponent(GlDropdown); - const parseDropdownItems = () => - findDropdown() - .findAll('gl-dropdown-item-stub,gl-dropdown-divider-stub') - .wrappers.map((x) => { - if (x.is(GlDropdownDivider)) { - return { type: 'divider' }; - } - - const { isCheckItem, isChecked, secondaryText } = x.props(); - - return { - type: 'item', - isCheckItem, - isChecked, - secondaryText, - text: x.text(), - }; - }); - const clickOn = (child, evt = new Event('click')) => child.vm.$emit('click', evt); - const clickLink = (...args) => clickOn(findButton(), ...args); - const clickDropdown = (...args) => clickOn(findDropdown(), ...args); - - describe('with 1 action', () => { - beforeEach(() => { - createComponent({ actions: [TEST_ACTION] }); - }); - - it('should not render dropdown', () => { - expect(findDropdown().exists()).toBe(false); - }); - - it('should render single button', () => { - expect(findButton().attributes()).toMatchObject({ - href: TEST_ACTION.href, - ...TEST_ACTION.attrs, - }); - expect(findButton().text()).toBe(TEST_ACTION.text); - }); - - it('should not have tooltip', () => { - expect(findTooltip().exists()).toBe(false); - }); + it('dropdown toggle displays provided toggleLabel', () => { + createComponent(); - it('should have attrs', () => { - expect(findButton().attributes()).toMatchObject(TEST_ACTION.attrs); - }); - - it('can click', () => { - expect(clickLink).not.toThrow(); - }); + expect(findDropdown().props().toggleText).toBe('Edit'); }); - describe('with 1 action with tooltip', () => { - it('should have tooltip', () => { - createComponent({ actions: [{ ...TEST_ACTION, tooltip: TEST_TOOLTIP }] }); + it('allows customizing variant and category', () => { + const variant = 'confirm'; + const category = 'secondary'; - expect(findTooltip().text()).toBe(TEST_TOOLTIP); - }); + createComponent({ variant, category }); + + expect(findDropdown().props()).toMatchObject({ category, variant }); }); - describe('when showActionTooltip is false', () => { - it('should not have tooltip', () => { - createComponent({ - actions: [{ ...TEST_ACTION, tooltip: TEST_TOOLTIP }], - showActionTooltip: false, - }); + it('displays a single dropdown group', () => { + createComponent(); - expect(findTooltip().exists()).toBe(false); - }); + expect(wrapper.findAllComponents(GlDisclosureDropdownGroup)).toHaveLength(1); }); - describe('with 1 action with handle', () => { - it('can click and trigger handle', () => { - const handleClick = jest.fn(); - createComponent({ actions: [{ ...TEST_ACTION, handle: handleClick }] }); + it('create dropdown items for every action', () => { + createComponent(); - const event = new Event('click'); - clickLink(event); + [TEST_ACTION, TEST_ACTION_2].forEach((action, index) => { + const dropdownItem = wrapper.findAllComponents(GlDisclosureDropdownItem).at(index); - expect(handleClick).toHaveBeenCalledWith(event); + expect(dropdownItem.props().item).toBe(action); + expect(dropdownItem.attributes()).toMatchObject(action.attrs); + expect(dropdownItem.text()).toContain(action.text); + expect(dropdownItem.text()).toContain(action.secondaryText); }); }); - describe('with multiple actions', () => { - let handleAction; + describe('when clicking a dropdown item', () => { + it("invokes the action's handle method", () => { + createComponent(); - beforeEach(() => { - handleAction = jest.fn(); + [TEST_ACTION, TEST_ACTION_2].forEach((action, index) => { + const dropdownItem = wrapper.findAllComponents(GlDisclosureDropdownItem).at(index); - createComponent({ actions: [{ ...TEST_ACTION, handle: handleAction }, TEST_ACTION_2] }); - }); + dropdownItem.vm.$emit('action'); - it('should default to selecting first action', () => { - expect(findDropdown().attributes()).toMatchObject({ - text: TEST_ACTION.text, - 'split-href': TEST_ACTION.href, + expect(action.handle).toHaveBeenCalled(); }); }); - - it('should handle first action click', () => { - const event = new Event('click'); - - clickDropdown(event); - - expect(handleAction).toHaveBeenCalledWith(event); - }); - - it('should render dropdown items', () => { - expect(parseDropdownItems()).toEqual([ - { - type: 'item', - isCheckItem: true, - isChecked: true, - secondaryText: TEST_ACTION.secondaryText, - text: TEST_ACTION.text, - }, - { type: 'divider' }, - { - type: 'item', - isCheckItem: true, - isChecked: false, - secondaryText: TEST_ACTION_2.secondaryText, - text: TEST_ACTION_2.text, - }, - ]); - }); - - it('should select action 2 when clicked', () => { - expect(wrapper.emitted('select')).toBeUndefined(); - - const action2 = wrapper.find(`[data-testid="action_${TEST_ACTION_2.key}"]`); - action2.vm.$emit('click'); - - expect(wrapper.emitted('select')).toEqual([[TEST_ACTION_2.key]]); - }); - - it('should not have tooltip value', () => { - expect(findTooltip().exists()).toBe(false); - }); - }); - - describe('with multiple actions and selectedKey', () => { - beforeEach(() => { - createComponent({ actions: [TEST_ACTION, TEST_ACTION_2], selectedKey: TEST_ACTION_2.key }); - }); - - it('should show action 2 as selected', () => { - expect(parseDropdownItems()).toEqual([ - expect.objectContaining({ - type: 'item', - isChecked: false, - }), - { type: 'divider' }, - expect.objectContaining({ - type: 'item', - isChecked: true, - }), - ]); - }); - - it('should have tooltip value', () => { - expect(findTooltip().text()).toBe(TEST_ACTION_2.tooltip); - }); }); }); diff --git a/spec/frontend/vue_shared/components/web_ide_link_spec.js b/spec/frontend/vue_shared/components/web_ide_link_spec.js index d888abc19ef..26557c63a77 100644 --- a/spec/frontend/vue_shared/components/web_ide_link_spec.js +++ b/spec/frontend/vue_shared/components/web_ide_link_spec.js @@ -1,19 +1,12 @@ -import { GlButton, GlModal } from '@gitlab/ui'; +import { GlModal } from '@gitlab/ui'; import { nextTick } from 'vue'; import ActionsButton from '~/vue_shared/components/actions_button.vue'; -import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; -import WebIdeLink, { - i18n, - PREFERRED_EDITOR_RESET_KEY, - PREFERRED_EDITOR_KEY, -} from '~/vue_shared/components/web_ide_link.vue'; +import WebIdeLink, { i18n } from '~/vue_shared/components/web_ide_link.vue'; import ConfirmForkModal from '~/vue_shared/components/confirm_fork_modal.vue'; -import { KEY_WEB_IDE } from '~/vue_shared/components/constants'; import { stubComponent } from 'helpers/stub_component'; import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; -import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import { visitUrl } from '~/lib/utils/url_utility'; @@ -30,9 +23,8 @@ const forkPath = '/some/fork/path'; const ACTION_EDIT = { href: TEST_EDIT_URL, key: 'edit', - text: 'Edit', + text: 'Edit single file', secondaryText: 'Edit this file only.', - tooltip: '', attrs: { 'data-qa-selector': 'edit_button', 'data-track-action': 'click_consolidated_edit', @@ -45,10 +37,8 @@ const ACTION_EDIT_CONFIRM_FORK = { handle: expect.any(Function), }; const ACTION_WEB_IDE = { - href: TEST_WEB_IDE_URL, key: 'webide', secondaryText: i18n.webIdeText, - tooltip: i18n.webIdeTooltip, text: 'Web IDE', attrs: { 'data-qa-selector': 'web_ide_button', @@ -59,7 +49,6 @@ const ACTION_WEB_IDE = { }; const ACTION_WEB_IDE_CONFIRM_FORK = { ...ACTION_WEB_IDE, - href: '#modal-confirm-fork-webide', handle: expect.any(Function), }; const ACTION_WEB_IDE_EDIT_FORK = { ...ACTION_WEB_IDE, text: 'Edit fork in Web IDE' }; @@ -67,7 +56,6 @@ const ACTION_GITPOD = { href: TEST_GITPOD_URL, key: 'gitpod', secondaryText: 'Launch a ready-to-code development environment for your project.', - tooltip: 'Launch a ready-to-code development environment for your project.', text: 'Gitpod', attrs: { 'data-qa-selector': 'gitpod_button', @@ -82,16 +70,13 @@ const ACTION_PIPELINE_EDITOR = { href: TEST_PIPELINE_EDITOR_URL, key: 'pipeline_editor', secondaryText: 'Edit, lint, and visualize your pipeline.', - tooltip: 'Edit, lint, and visualize your pipeline.', text: 'Edit in pipeline editor', attrs: { 'data-qa-selector': 'pipeline_editor_button', }, }; -describe('Web IDE link component', () => { - useLocalStorageSpy(); - +describe('vue_shared/components/web_ide_link', () => { let wrapper; function createComponent(props, { mountFn = shallowMountExtended, glFeatures = {} } = {}) { @@ -120,12 +105,7 @@ describe('Web IDE link component', () => { }); } - beforeEach(() => { - localStorage.setItem(PREFERRED_EDITOR_RESET_KEY, 'true'); - }); - const findActionsButton = () => wrapper.findComponent(ActionsButton); - const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync); const findModal = () => wrapper.findComponent(GlModal); const findForkConfirmModal = () => wrapper.findComponent(ConfirmForkModal); @@ -238,64 +218,16 @@ describe('Web IDE link component', () => { }); }); - it('selected Pipeline Editor by default', () => { + it('displays Pipeline Editor as the first action', () => { expect(findActionsButton().props()).toMatchObject({ actions: [ACTION_PIPELINE_EDITOR, ACTION_WEB_IDE, ACTION_GITPOD], - selectedKey: ACTION_PIPELINE_EDITOR.key, }); }); it('when web ide button is clicked it opens in a new tab', async () => { - findActionsButton().props('actions')[1].handle({ - preventDefault: jest.fn(), - }); - await nextTick(); - expect(visitUrl).toHaveBeenCalledWith(ACTION_WEB_IDE.href, true); - }); - }); - - describe('with multiple actions', () => { - beforeEach(() => { - createComponent({ - showEditButton: false, - showWebIdeButton: true, - showGitpodButton: true, - showPipelineEditorButton: false, - userPreferencesGitpodPath: TEST_USER_PREFERENCES_GITPOD_PATH, - userProfileEnableGitpodPath: TEST_USER_PROFILE_ENABLE_GITPOD_PATH, - gitpodEnabled: true, - }); - }); - - it('selected Web IDE by default', () => { - expect(findActionsButton().props()).toMatchObject({ - actions: [ACTION_WEB_IDE, ACTION_GITPOD], - selectedKey: ACTION_WEB_IDE.key, - }); - }); - - it('should set selection with local storage value', async () => { - expect(findActionsButton().props('selectedKey')).toBe(ACTION_WEB_IDE.key); - - findLocalStorageSync().vm.$emit('input', ACTION_GITPOD.key); - + findActionsButton().props('actions')[1].handle(); await nextTick(); - - expect(findActionsButton().props('selectedKey')).toBe(ACTION_GITPOD.key); - }); - - it('should update local storage when selection changes', async () => { - expect(findLocalStorageSync().props()).toMatchObject({ - asString: true, - value: ACTION_WEB_IDE.key, - }); - - findActionsButton().vm.$emit('select', ACTION_GITPOD.key); - - await nextTick(); - - expect(findActionsButton().props('selectedKey')).toBe(ACTION_GITPOD.key); - expect(findLocalStorageSync().props('value')).toBe(ACTION_GITPOD.key); + expect(visitUrl).toHaveBeenCalledWith(TEST_WEB_IDE_URL, true); }); }); @@ -348,7 +280,10 @@ describe('Web IDE link component', () => { it.each(testActions)('opens the modal when the button is clicked', async ({ props }) => { createComponent({ ...props, needsToFork: true }, { mountFn: mountExtended }); - await findActionsButton().findComponent(GlButton).trigger('click'); + wrapper.findComponent(ActionsButton).props().actions[0].handle(); + + await nextTick(); + await wrapper.findByRole('button', { name: /Web IDE|Edit/im }).trigger('click'); expect(findForkConfirmModal().props()).toEqual({ visible: true, @@ -404,10 +339,8 @@ describe('Web IDE link component', () => { { mountFn: mountExtended }, ); - findLocalStorageSync().vm.$emit('input', ACTION_GITPOD.key); - await nextTick(); - await wrapper.findByRole('button', { name: gitpodText }).trigger('click'); + await wrapper.findByRole('button', { name: new RegExp(gitpodText, 'm') }).trigger('click'); expect(findModal().props('visible')).toBe(true); }); @@ -425,58 +358,4 @@ describe('Web IDE link component', () => { expect(findModal().exists()).toBe(false); }); }); - - describe('when vscode_web_ide feature flag is enabled', () => { - describe('when is not showing edit button', () => { - describe(`when ${PREFERRED_EDITOR_RESET_KEY} is unset`, () => { - beforeEach(() => { - localStorage.setItem.mockReset(); - localStorage.getItem.mockReturnValueOnce(null); - createComponent({ showEditButton: false }, { glFeatures: { vscodeWebIde: true } }); - }); - - it(`sets ${PREFERRED_EDITOR_KEY} local storage key to ${KEY_WEB_IDE}`, () => { - expect(localStorage.getItem).toHaveBeenCalledWith(PREFERRED_EDITOR_RESET_KEY); - expect(localStorage.setItem).toHaveBeenCalledWith(PREFERRED_EDITOR_KEY, KEY_WEB_IDE); - }); - - it(`sets ${PREFERRED_EDITOR_RESET_KEY} local storage key to true`, () => { - expect(localStorage.setItem).toHaveBeenCalledWith(PREFERRED_EDITOR_RESET_KEY, true); - }); - - it(`selects ${KEY_WEB_IDE} as the preferred editor`, () => { - expect(findActionsButton().props().selectedKey).toBe(KEY_WEB_IDE); - }); - }); - - describe(`when ${PREFERRED_EDITOR_RESET_KEY} is set to true`, () => { - beforeEach(() => { - localStorage.setItem.mockReset(); - localStorage.getItem.mockReturnValueOnce('true'); - createComponent({ showEditButton: false }, { glFeatures: { vscodeWebIde: true } }); - }); - - it(`does not update the persisted preferred editor`, () => { - expect(localStorage.getItem).toHaveBeenCalledWith(PREFERRED_EDITOR_RESET_KEY); - expect(localStorage.setItem).not.toHaveBeenCalledWith(PREFERRED_EDITOR_RESET_KEY); - }); - }); - }); - - describe('when is showing the edit button', () => { - it(`does not try to reset the ${PREFERRED_EDITOR_KEY}`, () => { - createComponent({ showEditButton: true }, { glFeatures: { vscodeWebIde: true } }); - - expect(localStorage.getItem).not.toHaveBeenCalledWith(PREFERRED_EDITOR_RESET_KEY); - }); - }); - }); - - describe('when vscode_web_ide feature flag is disabled', () => { - it(`does not try to reset the ${PREFERRED_EDITOR_KEY}`, () => { - createComponent({}, { glFeatures: { vscodeWebIde: false } }); - - expect(localStorage.getItem).not.toHaveBeenCalledWith(PREFERRED_EDITOR_RESET_KEY); - }); - }); }); |