diff options
Diffstat (limited to 'spec/frontend/pipeline_editor/components')
-rw-r--r-- | spec/frontend/pipeline_editor/components/commit/commit_form_spec.js | 4 | ||||
-rw-r--r-- | spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js | 133 | ||||
-rw-r--r-- | spec/frontend/pipeline_editor/components/file-tree/container_spec.js | 138 | ||||
-rw-r--r-- | spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js | 52 | ||||
-rw-r--r-- | spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js | 56 | ||||
-rw-r--r-- | spec/frontend/pipeline_editor/components/popovers/walkthrough_popover_spec.js (renamed from spec/frontend/pipeline_editor/components/walkthrough_popover_spec.js) | 2 |
7 files changed, 379 insertions, 8 deletions
diff --git a/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js b/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js index 59bd71b0e60..bec6c2a8d0c 100644 --- a/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js +++ b/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js @@ -71,7 +71,7 @@ describe('Pipeline Editor | Commit Form', () => { expect(wrapper.emitted('submit')[0]).toEqual([ { message: mockCommitMessage, - targetBranch: mockDefaultBranch, + sourceBranch: mockDefaultBranch, openMergeRequest: false, }, ]); @@ -127,7 +127,7 @@ describe('Pipeline Editor | Commit Form', () => { expect(wrapper.emitted('submit')[0]).toEqual([ { message: anotherMessage, - targetBranch: anotherBranch, + sourceBranch: anotherBranch, openMergeRequest: true, }, ]); diff --git a/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js b/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js index e24de832d6d..a61796dbed2 100644 --- a/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js +++ b/spec/frontend/pipeline_editor/components/file-nav/pipeline_editor_file_nav_spec.js @@ -1,19 +1,58 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; import { shallowMount } from '@vue/test-utils'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import createMockApollo from 'helpers/mock_apollo_helper'; import BranchSwitcher from '~/pipeline_editor/components/file_nav/branch_switcher.vue'; import PipelineEditorFileNav from '~/pipeline_editor/components/file_nav/pipeline_editor_file_nav.vue'; +import FileTreePopover from '~/pipeline_editor/components/popovers/file_tree_popover.vue'; +import getAppStatus from '~/pipeline_editor/graphql/queries/client/app_status.query.graphql'; +import { + EDITOR_APP_STATUS_EMPTY, + EDITOR_APP_STATUS_LOADING, + EDITOR_APP_STATUS_VALID, +} from '~/pipeline_editor/constants'; + +Vue.use(VueApollo); describe('Pipeline editor file nav', () => { let wrapper; - const createComponent = ({ provide = {} } = {}) => { - wrapper = shallowMount(PipelineEditorFileNav, { - provide: { - ...provide, + const mockApollo = createMockApollo(); + + const createComponent = ({ + appStatus = EDITOR_APP_STATUS_VALID, + isNewCiConfigFile = false, + pipelineEditorFileTree = false, + } = {}) => { + mockApollo.clients.defaultClient.cache.writeQuery({ + query: getAppStatus, + data: { + app: { + __typename: 'PipelineEditorApp', + status: appStatus, + }, }, }); + + wrapper = extendedWrapper( + shallowMount(PipelineEditorFileNav, { + apolloProvider: mockApollo, + provide: { + glFeatures: { + pipelineEditorFileTree, + }, + }, + propsData: { + isNewCiConfigFile, + }, + }), + ); }; const findBranchSwitcher = () => wrapper.findComponent(BranchSwitcher); + const findFileTreeBtn = () => wrapper.findByTestId('file-tree-toggle'); + const findPopoverContainer = () => wrapper.findComponent(FileTreePopover); afterEach(() => { wrapper.destroy(); @@ -27,5 +66,91 @@ describe('Pipeline editor file nav', () => { it('renders the branch switcher', () => { expect(findBranchSwitcher().exists()).toBe(true); }); + + it('does not render the file tree button', () => { + expect(findFileTreeBtn().exists()).toBe(false); + }); + + it('does not render the file tree popover', () => { + expect(findPopoverContainer().exists()).toBe(false); + }); + }); + + describe('with pipelineEditorFileTree feature flag ON', () => { + describe('when editor is in the empty state', () => { + beforeEach(() => { + createComponent({ + appStatus: EDITOR_APP_STATUS_EMPTY, + isNewCiConfigFile: false, + pipelineEditorFileTree: true, + }); + }); + + it('does not render the file tree button', () => { + expect(findFileTreeBtn().exists()).toBe(false); + }); + + it('does not render the file tree popover', () => { + expect(findPopoverContainer().exists()).toBe(false); + }); + }); + + describe('when user is about to create their config file for the first time', () => { + beforeEach(() => { + createComponent({ + appStatus: EDITOR_APP_STATUS_VALID, + isNewCiConfigFile: true, + pipelineEditorFileTree: true, + }); + }); + + it('does not render the file tree button', () => { + expect(findFileTreeBtn().exists()).toBe(false); + }); + + it('does not render the file tree popover', () => { + expect(findPopoverContainer().exists()).toBe(false); + }); + }); + + describe('when app is in a global loading state', () => { + it('renders the file tree button with a loading icon', () => { + createComponent({ + appStatus: EDITOR_APP_STATUS_LOADING, + isNewCiConfigFile: false, + pipelineEditorFileTree: true, + }); + + expect(findFileTreeBtn().exists()).toBe(true); + expect(findFileTreeBtn().attributes('loading')).toBe('true'); + }); + }); + + describe('when editor has a non-empty config file open', () => { + beforeEach(() => { + createComponent({ + appStatus: EDITOR_APP_STATUS_VALID, + isNewCiConfigFile: false, + pipelineEditorFileTree: true, + }); + }); + + it('renders the file tree button', () => { + expect(findFileTreeBtn().exists()).toBe(true); + expect(findFileTreeBtn().props('icon')).toBe('file-tree'); + }); + + it('renders the file tree popover', () => { + expect(findPopoverContainer().exists()).toBe(true); + }); + + it('file tree button emits toggle-file-tree event', () => { + expect(wrapper.emitted('toggle-file-tree')).toBe(undefined); + + findFileTreeBtn().vm.$emit('click'); + + expect(wrapper.emitted('toggle-file-tree')).toHaveLength(1); + }); + }); }); }); diff --git a/spec/frontend/pipeline_editor/components/file-tree/container_spec.js b/spec/frontend/pipeline_editor/components/file-tree/container_spec.js new file mode 100644 index 00000000000..04a93e8db25 --- /dev/null +++ b/spec/frontend/pipeline_editor/components/file-tree/container_spec.js @@ -0,0 +1,138 @@ +import { nextTick } from 'vue'; +import { shallowMount } from '@vue/test-utils'; +import { GlAlert } from '@gitlab/ui'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import { createMockDirective } from 'helpers/vue_mock_directive'; +import PipelineEditorFileTreeContainer from '~/pipeline_editor/components/file_tree/container.vue'; +import PipelineEditorFileTreeItem from '~/pipeline_editor/components/file_tree/file_item.vue'; +import { FILE_TREE_TIP_DISMISSED_KEY } from '~/pipeline_editor/constants'; +import { mockCiConfigPath, mockIncludes, mockIncludesHelpPagePath } from '../../mock_data'; + +describe('Pipeline editor file nav', () => { + let wrapper; + + const createComponent = ({ includes = mockIncludes, stubs } = {}) => { + wrapper = extendedWrapper( + shallowMount(PipelineEditorFileTreeContainer, { + provide: { + ciConfigPath: mockCiConfigPath, + includesHelpPagePath: mockIncludesHelpPagePath, + }, + propsData: { + includes, + }, + directives: { + GlTooltip: createMockDirective(), + }, + stubs, + }), + ); + }; + + const findTip = () => wrapper.findComponent(GlAlert); + const findCurrentConfigFilename = () => wrapper.findByTestId('current-config-filename'); + const fileTreeItems = () => wrapper.findAll(PipelineEditorFileTreeItem); + + afterEach(() => { + localStorage.clear(); + wrapper.destroy(); + }); + + describe('template', () => { + beforeEach(() => { + createComponent({ stubs: { GlAlert } }); + }); + + it('renders config file as a file item', () => { + expect(findCurrentConfigFilename().text()).toBe(mockCiConfigPath); + }); + }); + + describe('when includes list is empty', () => { + describe('when dismiss state is not saved in local storage', () => { + beforeEach(() => { + createComponent({ + includes: [], + stubs: { GlAlert }, + }); + }); + + it('does not render filenames', () => { + expect(fileTreeItems().exists()).toBe(false); + }); + + it('renders alert tip', async () => { + expect(findTip().exists()).toBe(true); + }); + + it('renders learn more link', async () => { + expect(findTip().props('secondaryButtonLink')).toBe(mockIncludesHelpPagePath); + }); + + it('can dismiss the tip', async () => { + expect(findTip().exists()).toBe(true); + + findTip().vm.$emit('dismiss'); + await nextTick(); + + expect(findTip().exists()).toBe(false); + }); + }); + + describe('when dismiss state is saved in local storage', () => { + beforeEach(() => { + localStorage.setItem(FILE_TREE_TIP_DISMISSED_KEY, 'true'); + createComponent({ + includes: [], + stubs: { GlAlert }, + }); + }); + + it('does not render alert tip', async () => { + expect(findTip().exists()).toBe(false); + }); + }); + + describe('when component receives new props with includes files', () => { + beforeEach(() => { + createComponent({ includes: [] }); + }); + + it('hides tip and renders list of files', async () => { + expect(findTip().exists()).toBe(true); + expect(fileTreeItems()).toHaveLength(0); + + await wrapper.setProps({ includes: mockIncludes }); + + expect(findTip().exists()).toBe(false); + expect(fileTreeItems()).toHaveLength(mockIncludes.length); + }); + }); + }); + + describe('when there are includes files', () => { + beforeEach(() => { + createComponent({ stubs: { GlAlert } }); + }); + + it('does not render alert tip', () => { + expect(findTip().exists()).toBe(false); + }); + + it('renders the list of files', () => { + expect(fileTreeItems()).toHaveLength(mockIncludes.length); + }); + + describe('when component receives new props with empty includes', () => { + it('shows tip and does not render list of files', async () => { + expect(findTip().exists()).toBe(false); + expect(fileTreeItems()).toHaveLength(mockIncludes.length); + + await wrapper.setProps({ includes: [] }); + + expect(findTip().exists()).toBe(true); + expect(fileTreeItems()).toHaveLength(0); + }); + }); + }); +}); diff --git a/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js b/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js new file mode 100644 index 00000000000..f12ac14c6be --- /dev/null +++ b/spec/frontend/pipeline_editor/components/file-tree/file_item_spec.js @@ -0,0 +1,52 @@ +import { GlLink } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import FileIcon from '~/vue_shared/components/file_icon.vue'; +import PipelineEditorFileTreeItem from '~/pipeline_editor/components/file_tree/file_item.vue'; +import { mockIncludesWithBlob, mockDefaultIncludes } from '../../mock_data'; + +describe('Pipeline editor file nav', () => { + let wrapper; + + const createComponent = ({ file = mockDefaultIncludes } = {}) => { + wrapper = shallowMount(PipelineEditorFileTreeItem, { + propsData: { + file, + }, + }); + }; + + const fileIcon = () => wrapper.findComponent(FileIcon); + const link = () => wrapper.findComponent(GlLink); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('template', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders file icon', () => { + expect(fileIcon().exists()).toBe(true); + }); + + it('renders file name', () => { + expect(wrapper.text()).toBe(mockDefaultIncludes.location); + }); + + it('links to raw path by default', () => { + expect(link().attributes('href')).toBe(mockDefaultIncludes.raw); + }); + }); + + describe('when file has blob link', () => { + beforeEach(() => { + createComponent({ file: mockIncludesWithBlob }); + }); + + it('links to blob path', () => { + expect(link().attributes('href')).toBe(mockIncludesWithBlob.blob); + }); + }); +}); diff --git a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js index 6dffb7e5470..d159a20a8d6 100644 --- a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js +++ b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js @@ -3,7 +3,7 @@ import { shallowMount, mount } from '@vue/test-utils'; import Vue, { nextTick } from 'vue'; import setWindowLocation from 'helpers/set_window_location_helper'; import CiConfigMergedPreview from '~/pipeline_editor/components/editor/ci_config_merged_preview.vue'; -import WalkthroughPopover from '~/pipeline_editor/components/walkthrough_popover.vue'; +import WalkthroughPopover from '~/pipeline_editor/components/popovers/walkthrough_popover.vue'; import CiLint from '~/pipeline_editor/components/lint/ci_lint.vue'; import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue'; import EditorTab from '~/pipeline_editor/components/ui/editor_tab.vue'; diff --git a/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js b/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js new file mode 100644 index 00000000000..98ce3f6ea40 --- /dev/null +++ b/spec/frontend/pipeline_editor/components/popovers/file_tree_popover_spec.js @@ -0,0 +1,56 @@ +import { nextTick } from 'vue'; +import { GlLink, GlPopover, GlSprintf } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import FileTreePopover from '~/pipeline_editor/components/popovers/file_tree_popover.vue'; +import { FILE_TREE_POPOVER_DISMISSED_KEY } from '~/pipeline_editor/constants'; +import { mockIncludesHelpPagePath } from '../../mock_data'; + +describe('FileTreePopover component', () => { + let wrapper; + + const findPopover = () => wrapper.findComponent(GlPopover); + const findLink = () => findPopover().findComponent(GlLink); + + const createComponent = ({ stubs } = {}) => { + wrapper = shallowMount(FileTreePopover, { + provide: { + includesHelpPagePath: mockIncludesHelpPagePath, + }, + stubs, + }); + }; + + afterEach(() => { + localStorage.clear(); + wrapper.destroy(); + }); + + describe('default', () => { + beforeEach(async () => { + createComponent({ stubs: { GlSprintf } }); + }); + + it('renders dismissable popover', async () => { + expect(findPopover().exists()).toBe(true); + + findPopover().vm.$emit('close-button-clicked'); + await nextTick(); + + expect(findPopover().exists()).toBe(false); + }); + + it('renders learn more link', () => { + expect(findLink().exists()).toBe(true); + expect(findLink().attributes('href')).toBe(mockIncludesHelpPagePath); + }); + }); + + describe('when popover has already been dismissed before', () => { + it('does not render popover', async () => { + localStorage.setItem(FILE_TREE_POPOVER_DISMISSED_KEY, 'true'); + createComponent(); + + expect(findPopover().exists()).toBe(false); + }); + }); +}); diff --git a/spec/frontend/pipeline_editor/components/walkthrough_popover_spec.js b/spec/frontend/pipeline_editor/components/popovers/walkthrough_popover_spec.js index a9ce89ff521..8d172a8462a 100644 --- a/spec/frontend/pipeline_editor/components/walkthrough_popover_spec.js +++ b/spec/frontend/pipeline_editor/components/popovers/walkthrough_popover_spec.js @@ -1,6 +1,6 @@ import { mount, shallowMount } from '@vue/test-utils'; import Vue from 'vue'; -import WalkthroughPopover from '~/pipeline_editor/components/walkthrough_popover.vue'; +import WalkthroughPopover from '~/pipeline_editor/components/popovers/walkthrough_popover.vue'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; Vue.config.ignoredElements = ['gl-emoji']; |