Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-10-03 15:08:27 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-10-03 15:08:27 +0300
commit077b0a79d52753d020280ed8d58f97f8207b42de (patch)
tree79c6a7d3bbc41915acfff72e4620e7c4490528bf /spec/frontend/ide
parent10d4625ed3b73f73bc67bf7d35347dcd1912cf7b (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/ide')
-rw-r--r--spec/frontend/ide/components/commit_sidebar/actions_spec.js65
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_item_spec.js113
-rw-r--r--spec/frontend/ide/components/commit_sidebar/message_field_spec.js128
-rw-r--r--spec/frontend/ide/components/commit_sidebar/radio_group_spec.js135
-rw-r--r--spec/frontend/ide/components/file_row_extra_spec.js140
-rw-r--r--spec/frontend/ide/components/file_templates/bar_spec.js71
-rw-r--r--spec/frontend/ide/components/jobs/detail/description_spec.js35
-rw-r--r--spec/frontend/ide/components/jobs/detail_spec.js162
-rw-r--r--spec/frontend/ide/components/jobs/item_spec.js30
-rw-r--r--spec/frontend/ide/components/new_dropdown/button_spec.js65
-rw-r--r--spec/frontend/ide/components/new_dropdown/upload_spec.js71
-rw-r--r--spec/frontend/ide/components/shared/tokened_input_spec.js135
12 files changed, 531 insertions, 619 deletions
diff --git a/spec/frontend/ide/components/commit_sidebar/actions_spec.js b/spec/frontend/ide/components/commit_sidebar/actions_spec.js
index c9425f6c9cd..dc103fec5d0 100644
--- a/spec/frontend/ide/components/commit_sidebar/actions_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/actions_spec.js
@@ -1,7 +1,7 @@
import Vue, { nextTick } from 'vue';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { mount } from '@vue/test-utils';
import { projectData, branches } from 'jest/ide/mock_data';
-import commitActions from '~/ide/components/commit_sidebar/actions.vue';
+import CommitActions from '~/ide/components/commit_sidebar/actions.vue';
import { createStore } from '~/ide/stores';
import {
COMMIT_TO_NEW_BRANCH,
@@ -18,32 +18,27 @@ const BRANCH_REGULAR_NO_ACCESS = 'regular/no-access';
describe('IDE commit sidebar actions', () => {
let store;
- let vm;
+ let wrapper;
const createComponent = ({ hasMR = false, currentBranchId = 'main', emptyRepo = false } = {}) => {
- const Component = Vue.extend(commitActions);
-
- vm = createComponentWithStore(Component, store);
-
- vm.$store.state.currentBranchId = currentBranchId;
- vm.$store.state.currentProjectId = 'abcproject';
+ store.state.currentBranchId = currentBranchId;
+ store.state.currentProjectId = 'abcproject';
const proj = { ...projectData };
proj.branches[currentBranchId] = branches.find((branch) => branch.name === currentBranchId);
proj.empty_repo = emptyRepo;
- Vue.set(vm.$store.state.projects, 'abcproject', proj);
+ Vue.set(store.state.projects, 'abcproject', proj);
if (hasMR) {
- vm.$store.state.currentMergeRequestId = '1';
- vm.$store.state.projects[store.state.currentProjectId].mergeRequests[
+ store.state.currentMergeRequestId = '1';
+ store.state.projects[store.state.currentProjectId].mergeRequests[
store.state.currentMergeRequestId
] = { foo: 'bar' };
}
- vm.$mount();
-
- return vm;
+ wrapper = mount(CommitActions, { store });
+ return wrapper;
};
beforeEach(() => {
@@ -52,17 +47,16 @@ describe('IDE commit sidebar actions', () => {
});
afterEach(() => {
- vm.$destroy();
- vm = null;
+ wrapper.destroy();
});
- const findText = () => vm.$el.textContent;
- const findRadios = () => Array.from(vm.$el.querySelectorAll('input[type="radio"]'));
+ const findText = () => wrapper.text();
+ const findRadios = () => wrapper.findAll('input[type="radio"]');
it('renders 2 groups', () => {
createComponent();
- expect(findRadios().length).toBe(2);
+ expect(findRadios()).toHaveLength(2);
});
it('renders current branch text', () => {
@@ -79,41 +73,38 @@ describe('IDE commit sidebar actions', () => {
expect(findText()).not.toContain('Create a new branch and merge request');
});
- describe('currentBranchText', () => {
- it('escapes current branch', () => {
- const injectedSrc = '<img src="x" />';
- createComponent({ currentBranchId: injectedSrc });
+ it('escapes current branch name', () => {
+ const injectedSrc = '<img src="x" />';
+ const escapedSrc = '&lt;img src=&quot;x&quot; /&gt';
+ createComponent({ currentBranchId: injectedSrc });
- expect(vm.currentBranchText).not.toContain(injectedSrc);
- });
+ expect(wrapper.text()).not.toContain(injectedSrc);
+ expect(wrapper.text).not.toContain(escapedSrc);
});
describe('updateSelectedCommitAction', () => {
it('does not return anything if currentBranch does not exist', () => {
createComponent({ currentBranchId: null });
- expect(vm.$store.dispatch).not.toHaveBeenCalled();
+ expect(store.dispatch).not.toHaveBeenCalled();
});
it('is not called on mount if there is already a selected commitAction', () => {
store.state.commitAction = '1';
createComponent({ currentBranchId: null });
- expect(vm.$store.dispatch).not.toHaveBeenCalled();
+ expect(store.dispatch).not.toHaveBeenCalled();
});
it('calls again after staged changes', async () => {
createComponent({ currentBranchId: null });
- vm.$store.state.currentBranchId = 'main';
- vm.$store.state.changedFiles.push({});
- vm.$store.state.stagedFiles.push({});
+ store.state.currentBranchId = 'main';
+ store.state.changedFiles.push({});
+ store.state.stagedFiles.push({});
await nextTick();
- expect(vm.$store.dispatch).toHaveBeenCalledWith(
- ACTION_UPDATE_COMMIT_ACTION,
- expect.anything(),
- );
+ expect(store.dispatch).toHaveBeenCalledWith(ACTION_UPDATE_COMMIT_ACTION, expect.anything());
});
it.each`
@@ -133,9 +124,7 @@ describe('IDE commit sidebar actions', () => {
({ input, expectedOption }) => {
createComponent(input);
- expect(vm.$store.dispatch.mock.calls).toEqual([
- [ACTION_UPDATE_COMMIT_ACTION, expectedOption],
- ]);
+ expect(store.dispatch.mock.calls).toEqual([[ACTION_UPDATE_COMMIT_ACTION, expectedOption]]);
},
);
});
diff --git a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
index dea920ecb5e..f71f6a5e5c7 100644
--- a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
@@ -1,14 +1,15 @@
+import { mount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import { trimText } from 'helpers/text_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
-import listItem from '~/ide/components/commit_sidebar/list_item.vue';
+import ListItem from '~/ide/components/commit_sidebar/list_item.vue';
import { createRouter } from '~/ide/ide_router';
import { createStore } from '~/ide/stores';
import { file } from '../../helpers';
describe('Multi-file editor commit sidebar list item', () => {
- let vm;
+ let wrapper;
let f;
let findPathEl;
let store;
@@ -16,118 +17,120 @@ describe('Multi-file editor commit sidebar list item', () => {
beforeEach(() => {
store = createStore();
- router = createRouter(store);
+ jest.spyOn(store, 'dispatch');
- const Component = Vue.extend(listItem);
+ router = createRouter(store);
f = file('test-file');
store.state.entries[f.path] = f;
- vm = createComponentWithStore(Component, store, {
- file: f,
- activeFileKey: `staged-${f.key}`,
- }).$mount();
+ wrapper = mount(ListItem, {
+ store,
+ propsData: {
+ file: f,
+ activeFileKey: `staged-${f.key}`,
+ },
+ });
- findPathEl = vm.$el.querySelector('.multi-file-commit-list-path');
+ findPathEl = wrapper.find('.multi-file-commit-list-path');
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
- const findPathText = () => trimText(findPathEl.textContent);
+ const findPathText = () => trimText(findPathEl.text());
it('renders file path', () => {
expect(findPathText()).toContain(f.path);
});
it('correctly renders renamed entries', async () => {
- Vue.set(vm.file, 'prevName', 'Old name');
-
+ Vue.set(f, 'prevName', 'Old name');
await nextTick();
+
expect(findPathText()).toEqual(`Old name → ${f.name}`);
});
it('correctly renders entry, the name of which did not change after rename (as within a folder)', async () => {
- Vue.set(vm.file, 'prevName', f.name);
-
+ Vue.set(f, 'prevName', f.name);
await nextTick();
+
expect(findPathText()).toEqual(f.name);
});
it('opens a closed file in the editor when clicking the file path', async () => {
- jest.spyOn(vm, 'openPendingTab');
jest.spyOn(router, 'push').mockImplementation(() => {});
- findPathEl.click();
-
- await nextTick();
+ await findPathEl.trigger('click');
- expect(vm.openPendingTab).toHaveBeenCalled();
+ expect(store.dispatch).toHaveBeenCalledWith('openPendingTab', expect.anything());
expect(router.push).toHaveBeenCalled();
});
it('calls updateViewer with diff when clicking file', async () => {
- jest.spyOn(vm, 'openFileInEditor');
- jest.spyOn(vm, 'updateViewer');
jest.spyOn(router, 'push').mockImplementation(() => {});
- findPathEl.click();
-
+ await findPathEl.trigger('click');
await waitForPromises();
- expect(vm.updateViewer).toHaveBeenCalledWith('diff');
+ expect(store.dispatch).toHaveBeenCalledWith('updateViewer', 'diff');
});
- describe('computed', () => {
- describe('iconName', () => {
- it('returns modified when not a tempFile', () => {
- expect(vm.iconName).toBe('file-modified');
- });
+ describe('icon name', () => {
+ const getIconName = () => wrapper.findComponent(GlIcon).props('name');
+
+ it('is modified when not a tempFile', () => {
+ expect(getIconName()).toBe('file-modified');
+ });
- it('returns addition when not a tempFile', () => {
- f.tempFile = true;
+ it('is addition when is a tempFile', async () => {
+ f.tempFile = true;
+ await nextTick();
- expect(vm.iconName).toBe('file-addition');
- });
+ expect(getIconName()).toBe('file-addition');
+ });
- it('returns deletion', () => {
- f.deleted = true;
+ it('is deletion when is deleted', async () => {
+ f.deleted = true;
+ await nextTick();
- expect(vm.iconName).toBe('file-deletion');
- });
+ expect(getIconName()).toBe('file-deletion');
});
+ });
- describe('iconClass', () => {
- it('returns modified when not a tempFile', () => {
- expect(vm.iconClass).toContain('ide-file-modified');
- });
+ describe('icon class', () => {
+ const getIconClass = () => wrapper.findComponent(GlIcon).classes();
- it('returns addition when not a tempFile', () => {
- f.tempFile = true;
+ it('is modified when not a tempFile', () => {
+ expect(getIconClass()).toContain('ide-file-modified');
+ });
- expect(vm.iconClass).toContain('ide-file-addition');
- });
+ it('is addition when is a tempFile', async () => {
+ f.tempFile = true;
+ await nextTick();
- it('returns deletion', () => {
- f.deleted = true;
+ expect(getIconClass()).toContain('ide-file-addition');
+ });
- expect(vm.iconClass).toContain('ide-file-deletion');
- });
+ it('returns deletion when is deleted', async () => {
+ f.deleted = true;
+ await nextTick();
+
+ expect(getIconClass()).toContain('ide-file-deletion');
});
});
describe('is active', () => {
it('does not add active class when dont keys match', () => {
- expect(vm.$el.querySelector('.is-active')).toBe(null);
+ expect(wrapper.find('.is-active').exists()).toBe(false);
});
it('adds active class when keys match', async () => {
- vm.keyPrefix = 'staged';
+ await wrapper.setProps({ keyPrefix: 'staged' });
- await nextTick();
- expect(vm.$el.querySelector('.is-active')).not.toBe(null);
+ expect(wrapper.find('.is-active').exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/ide/components/commit_sidebar/message_field_spec.js b/spec/frontend/ide/components/commit_sidebar/message_field_spec.js
index ace266aec5e..c2ef29c1059 100644
--- a/spec/frontend/ide/components/commit_sidebar/message_field_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/message_field_spec.js
@@ -1,135 +1,121 @@
-import Vue, { nextTick } from 'vue';
-import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import createComponent from 'helpers/vue_mount_component_helper';
+import { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
import CommitMessageField from '~/ide/components/commit_sidebar/message_field.vue';
describe('IDE commit message field', () => {
- const Component = Vue.extend(CommitMessageField);
- let vm;
+ let wrapper;
beforeEach(() => {
- setHTMLFixture('<div id="app"></div>');
-
- vm = createComponent(
- Component,
- {
+ wrapper = mount(CommitMessageField, {
+ propsData: {
text: '',
placeholder: 'testing',
},
- '#app',
- );
+ attachTo: document.body,
+ });
});
afterEach(() => {
- vm.$destroy();
-
- resetHTMLFixture();
+ wrapper.destroy();
});
+ const findMessage = () => wrapper.find('textarea');
+ const findHighlights = () => wrapper.findAll('.highlights span');
+ const findMarks = () => wrapper.findAll('mark');
+
it('adds is-focused class on focus', async () => {
- vm.$el.querySelector('textarea').focus();
+ await findMessage().trigger('focus');
- await nextTick();
- expect(vm.$el.querySelector('.is-focused')).not.toBeNull();
+ expect(wrapper.find('.is-focused').exists()).toBe(true);
});
it('removed is-focused class on blur', async () => {
- vm.$el.querySelector('textarea').focus();
+ await findMessage().trigger('focus');
- await nextTick();
- expect(vm.$el.querySelector('.is-focused')).not.toBeNull();
+ expect(wrapper.find('.is-focused').exists()).toBe(true);
- vm.$el.querySelector('textarea').blur();
+ await findMessage().trigger('blur');
- await nextTick();
- expect(vm.$el.querySelector('.is-focused')).toBeNull();
+ expect(wrapper.find('.is-focused').exists()).toBe(false);
});
- it('emits input event on input', () => {
- jest.spyOn(vm, '$emit').mockImplementation();
-
- const textarea = vm.$el.querySelector('textarea');
- textarea.value = 'testing';
-
- textarea.dispatchEvent(new Event('input'));
+ it('emits input event on input', async () => {
+ await findMessage().setValue('testing');
- expect(vm.$emit).toHaveBeenCalledWith('input', 'testing');
+ expect(wrapper.emitted('input')[0]).toStrictEqual(['testing']);
});
describe('highlights', () => {
describe('subject line', () => {
it('does not highlight less than 50 characters', async () => {
- vm.text = 'text less than 50 chars';
+ await wrapper.setProps({ text: 'text less than 50 chars' });
- await nextTick();
- expect(vm.$el.querySelector('.highlights span').textContent).toContain(
- 'text less than 50 chars',
- );
+ expect(findHighlights()).toHaveLength(1);
+ expect(findHighlights().at(0).text()).toContain('text less than 50 chars');
- expect(vm.$el.querySelector('mark').style.display).toBe('none');
+ expect(findMarks()).toHaveLength(1);
+ expect(findMarks().at(0).isVisible()).toBe(false);
});
it('highlights characters over 50 length', async () => {
- vm.text =
- 'text less than 50 chars that should not highlighted. text more than 50 should be highlighted';
+ await wrapper.setProps({
+ text:
+ 'text less than 50 chars that should not highlighted. text more than 50 should be highlighted',
+ });
- await nextTick();
- expect(vm.$el.querySelector('.highlights span').textContent).toContain(
+ expect(findHighlights()).toHaveLength(1);
+ expect(findHighlights().at(0).text()).toContain(
'text less than 50 chars that should not highlighte',
);
- expect(vm.$el.querySelector('mark').style.display).not.toBe('none');
- expect(vm.$el.querySelector('mark').textContent).toBe(
- 'd. text more than 50 should be highlighted',
- );
+ expect(findMarks()).toHaveLength(1);
+ expect(findMarks().at(0).isVisible()).toBe(true);
+ expect(findMarks().at(0).text()).toBe('d. text more than 50 should be highlighted');
});
});
describe('body text', () => {
it('does not highlight body text less tan 72 characters', async () => {
- vm.text = 'subject line\nbody content';
+ await wrapper.setProps({ text: 'subject line\nbody content' });
- await nextTick();
- expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2);
- expect(vm.$el.querySelectorAll('mark')[1].style.display).toBe('none');
+ expect(findHighlights()).toHaveLength(2);
+ expect(findMarks().at(1).isVisible()).toBe(false);
});
it('highlights body text more than 72 characters', async () => {
- vm.text =
- 'subject line\nbody content that will be highlighted when it is more than 72 characters in length';
-
- await nextTick();
- expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2);
- expect(vm.$el.querySelectorAll('mark')[1].style.display).not.toBe('none');
- expect(vm.$el.querySelectorAll('mark')[1].textContent).toBe(' in length');
+ await wrapper.setProps({
+ text:
+ 'subject line\nbody content that will be highlighted when it is more than 72 characters in length',
+ });
+
+ expect(findHighlights()).toHaveLength(2);
+ expect(findMarks().at(1).isVisible()).toBe(true);
+ expect(findMarks().at(1).text()).toBe('in length');
});
it('highlights body text & subject line', async () => {
- vm.text =
- 'text less than 50 chars that should not highlighted\nbody content that will be highlighted when it is more than 72 characters in length';
+ await wrapper.setProps({
+ text:
+ 'text less than 50 chars that should not highlighted\nbody content that will be highlighted when it is more than 72 characters in length',
+ });
- await nextTick();
- expect(vm.$el.querySelectorAll('.highlights span').length).toBe(2);
- expect(vm.$el.querySelectorAll('mark').length).toBe(2);
+ expect(findHighlights()).toHaveLength(2);
+ expect(findMarks()).toHaveLength(2);
- expect(vm.$el.querySelectorAll('mark')[0].textContent).toContain('d');
- expect(vm.$el.querySelectorAll('mark')[1].textContent).toBe(' in length');
+ expect(findMarks().at(0).text()).toContain('d');
+ expect(findMarks().at(1).text()).toBe('in length');
});
});
});
describe('scrolling textarea', () => {
it('updates transform of highlights', async () => {
- vm.text = 'subject line\n\n\n\n\n\n\n\n\n\n\nbody content';
+ await wrapper.setProps({ text: 'subject line\n\n\n\n\n\n\n\n\n\n\nbody content' });
+ findMessage().element.scrollTo(0, 50);
await nextTick();
- vm.$el.querySelector('textarea').scrollTo(0, 50);
- vm.handleScroll();
-
- await nextTick();
- expect(vm.scrollTop).toBe(50);
- expect(vm.$el.querySelector('.highlights').style.transform).toBe('translate3d(0, -50px, 0)');
+ expect(wrapper.find('.highlights').element.style.transform).toBe('translate3d(0, -50px, 0)');
});
});
});
diff --git a/spec/frontend/ide/components/commit_sidebar/radio_group_spec.js b/spec/frontend/ide/components/commit_sidebar/radio_group_spec.js
index ee6ed694285..a3fa03a4aa5 100644
--- a/spec/frontend/ide/components/commit_sidebar/radio_group_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/radio_group_spec.js
@@ -1,123 +1,116 @@
-import Vue, { nextTick } from 'vue';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { GlFormRadioGroup } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
import RadioGroup from '~/ide/components/commit_sidebar/radio_group.vue';
import { createStore } from '~/ide/stores';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
describe('IDE commit sidebar radio group', () => {
- let vm;
+ let wrapper;
let store;
- beforeEach(async () => {
+ const createComponent = (config = {}) => {
store = createStore();
- const Component = Vue.extend(RadioGroup);
-
store.state.commit.commitAction = '2';
+ store.state.commit.newBranchName = 'test-123';
- vm = createComponentWithStore(Component, store, {
- value: '1',
- label: 'test',
- checked: true,
+ wrapper = mount(RadioGroup, {
+ store,
+ propsData: config.props,
+ slots: config.slots,
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
});
-
- vm.$mount();
-
- await nextTick();
- });
+ };
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
- it('uses label if present', () => {
- expect(vm.$el.textContent).toContain('test');
- });
+ describe('without input', () => {
+ const props = {
+ value: '1',
+ label: 'test',
+ checked: true,
+ };
- it('uses slot if label is not present', async () => {
- vm.$destroy();
+ it('uses label if present', () => {
+ createComponent({ props });
- vm = new Vue({
- components: {
- RadioGroup,
- },
- store,
- render: (createElement) =>
- createElement('radio-group', { props: { value: '1' } }, 'Testing slot'),
+ expect(wrapper.text()).toContain('test');
});
- vm.$mount();
+ it('uses slot if label is not present', () => {
+ createComponent({ props: { value: '1', checked: true }, slots: { default: 'Testing slot' } });
- await nextTick();
- expect(vm.$el.textContent).toContain('Testing slot');
- });
+ expect(wrapper.text()).toContain('Testing slot');
+ });
- it('updates store when changing radio button', async () => {
- vm.$el.querySelector('input').dispatchEvent(new Event('change'));
+ it('updates store when changing radio button', async () => {
+ createComponent({ props });
- await nextTick();
- expect(store.state.commit.commitAction).toBe('1');
+ await wrapper.find('input').trigger('change');
+
+ expect(store.state.commit.commitAction).toBe('1');
+ });
});
describe('with input', () => {
- beforeEach(async () => {
- vm.$destroy();
-
- const Component = Vue.extend(RadioGroup);
-
- store.state.commit.commitAction = '1';
- store.state.commit.newBranchName = 'test-123';
-
- vm = createComponentWithStore(Component, store, {
- value: '1',
- label: 'test',
- checked: true,
- showInput: true,
- });
-
- vm.$mount();
-
- await nextTick();
- });
+ const props = {
+ value: '2',
+ label: 'test',
+ checked: true,
+ showInput: true,
+ };
it('renders input box when commitAction matches value', () => {
- expect(vm.$el.querySelector('.form-control')).not.toBeNull();
+ createComponent({ props: { ...props, value: '2' } });
+
+ expect(wrapper.find('.form-control').exists()).toBe(true);
});
- it('hides input when commitAction doesnt match value', async () => {
- store.state.commit.commitAction = '2';
+ it('hides input when commitAction doesnt match value', () => {
+ createComponent({ props: { ...props, value: '1' } });
- await nextTick();
- expect(vm.$el.querySelector('.form-control')).toBeNull();
+ expect(wrapper.find('.form-control').exists()).toBe(false);
});
it('updates branch name in store on input', async () => {
- const input = vm.$el.querySelector('.form-control');
- input.value = 'testing-123';
- input.dispatchEvent(new Event('input'));
+ createComponent({ props });
+
+ await wrapper.find('.form-control').setValue('testing-123');
- await nextTick();
expect(store.state.commit.newBranchName).toBe('testing-123');
});
it('renders newBranchName if present', () => {
- const input = vm.$el.querySelector('.form-control');
+ createComponent({ props });
- expect(input.value).toBe('test-123');
+ const input = wrapper.find('.form-control');
+
+ expect(input.element.value).toBe('test-123');
});
});
describe('tooltipTitle', () => {
it('returns title when disabled', () => {
- vm.title = 'test title';
- vm.disabled = true;
+ createComponent({
+ props: { value: '1', label: 'test', disabled: true, title: 'test title' },
+ });
- expect(vm.tooltipTitle).toBe('test title');
+ const tooltip = getBinding(wrapper.findComponent(GlFormRadioGroup).element, 'gl-tooltip');
+ expect(tooltip.value).toBe('test title');
});
it('returns blank when not disabled', () => {
- vm.title = 'test title';
+ createComponent({
+ props: { value: '1', label: 'test', title: 'test title' },
+ });
+
+ const tooltip = getBinding(wrapper.findComponent(GlFormRadioGroup).element, 'gl-tooltip');
- expect(vm.tooltipTitle).not.toBe('test title');
+ expect(tooltip.value).toBe('');
});
});
});
diff --git a/spec/frontend/ide/components/file_row_extra_spec.js b/spec/frontend/ide/components/file_row_extra_spec.js
index 5a7a1fe7db0..281c549a1b4 100644
--- a/spec/frontend/ide/components/file_row_extra_spec.js
+++ b/spec/frontend/ide/components/file_row_extra_spec.js
@@ -1,146 +1,146 @@
-import Vue, { nextTick } from 'vue';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import Vuex from 'vuex';
+import { mount } from '@vue/test-utils';
import FileRowExtra from '~/ide/components/file_row_extra.vue';
-import { createStore } from '~/ide/stores';
+import { createStoreOptions } from '~/ide/stores';
import { file } from '../helpers';
describe('IDE extra file row component', () => {
- let Component;
- let vm;
+ let wrapper;
+ let store;
let unstagedFilesCount = 0;
let stagedFilesCount = 0;
let changesCount = 0;
- beforeAll(() => {
- Component = Vue.extend(FileRowExtra);
- });
+ const createComponent = (fileProps) => {
+ const storeConfig = createStoreOptions();
- beforeEach(() => {
- vm = createComponentWithStore(Component, createStore(), {
- file: {
- ...file('test'),
+ store = new Vuex.Store({
+ ...storeConfig,
+ getters: {
+ getUnstagedFilesCountForPath: () => () => unstagedFilesCount,
+ getStagedFilesCountForPath: () => () => stagedFilesCount,
+ getChangesInFolder: () => () => changesCount,
},
- dropdownOpen: false,
});
- jest.spyOn(vm, 'getUnstagedFilesCountForPath', 'get').mockReturnValue(() => unstagedFilesCount);
- jest.spyOn(vm, 'getStagedFilesCountForPath', 'get').mockReturnValue(() => stagedFilesCount);
- jest.spyOn(vm, 'getChangesInFolder', 'get').mockReturnValue(() => changesCount);
-
- vm.$mount();
- });
+ wrapper = mount(FileRowExtra, {
+ store,
+ propsData: {
+ file: {
+ ...file('test'),
+ type: 'tree',
+ ...fileProps,
+ },
+ dropdownOpen: false,
+ },
+ });
+ };
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
stagedFilesCount = 0;
unstagedFilesCount = 0;
changesCount = 0;
});
- describe('folderChangesTooltip', () => {
- it('returns undefined when changes count is 0', () => {
- changesCount = 0;
-
- expect(vm.folderChangesTooltip).toBe(undefined);
- });
-
+ describe('folder changes tooltip', () => {
[
{ input: 1, output: '1 changed file' },
{ input: 2, output: '2 changed files' },
].forEach(({ input, output }) => {
- it('returns changed files count if changes count is not 0', () => {
+ it('shows changed files count if changes count is not 0', () => {
changesCount = input;
+ createComponent();
- expect(vm.folderChangesTooltip).toBe(output);
+ expect(wrapper.find('.ide-file-modified').attributes('title')).toBe(output);
});
});
});
describe('show tree changes count', () => {
+ const findTreeChangesCount = () => wrapper.find('.ide-tree-changes');
+
it('does not show for blobs', () => {
- vm.file.type = 'blob';
+ createComponent({ type: 'blob' });
- expect(vm.$el.querySelector('.ide-tree-changes')).toBe(null);
+ expect(findTreeChangesCount().exists()).toBe(false);
});
it('does not show when changes count is 0', () => {
- vm.file.type = 'tree';
+ createComponent({ type: 'tree' });
- expect(vm.$el.querySelector('.ide-tree-changes')).toBe(null);
+ expect(findTreeChangesCount().exists()).toBe(false);
});
- it('does not show when tree is open', async () => {
- vm.file.type = 'tree';
- vm.file.opened = true;
+ it('does not show when tree is open', () => {
changesCount = 1;
+ createComponent({ type: 'tree', opened: true });
- await nextTick();
- expect(vm.$el.querySelector('.ide-tree-changes')).toBe(null);
+ expect(findTreeChangesCount().exists()).toBe(false);
});
- it('shows for trees with changes', async () => {
- vm.file.type = 'tree';
- vm.file.opened = false;
+ it('shows for trees with changes', () => {
changesCount = 1;
+ createComponent({ type: 'tree', opened: false });
- await nextTick();
- expect(vm.$el.querySelector('.ide-tree-changes')).not.toBe(null);
+ expect(findTreeChangesCount().exists()).toBe(true);
});
});
describe('changes file icon', () => {
+ const findChangedFileIcon = () => wrapper.find('.file-changed-icon');
+
it('hides when file is not changed', () => {
- expect(vm.$el.querySelector('.file-changed-icon')).toBe(null);
+ createComponent();
+
+ expect(findChangedFileIcon().exists()).toBe(false);
});
- it('shows when file is changed', async () => {
- vm.file.changed = true;
+ it('shows when file is changed', () => {
+ createComponent({ type: 'blob', changed: true });
- await nextTick();
- expect(vm.$el.querySelector('.file-changed-icon')).not.toBe(null);
+ expect(findChangedFileIcon().exists()).toBe(true);
});
- it('shows when file is staged', async () => {
- vm.file.staged = true;
+ it('shows when file is staged', () => {
+ createComponent({ type: 'blob', staged: true });
- await nextTick();
- expect(vm.$el.querySelector('.file-changed-icon')).not.toBe(null);
+ expect(findChangedFileIcon().exists()).toBe(true);
});
- it('shows when file is a tempFile', async () => {
- vm.file.tempFile = true;
+ it('shows when file is a tempFile', () => {
+ createComponent({ type: 'blob', tempFile: true });
- await nextTick();
- expect(vm.$el.querySelector('.file-changed-icon')).not.toBe(null);
+ expect(findChangedFileIcon().exists()).toBe(true);
});
- it('shows when file is renamed', async () => {
- vm.file.prevPath = 'original-file';
+ it('shows when file is renamed', () => {
+ createComponent({ type: 'blob', prevPath: 'original-file' });
- await nextTick();
- expect(vm.$el.querySelector('.file-changed-icon')).not.toBe(null);
+ expect(findChangedFileIcon().exists()).toBe(true);
});
- it('hides when file is renamed', async () => {
- vm.file.prevPath = 'original-file';
- vm.file.type = 'tree';
+ it('hides when tree is renamed', () => {
+ createComponent({ type: 'tree', prevPath: 'original-path' });
- await nextTick();
- expect(vm.$el.querySelector('.file-changed-icon')).toBe(null);
+ expect(findChangedFileIcon().exists()).toBe(false);
});
});
describe('merge request icon', () => {
+ const findMergeRequestIcon = () => wrapper.find('[data-testid="git-merge-icon"]');
+
it('hides when not a merge request change', () => {
- expect(vm.$el.querySelector('[data-testid="git-merge-icon"]')).toBe(null);
+ createComponent();
+
+ expect(findMergeRequestIcon().exists()).toBe(false);
});
- it('shows when a merge request change', async () => {
- vm.file.mrChange = true;
+ it('shows when a merge request change', () => {
+ createComponent({ mrChange: true });
- await nextTick();
- expect(vm.$el.querySelector('[data-testid="git-merge-icon"]')).not.toBe(null);
+ expect(findMergeRequestIcon().exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/ide/components/file_templates/bar_spec.js b/spec/frontend/ide/components/file_templates/bar_spec.js
index aaf9c17ccbf..60f37260393 100644
--- a/spec/frontend/ide/components/file_templates/bar_spec.js
+++ b/spec/frontend/ide/components/file_templates/bar_spec.js
@@ -1,19 +1,16 @@
-import Vue, { nextTick } from 'vue';
-import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
import Bar from '~/ide/components/file_templates/bar.vue';
import { createStore } from '~/ide/stores';
import { file } from '../../helpers';
describe('IDE file templates bar component', () => {
- let Component;
- let vm;
-
- beforeAll(() => {
- Component = Vue.extend(Bar);
- });
+ let wrapper;
+ let store;
beforeEach(() => {
- const store = createStore();
+ store = createStore();
+ jest.spyOn(store, 'dispatch').mockImplementation();
store.state.openFiles.push({
...file('file'),
@@ -21,24 +18,22 @@ describe('IDE file templates bar component', () => {
active: true,
});
- vm = mountComponentWithStore(Component, { store });
+ wrapper = mount(Bar, { store });
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
describe('template type dropdown', () => {
it('renders dropdown component', () => {
- expect(vm.$el.querySelector('.dropdown').textContent).toContain('Choose a type');
+ expect(wrapper.find('.dropdown').text()).toContain('Choose a type');
});
- it('calls setSelectedTemplateType when clicking item', () => {
- jest.spyOn(vm, 'setSelectedTemplateType').mockImplementation();
-
- vm.$el.querySelector('.dropdown-menu button').click();
+ it('calls setSelectedTemplateType when clicking item', async () => {
+ await wrapper.find('.dropdown-menu button').trigger('click');
- expect(vm.setSelectedTemplateType).toHaveBeenCalledWith({
+ expect(store.dispatch).toHaveBeenCalledWith('fileTemplates/setSelectedTemplateType', {
name: '.gitlab-ci.yml',
key: 'gitlab_ci_ymls',
});
@@ -46,60 +41,52 @@ describe('IDE file templates bar component', () => {
});
describe('template dropdown', () => {
- beforeEach(async () => {
- vm.$store.state.fileTemplates.templates = [
+ beforeEach(() => {
+ store.state.fileTemplates.templates = [
{
name: 'test',
},
];
- vm.$store.state.fileTemplates.selectedTemplateType = {
+ store.state.fileTemplates.selectedTemplateType = {
name: '.gitlab-ci.yml',
key: 'gitlab_ci_ymls',
};
-
- await nextTick();
});
it('renders dropdown component', () => {
- expect(vm.$el.querySelectorAll('.dropdown')[1].textContent).toContain('Choose a template');
+ expect(wrapper.findAll('.dropdown').at(1).text()).toContain('Choose a template');
});
- it('calls fetchTemplate on dropdown open', () => {
- jest.spyOn(vm, 'fetchTemplate').mockImplementation();
-
- vm.$el.querySelectorAll('.dropdown-menu')[1].querySelector('button').click();
+ it('calls fetchTemplate on dropdown open', async () => {
+ await wrapper.findAll('.dropdown-menu').at(1).find('button').trigger('click');
- expect(vm.fetchTemplate).toHaveBeenCalledWith({
+ expect(store.dispatch).toHaveBeenCalledWith('fileTemplates/fetchTemplate', {
name: 'test',
});
});
});
+ const findUndoButton = () => wrapper.find('.btn-default-secondary');
it('shows undo button if updateSuccess is true', async () => {
- vm.$store.state.fileTemplates.updateSuccess = true;
-
+ store.state.fileTemplates.updateSuccess = true;
await nextTick();
- expect(vm.$el.querySelector('.btn-default').style.display).not.toBe('none');
- });
- it('calls undoFileTemplate when clicking undo button', () => {
- jest.spyOn(vm, 'undoFileTemplate').mockImplementation();
+ expect(findUndoButton().isVisible()).toBe(true);
+ });
- vm.$el.querySelector('.btn-default-secondary').click();
+ it('calls undoFileTemplate when clicking undo button', async () => {
+ await findUndoButton().trigger('click');
- expect(vm.undoFileTemplate).toHaveBeenCalled();
+ expect(store.dispatch).toHaveBeenCalledWith('fileTemplates/undoFileTemplate', undefined);
});
it('calls setSelectedTemplateType if activeFile name matches a template', async () => {
const fileName = '.gitlab-ci.yml';
-
- jest.spyOn(vm, 'setSelectedTemplateType').mockImplementation(() => {});
- vm.$store.state.openFiles[0].name = fileName;
-
- vm.setInitialType();
+ store.state.openFiles = [{ ...file(fileName), opened: true, active: true }];
await nextTick();
- expect(vm.setSelectedTemplateType).toHaveBeenCalledWith({
+
+ expect(store.dispatch).toHaveBeenCalledWith('fileTemplates/setSelectedTemplateType', {
name: fileName,
key: 'gitlab_ci_ymls',
});
diff --git a/spec/frontend/ide/components/jobs/detail/description_spec.js b/spec/frontend/ide/components/jobs/detail/description_spec.js
index 128ccff6568..629c4424314 100644
--- a/spec/frontend/ide/components/jobs/detail/description_spec.js
+++ b/spec/frontend/ide/components/jobs/detail/description_spec.js
@@ -1,44 +1,43 @@
-import Vue from 'vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
+import { mount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
import Description from '~/ide/components/jobs/detail/description.vue';
import { jobs } from '../../../mock_data';
describe('IDE job description', () => {
- const Component = Vue.extend(Description);
- let vm;
+ let wrapper;
beforeEach(() => {
- vm = mountComponent(Component, {
- job: jobs[0],
+ wrapper = mount(Description, {
+ propsData: {
+ job: jobs[0],
+ },
});
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
it('renders job details', () => {
- expect(vm.$el.textContent).toContain('#1');
- expect(vm.$el.textContent).toContain('test');
+ expect(wrapper.text()).toContain('#1');
+ expect(wrapper.text()).toContain('test');
});
it('renders CI icon', () => {
- expect(
- vm.$el.querySelector('.ci-status-icon [data-testid="status_success_borderless-icon"]'),
- ).not.toBe(null);
+ expect(wrapper.find('.ci-status-icon').findComponent(GlIcon).exists()).toBe(true);
});
it('renders a borderless CI icon', () => {
- expect(
- vm.$el.querySelector('.borderless [data-testid="status_success_borderless-icon"]'),
- ).not.toBe(null);
+ expect(wrapper.find('.borderless').findComponent(GlIcon).exists()).toBe(true);
});
it('renders bridge job details without the job link', () => {
- vm = mountComponent(Component, {
- job: { ...jobs[0], path: undefined },
+ wrapper = mount(Description, {
+ propsData: {
+ job: { ...jobs[0], path: undefined },
+ },
});
- expect(vm.$el.querySelector('[data-testid="description-detail-link"]')).toBe(null);
+ expect(wrapper.find('[data-testid="description-detail-link"]').exists()).toBe(false);
});
});
diff --git a/spec/frontend/ide/components/jobs/detail_spec.js b/spec/frontend/ide/components/jobs/detail_spec.js
index 9122471d421..bf2be3aa595 100644
--- a/spec/frontend/ide/components/jobs/detail_spec.js
+++ b/spec/frontend/ide/components/jobs/detail_spec.js
@@ -1,15 +1,17 @@
-import Vue, { nextTick } from 'vue';
+import { nextTick } from 'vue';
+import { mount } from '@vue/test-utils';
+
import { TEST_HOST } from 'helpers/test_constants';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import JobDetail from '~/ide/components/jobs/detail.vue';
import { createStore } from '~/ide/stores';
import { jobs } from '../../mock_data';
describe('IDE jobs detail view', () => {
- let vm;
+ let wrapper;
+ let store;
const createComponent = () => {
- const store = createStore();
+ store = createStore();
store.state.pipelines.detailJob = {
...jobs[0],
@@ -18,163 +20,129 @@ describe('IDE jobs detail view', () => {
rawPath: `${TEST_HOST}/raw`,
};
- return createComponentWithStore(Vue.extend(JobDetail), store);
+ jest.spyOn(store, 'dispatch');
+ store.dispatch.mockResolvedValue();
+
+ wrapper = mount(JobDetail, { store });
};
- beforeEach(() => {
- vm = createComponent();
+ const findBuildJobLog = () => wrapper.find('pre');
+ const findScrollToBottomButton = () => wrapper.find('button[aria-label="Scroll to bottom"]');
+ const findScrollToTopButton = () => wrapper.find('button[aria-label="Scroll to top"]');
- jest.spyOn(vm, 'fetchJobLogs').mockResolvedValue();
+ beforeEach(() => {
+ createComponent();
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
describe('mounted', () => {
- beforeEach(() => {
- vm = vm.$mount();
- });
+ const findJobOutput = () => wrapper.find('.bash');
+ const findBuildLoaderAnimation = () => wrapper.find('.build-loader-animation');
it('calls fetchJobLogs', () => {
- expect(vm.fetchJobLogs).toHaveBeenCalled();
+ expect(store.dispatch).toHaveBeenCalledWith('pipelines/fetchJobLogs', undefined);
});
it('scrolls to bottom', () => {
- expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalled();
+ expect(findBuildJobLog().element.scrollTo).toHaveBeenCalled();
});
it('renders job output', () => {
- expect(vm.$el.querySelector('.bash').textContent).toContain('testing');
+ expect(findJobOutput().text()).toContain('testing');
});
it('renders empty message output', async () => {
- vm.$store.state.pipelines.detailJob.output = '';
-
+ store.state.pipelines.detailJob.output = '';
await nextTick();
- expect(vm.$el.querySelector('.bash').textContent).toContain('No messages were logged');
+
+ expect(findJobOutput().text()).toContain('No messages were logged');
});
it('renders loading icon', () => {
- expect(vm.$el.querySelector('.build-loader-animation')).not.toBe(null);
- expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe('');
+ expect(findBuildLoaderAnimation().exists()).toBe(true);
+ expect(findBuildLoaderAnimation().isVisible()).toBe(true);
});
it('hides output when loading', () => {
- expect(vm.$el.querySelector('.bash')).not.toBe(null);
- expect(vm.$el.querySelector('.bash').style.display).toBe('none');
+ expect(findJobOutput().exists()).toBe(true);
+ expect(findJobOutput().isVisible()).toBe(false);
});
it('hide loading icon when isLoading is false', async () => {
- vm.$store.state.pipelines.detailJob.isLoading = false;
-
+ store.state.pipelines.detailJob.isLoading = false;
await nextTick();
- expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe('none');
- });
- it('resets detailJob when clicking header button', () => {
- jest.spyOn(vm, 'setDetailJob').mockImplementation();
+ expect(findBuildLoaderAnimation().isVisible()).toBe(false);
+ });
- vm.$el.querySelector('.btn').click();
+ it('resets detailJob when clicking header button', async () => {
+ await wrapper.find('.btn').trigger('click');
- expect(vm.setDetailJob).toHaveBeenCalledWith(null);
+ expect(store.dispatch).toHaveBeenCalledWith('pipelines/setDetailJob', null);
});
it('renders raw path link', () => {
- expect(vm.$el.querySelector('.controllers-buttons').getAttribute('href')).toBe(
- `${TEST_HOST}/raw`,
- );
+ expect(wrapper.find('.controllers-buttons').attributes('href')).toBe(`${TEST_HOST}/raw`);
});
});
describe('scroll buttons', () => {
beforeEach(() => {
- vm = createComponent();
- jest.spyOn(vm, 'fetchJobLogs').mockResolvedValue();
- });
-
- afterEach(() => {
- vm.$destroy();
+ createComponent();
});
it.each`
- fnName | btnName | scrollPos
- ${'scrollDown'} | ${'down'} | ${0}
- ${'scrollUp'} | ${'up'} | ${1}
- `('triggers $fnName when clicking $btnName button', async ({ fnName, scrollPos }) => {
- jest.spyOn(vm, fnName).mockImplementation();
-
- vm = vm.$mount();
+ fnName | btnName | scrollPos | targetScrollPos
+ ${'scroll down'} | ${'down'} | ${0} | ${200}
+ ${'scroll up'} | ${'up'} | ${200} | ${0}
+ `('triggers $fnName when clicking $btnName button', async ({ scrollPos, targetScrollPos }) => {
+ jest.spyOn(findBuildJobLog().element, 'offsetHeight', 'get').mockReturnValue(0);
+ jest.spyOn(findBuildJobLog().element, 'scrollHeight', 'get').mockReturnValue(200);
+ jest.spyOn(findBuildJobLog().element, 'scrollTop', 'get').mockReturnValue(scrollPos);
+ findBuildJobLog().element.scrollTo.mockReset();
- vm.scrollPos = scrollPos;
-
- await nextTick();
- vm.$el.querySelector('.btn-scroll:not([disabled])').click();
- expect(vm[fnName]).toHaveBeenCalled();
- });
- });
-
- describe('scrollDown', () => {
- beforeEach(() => {
- vm = vm.$mount();
-
- jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation();
- });
-
- it('scrolls build trace to bottom', () => {
- jest.spyOn(vm.$refs.buildJobLog, 'scrollHeight', 'get').mockReturnValue(1000);
-
- vm.scrollDown();
-
- expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalledWith(0, 1000);
- });
- });
-
- describe('scrollUp', () => {
- beforeEach(() => {
- vm = vm.$mount();
-
- jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation();
- });
+ await findBuildJobLog().trigger('scroll'); // trigger button updates
- it('scrolls build trace to top', () => {
- vm.scrollUp();
+ await wrapper.find('.controllers button:not(:disabled)').trigger('click');
- expect(vm.$refs.buildJobLog.scrollTo).toHaveBeenCalledWith(0, 0);
+ expect(findBuildJobLog().element.scrollTo).toHaveBeenCalledWith(0, targetScrollPos);
});
});
- describe('scrollBuildLog', () => {
+ describe('scrolling build log', () => {
beforeEach(() => {
- vm = vm.$mount();
- jest.spyOn(vm.$refs.buildJobLog, 'scrollTo').mockImplementation();
- jest.spyOn(vm.$refs.buildJobLog, 'offsetHeight', 'get').mockReturnValue(100);
- jest.spyOn(vm.$refs.buildJobLog, 'scrollHeight', 'get').mockReturnValue(200);
+ jest.spyOn(findBuildJobLog().element, 'offsetHeight', 'get').mockReturnValue(100);
+ jest.spyOn(findBuildJobLog().element, 'scrollHeight', 'get').mockReturnValue(200);
});
- it('sets scrollPos to bottom when at the bottom', () => {
- jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(100);
+ it('keeps scroll at bottom when already at the bottom', async () => {
+ jest.spyOn(findBuildJobLog().element, 'scrollTop', 'get').mockReturnValue(100);
- vm.scrollBuildLog();
+ await findBuildJobLog().trigger('scroll');
- expect(vm.scrollPos).toBe(1);
+ expect(findScrollToBottomButton().attributes('disabled')).toBe('disabled');
+ expect(findScrollToTopButton().attributes('disabled')).not.toBe('disabled');
});
- it('sets scrollPos to top when at the top', () => {
- jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(0);
- vm.scrollPos = 1;
+ it('keeps scroll at top when already at top', async () => {
+ jest.spyOn(findBuildJobLog().element, 'scrollTop', 'get').mockReturnValue(0);
- vm.scrollBuildLog();
+ await findBuildJobLog().trigger('scroll');
- expect(vm.scrollPos).toBe(0);
+ expect(findScrollToBottomButton().attributes('disabled')).not.toBe('disabled');
+ expect(findScrollToTopButton().attributes('disabled')).toBe('disabled');
});
- it('resets scrollPos when not at top or bottom', () => {
- jest.spyOn(vm.$refs.buildJobLog, 'scrollTop', 'get').mockReturnValue(10);
+ it('resets scroll when not at top or bottom', async () => {
+ jest.spyOn(findBuildJobLog().element, 'scrollTop', 'get').mockReturnValue(10);
- vm.scrollBuildLog();
+ await findBuildJobLog().trigger('scroll');
- expect(vm.scrollPos).toBe('');
+ expect(findScrollToBottomButton().attributes('disabled')).not.toBe('disabled');
+ expect(findScrollToTopButton().attributes('disabled')).not.toBe('disabled');
});
});
});
diff --git a/spec/frontend/ide/components/jobs/item_spec.js b/spec/frontend/ide/components/jobs/item_spec.js
index c76760a5522..32e27333e42 100644
--- a/spec/frontend/ide/components/jobs/item_spec.js
+++ b/spec/frontend/ide/components/jobs/item_spec.js
@@ -1,36 +1,38 @@
-import Vue, { nextTick } from 'vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
+import { mount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
+
import JobItem from '~/ide/components/jobs/item.vue';
import { jobs } from '../../mock_data';
describe('IDE jobs item', () => {
- const Component = Vue.extend(JobItem);
const job = jobs[0];
- let vm;
+ let wrapper;
beforeEach(() => {
- vm = mountComponent(Component, {
- job,
- });
+ wrapper = mount(JobItem, { propsData: { job } });
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
it('renders job details', () => {
- expect(vm.$el.textContent).toContain(job.name);
- expect(vm.$el.textContent).toContain(`#${job.id}`);
+ expect(wrapper.text()).toContain(job.name);
+ expect(wrapper.text()).toContain(`#${job.id}`);
});
it('renders CI icon', () => {
- expect(vm.$el.querySelector('[data-testid="status_success_borderless-icon"]')).not.toBe(null);
+ expect(wrapper.find('[data-testid="status_success_borderless-icon"]').exists()).toBe(true);
});
it('does not render view logs button if not started', async () => {
- vm.job.started = false;
+ await wrapper.setProps({
+ job: {
+ ...jobs[0],
+ started: false,
+ },
+ });
- await nextTick();
- expect(vm.$el.querySelector('.btn')).toBe(null);
+ expect(wrapper.findComponent(GlButton).exists()).toBe(false);
});
});
diff --git a/spec/frontend/ide/components/new_dropdown/button_spec.js b/spec/frontend/ide/components/new_dropdown/button_spec.js
index 298d7b810e1..a9cfdfd20c1 100644
--- a/spec/frontend/ide/components/new_dropdown/button_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/button_spec.js
@@ -1,59 +1,60 @@
-import Vue, { nextTick } from 'vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
+import { mount } from '@vue/test-utils';
import Button from '~/ide/components/new_dropdown/button.vue';
describe('IDE new entry dropdown button component', () => {
- let Component;
- let vm;
-
- beforeAll(() => {
- Component = Vue.extend(Button);
- });
-
- beforeEach(() => {
- vm = mountComponent(Component, {
- label: 'Testing',
- icon: 'doc-new',
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(Button, {
+ propsData: {
+ label: 'Testing',
+ icon: 'doc-new',
+ ...props,
+ },
});
-
- jest.spyOn(vm, '$emit').mockImplementation(() => {});
- });
+ };
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
it('renders button with label', () => {
- expect(vm.$el.textContent).toContain('Testing');
+ createComponent();
+
+ expect(wrapper.text()).toContain('Testing');
});
it('renders icon', () => {
- expect(vm.$el.querySelector('[data-testid="doc-new-icon"]')).not.toBe(null);
+ createComponent();
+
+ expect(wrapper.find('[data-testid="doc-new-icon"]').exists()).toBe(true);
});
- it('emits click event', () => {
- vm.$el.click();
+ it('emits click event', async () => {
+ createComponent();
- expect(vm.$emit).toHaveBeenCalledWith('click');
+ await wrapper.trigger('click');
+
+ expect(wrapper.emitted('click')).toHaveLength(1);
});
- it('hides label if showLabel is false', async () => {
- vm.showLabel = false;
+ it('hides label if showLabel is false', () => {
+ createComponent({ showLabel: false });
- await nextTick();
- expect(vm.$el.textContent).not.toContain('Testing');
+ expect(wrapper.text()).not.toContain('Testing');
});
- describe('tooltipTitle', () => {
+ describe('tooltip title', () => {
it('returns empty string when showLabel is true', () => {
- expect(vm.tooltipTitle).toBe('');
+ createComponent({ showLabel: true });
+
+ expect(wrapper.attributes('title')).toBe('');
});
- it('returns label', async () => {
- vm.showLabel = false;
+ it('returns label', () => {
+ createComponent({ showLabel: false });
- await nextTick();
- expect(vm.tooltipTitle).toBe('Testing');
+ expect(wrapper.attributes('title')).toBe('Testing');
});
});
});
diff --git a/spec/frontend/ide/components/new_dropdown/upload_spec.js b/spec/frontend/ide/components/new_dropdown/upload_spec.js
index 3eafe9e7ccb..fc643589d51 100644
--- a/spec/frontend/ide/components/new_dropdown/upload_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/upload_spec.js
@@ -1,39 +1,34 @@
-import Vue from 'vue';
-import createComponent from 'helpers/vue_mount_component_helper';
-import upload from '~/ide/components/new_dropdown/upload.vue';
+import { mount } from '@vue/test-utils';
+import Upload from '~/ide/components/new_dropdown/upload.vue';
describe('new dropdown upload', () => {
- let vm;
+ let wrapper;
beforeEach(() => {
- const Component = Vue.extend(upload);
-
- vm = createComponent(Component, {
- path: '',
+ wrapper = mount(Upload, {
+ propsData: {
+ path: '',
+ },
});
-
- vm.entryName = 'testing';
-
- jest.spyOn(vm, '$emit');
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
describe('openFile', () => {
it('calls for each file', () => {
const files = ['test', 'test2', 'test3'];
- jest.spyOn(vm, 'readFile').mockImplementation(() => {});
- jest.spyOn(vm.$refs.fileUpload, 'files', 'get').mockReturnValue(files);
+ jest.spyOn(wrapper.vm, 'readFile').mockImplementation(() => {});
+ jest.spyOn(wrapper.vm.$refs.fileUpload, 'files', 'get').mockReturnValue(files);
- vm.openFile();
+ wrapper.vm.openFile();
- expect(vm.readFile.mock.calls.length).toBe(3);
+ expect(wrapper.vm.readFile.mock.calls.length).toBe(3);
files.forEach((file, i) => {
- expect(vm.readFile.mock.calls[i]).toEqual([file]);
+ expect(wrapper.vm.readFile.mock.calls[i]).toEqual([file]);
});
});
});
@@ -48,7 +43,7 @@ describe('new dropdown upload', () => {
type: 'images/png',
};
- vm.readFile(file);
+ wrapper.vm.readFile(file);
expect(FileReader.prototype.readAsDataURL).toHaveBeenCalledWith(file);
});
@@ -71,35 +66,39 @@ describe('new dropdown upload', () => {
it('calls readAsText and creates file in plain text (without encoding) if the file content is plain text', async () => {
const waitForCreate = new Promise((resolve) => {
- vm.$on('create', resolve);
+ wrapper.vm.$on('create', resolve);
});
- vm.createFile(textTarget, textFile);
+ wrapper.vm.createFile(textTarget, textFile);
expect(FileReader.prototype.readAsText).toHaveBeenCalledWith(textFile);
await waitForCreate;
- expect(vm.$emit).toHaveBeenCalledWith('create', {
- name: textFile.name,
- type: 'blob',
- content: 'plain text',
- rawPath: '',
- mimeType: 'test/mime-text',
- });
+ expect(wrapper.emitted('create')[0]).toStrictEqual([
+ {
+ name: textFile.name,
+ type: 'blob',
+ content: 'plain text',
+ rawPath: '',
+ mimeType: 'test/mime-text',
+ },
+ ]);
});
it('creates a blob URL for the content if binary', () => {
- vm.createFile(binaryTarget, binaryFile);
+ wrapper.vm.createFile(binaryTarget, binaryFile);
expect(FileReader.prototype.readAsText).not.toHaveBeenCalled();
- expect(vm.$emit).toHaveBeenCalledWith('create', {
- name: binaryFile.name,
- type: 'blob',
- content: 'ðððð',
- rawPath: 'blob:https://gitlab.com/048c7ac1-98de-4a37-ab1b-0206d0ea7e1b',
- mimeType: 'test/mime-binary',
- });
+ expect(wrapper.emitted('create')[0]).toStrictEqual([
+ {
+ name: binaryFile.name,
+ type: 'blob',
+ content: 'ðððð',
+ rawPath: 'blob:https://gitlab.com/048c7ac1-98de-4a37-ab1b-0206d0ea7e1b',
+ mimeType: 'test/mime-binary',
+ },
+ ]);
});
});
});
diff --git a/spec/frontend/ide/components/shared/tokened_input_spec.js b/spec/frontend/ide/components/shared/tokened_input_spec.js
index 2efef9918b1..b70c9659e46 100644
--- a/spec/frontend/ide/components/shared/tokened_input_spec.js
+++ b/spec/frontend/ide/components/shared/tokened_input_spec.js
@@ -1,5 +1,4 @@
-import Vue, { nextTick } from 'vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
+import { mount } from '@vue/test-utils';
import TokenedInput from '~/ide/components/shared/tokened_input.vue';
const TEST_PLACEHOLDER = 'Searching in test';
@@ -10,120 +9,106 @@ const TEST_TOKENS = [
];
const TEST_VALUE = 'lorem';
-function getTokenElements(vm) {
- return Array.from(vm.$el.querySelectorAll('.filtered-search-token button'));
-}
-
-function createBackspaceEvent() {
- const e = new Event('keyup');
- e.keyCode = 8;
- e.which = e.keyCode;
- e.altKey = false;
- e.ctrlKey = true;
- e.shiftKey = false;
- e.metaKey = false;
- return e;
+function getTokenElements(wrapper) {
+ return wrapper.findAll('.filtered-search-token button');
}
describe('IDE shared/TokenedInput', () => {
- const Component = Vue.extend(TokenedInput);
- let vm;
-
- beforeEach(() => {
- vm = mountComponent(Component, {
- tokens: TEST_TOKENS,
- placeholder: TEST_PLACEHOLDER,
- value: TEST_VALUE,
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(TokenedInput, {
+ propsData: {
+ tokens: TEST_TOKENS,
+ placeholder: TEST_PLACEHOLDER,
+ value: TEST_VALUE,
+ ...props,
+ },
+ attachTo: document.body,
});
-
- jest.spyOn(vm, '$emit').mockImplementation(() => {});
- });
+ };
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
it('renders tokens', () => {
- const renderedTokens = getTokenElements(vm).map((x) => x.textContent.trim());
+ createComponent();
+ const renderedTokens = getTokenElements(wrapper).wrappers.map((w) => w.text());
expect(renderedTokens).toEqual(TEST_TOKENS.map((x) => x.label));
});
it('renders input', () => {
- expect(vm.$refs.input).toBeInstanceOf(HTMLInputElement);
- expect(vm.$refs.input).toHaveValue(TEST_VALUE);
- });
-
- it('renders placeholder, when tokens are empty', async () => {
- vm.tokens = [];
+ createComponent();
- await nextTick();
- expect(vm.$refs.input).toHaveAttr('placeholder', TEST_PLACEHOLDER);
+ expect(wrapper.find('input').element).toBeInstanceOf(HTMLInputElement);
+ expect(wrapper.find('input').element).toHaveValue(TEST_VALUE);
});
- it('triggers "removeToken" on token click', () => {
- getTokenElements(vm)[0].click();
+ it('renders placeholder, when tokens are empty', () => {
+ createComponent({ tokens: [] });
- expect(vm.$emit).toHaveBeenCalledWith('removeToken', TEST_TOKENS[0]);
+ expect(wrapper.find('input').attributes('placeholder')).toBe(TEST_PLACEHOLDER);
});
- it('when input triggers backspace event, it calls "onBackspace"', () => {
- jest.spyOn(vm, 'onBackspace').mockImplementation(() => {});
+ it('triggers "removeToken" on token click', async () => {
+ createComponent();
+ await getTokenElements(wrapper).at(0).trigger('click');
- vm.$refs.input.dispatchEvent(createBackspaceEvent());
- vm.$refs.input.dispatchEvent(createBackspaceEvent());
-
- expect(vm.onBackspace).toHaveBeenCalledTimes(2);
+ expect(wrapper.emitted('removeToken')[0]).toStrictEqual([TEST_TOKENS[0]]);
});
- it('triggers "removeToken" on backspaces when value is empty', () => {
- vm.value = '';
-
- vm.onBackspace();
+ it('removes token on backspace when value is empty', async () => {
+ createComponent({ value: '' });
- expect(vm.$emit).not.toHaveBeenCalled();
- expect(vm.backspaceCount).toEqual(1);
+ expect(wrapper.emitted('removeToken')).toBeUndefined();
- vm.onBackspace();
+ await wrapper.find('input').trigger('keyup.delete');
+ await wrapper.find('input').trigger('keyup.delete');
- expect(vm.$emit).toHaveBeenCalledWith('removeToken', TEST_TOKENS[TEST_TOKENS.length - 1]);
- expect(vm.backspaceCount).toEqual(0);
+ expect(wrapper.emitted('removeToken')[0]).toStrictEqual([TEST_TOKENS[TEST_TOKENS.length - 1]]);
});
- it('does not trigger "removeToken" on backspaces when value is not empty', () => {
- vm.onBackspace();
- vm.onBackspace();
+ it('does not trigger "removeToken" on backspaces when value is not empty', async () => {
+ createComponent({ value: 'SOMETHING' });
+
+ await wrapper.find('input').trigger('keyup.delete');
+ await wrapper.find('input').trigger('keyup.delete');
- expect(vm.backspaceCount).toEqual(0);
- expect(vm.$emit).not.toHaveBeenCalled();
+ expect(wrapper.emitted('removeToken')).toBeUndefined();
});
- it('does not trigger "removeToken" on backspaces when tokens are empty', () => {
- vm.tokens = [];
+ it('does not trigger "removeToken" on backspaces when tokens are empty', async () => {
+ createComponent({ value: '', tokens: [] });
- vm.onBackspace();
- vm.onBackspace();
+ await wrapper.find('input').trigger('keyup.delete');
+ await wrapper.find('input').trigger('keyup.delete');
- expect(vm.backspaceCount).toEqual(0);
- expect(vm.$emit).not.toHaveBeenCalled();
+ expect(wrapper.emitted('removeToken')).toBeUndefined();
});
- it('triggers "focus" on input focus', () => {
- vm.$refs.input.dispatchEvent(new Event('focus'));
+ it('triggers "focus" on input focus', async () => {
+ createComponent();
- expect(vm.$emit).toHaveBeenCalledWith('focus');
+ await wrapper.find('input').trigger('focus');
+
+ expect(wrapper.emitted('focus')).toHaveLength(1);
});
- it('triggers "blur" on input blur', () => {
- vm.$refs.input.dispatchEvent(new Event('blur'));
+ it('triggers "blur" on input blur', async () => {
+ createComponent();
+
+ await wrapper.find('input').trigger('blur');
- expect(vm.$emit).toHaveBeenCalledWith('blur');
+ expect(wrapper.emitted('blur')).toHaveLength(1);
});
- it('triggers "input" with value on input change', () => {
- vm.$refs.input.value = 'something-else';
- vm.$refs.input.dispatchEvent(new Event('input'));
+ it('triggers "input" with value on input change', async () => {
+ createComponent();
+
+ await wrapper.find('input').setValue('something-else');
- expect(vm.$emit).toHaveBeenCalledWith('input', 'something-else');
+ expect(wrapper.emitted('input')[0]).toStrictEqual(['something-else']);
});
});