summaryrefslogtreecommitdiff
path: root/spec/frontend/vue_shared/components
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/vue_shared/components')
-rw-r--r--spec/frontend/vue_shared/components/color_picker/color_picker_spec.js39
-rw-r--r--spec/frontend/vue_shared/components/editor_lite_spec.js9
-rw-r--r--spec/frontend/vue_shared/components/file_row_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap8
-rw-r--r--spec/frontend/vue_shared/components/gl_countdown_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/gl_modal_vuex_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/help_popover_spec.js65
-rw-r--r--spec/frontend/vue_shared/components/issue/issue_milestone_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/markdown/field_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/modal_copy_button_spec.js3
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/mock_data.js107
-rw-r--r--spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js113
-rw-r--r--spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap43
-rw-r--r--spec/frontend/vue_shared/components/settings/settings_block_spec.js86
-rw-r--r--spec/frontend/vue_shared/components/todo_button_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js2
17 files changed, 452 insertions, 40 deletions
diff --git a/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js b/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js
index c8fe6c3131c..d30f36ec63c 100644
--- a/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js
+++ b/spec/frontend/vue_shared/components/color_picker/color_picker_spec.js
@@ -13,6 +13,7 @@ describe('ColorPicker', () => {
};
const setColor = '#000000';
+ const invalidText = 'Please enter a valid hex (#RRGGBB or #RGB) color value';
const label = () => wrapper.find(GlFormGroup).attributes('label');
const colorPreview = () => wrapper.find('[data-testid="color-preview"]');
const colorPicker = () => wrapper.find(GlFormInput);
@@ -28,8 +29,6 @@ describe('ColorPicker', () => {
'#428BCA': 'Moderate blue',
'#44AD8E': 'Lime green',
};
-
- createComponent(shallowMount);
});
afterEach(() => {
@@ -38,6 +37,8 @@ describe('ColorPicker', () => {
describe('label', () => {
it('hides the label if the label is not passed', () => {
+ createComponent(shallowMount);
+
expect(label()).toBe('');
});
@@ -55,43 +56,37 @@ describe('ColorPicker', () => {
expect(colorPreview().attributes('style')).toBe(undefined);
expect(colorPicker().attributes('value')).toBe(undefined);
expect(colorInput().props('value')).toBe('');
+ expect(colorPreview().attributes('class')).toContain('gl-inset-border-1-gray-400');
});
it('has a color set on initialization', () => {
- createComponent(shallowMount, { setColor });
+ createComponent(mount, { value: setColor });
- expect(wrapper.vm.$data.selectedColor).toBe(setColor);
+ expect(colorInput().props('value')).toBe(setColor);
});
it('emits input event from component when a color is selected', async () => {
createComponent();
await colorInput().setValue(setColor);
- expect(wrapper.emitted().input[0]).toEqual([setColor]);
+ expect(wrapper.emitted().input[0]).toStrictEqual([setColor]);
});
it('trims spaces from submitted colors', async () => {
createComponent();
await colorInput().setValue(` ${setColor} `);
- expect(wrapper.vm.$data.selectedColor).toBe(setColor);
+ expect(wrapper.emitted().input[0]).toStrictEqual([setColor]);
+ expect(colorPreview().attributes('class')).toContain('gl-inset-border-1-gray-400');
+ expect(colorInput().attributes('class')).not.toContain('is-invalid');
});
- it('shows invalid feedback when an invalid color is used', async () => {
- createComponent();
- await colorInput().setValue('abcd');
-
- expect(invalidFeedback().text()).toBe(
- 'Please enter a valid hex (#RRGGBB or #RGB) color value',
- );
- expect(wrapper.emitted().input).toBe(undefined);
- });
-
- it('shows an invalid feedback border on the preview when an invalid color is used', async () => {
- createComponent();
- await colorInput().setValue('abcd');
+ it('shows invalid feedback when the state is marked as invalid', async () => {
+ createComponent(mount, { invalidFeedback: invalidText, state: false });
+ expect(invalidFeedback().text()).toBe(invalidText);
expect(colorPreview().attributes('class')).toContain('gl-inset-border-1-red-500');
+ expect(colorInput().attributes('class')).toContain('is-invalid');
});
});
@@ -100,14 +95,14 @@ describe('ColorPicker', () => {
createComponent();
await colorInput().setValue(setColor);
- expect(wrapper.vm.$data.selectedColor).toBe(setColor);
+ expect(wrapper.emitted().input[0]).toStrictEqual([setColor]);
});
it('has color picker value entered', async () => {
createComponent();
await colorPicker().setValue(setColor);
- expect(wrapper.vm.$data.selectedColor).toBe(setColor);
+ expect(wrapper.emitted().input[0]).toStrictEqual([setColor]);
});
});
@@ -132,7 +127,7 @@ describe('ColorPicker', () => {
createComponent();
await presetColors().at(0).trigger('click');
- expect(wrapper.vm.$data.selectedColor).toBe(setColor);
+ expect(wrapper.emitted().input[0]).toStrictEqual([setColor]);
});
});
});
diff --git a/spec/frontend/vue_shared/components/editor_lite_spec.js b/spec/frontend/vue_shared/components/editor_lite_spec.js
index 70fdd8e24a5..9298851d143 100644
--- a/spec/frontend/vue_shared/components/editor_lite_spec.js
+++ b/spec/frontend/vue_shared/components/editor_lite_spec.js
@@ -2,6 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import EditorLite from '~/vue_shared/components/editor_lite.vue';
import Editor from '~/editor/editor_lite';
+import { EDITOR_READY_EVENT } from '~/editor/constants';
jest.mock('~/editor/editor_lite');
@@ -110,13 +111,13 @@ describe('Editor Lite component', () => {
expect(wrapper.emitted().input).toEqual([[value]]);
});
- it('emits editor-ready event when the Editor Lite is ready', async () => {
+ it('emits EDITOR_READY_EVENT event when the Editor Lite is ready', async () => {
const el = wrapper.find({ ref: 'editor' }).element;
- expect(wrapper.emitted()['editor-ready']).toBeUndefined();
+ expect(wrapper.emitted()[EDITOR_READY_EVENT]).toBeUndefined();
- await el.dispatchEvent(new Event('editor-ready'));
+ await el.dispatchEvent(new Event(EDITOR_READY_EVENT));
- expect(wrapper.emitted()['editor-ready']).toBeDefined();
+ expect(wrapper.emitted()[EDITOR_READY_EVENT]).toBeDefined();
});
it('component API `getEditor()` returns the editor instance', () => {
diff --git a/spec/frontend/vue_shared/components/file_row_spec.js b/spec/frontend/vue_shared/components/file_row_spec.js
index bd6a18bf704..92690f6fc37 100644
--- a/spec/frontend/vue_shared/components/file_row_spec.js
+++ b/spec/frontend/vue_shared/components/file_row_spec.js
@@ -1,6 +1,6 @@
-import { file } from 'jest/ide/helpers';
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
+import { file } from 'jest/ide/helpers';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileHeader from '~/vue_shared/components/file_row_header.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
diff --git a/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap b/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap
index d8e6e37bb89..5f55502567b 100644
--- a/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap
+++ b/spec/frontend/vue_shared/components/gfm_autocomplete/__snapshots__/utils_spec.js.snap
@@ -21,10 +21,10 @@ exports[`gfm_autocomplete/utils labels config shows the title in the menu item 1
exports[`gfm_autocomplete/utils members config shows an avatar character, name, parent name, and count in the menu item for a group 1`] = `
"
<div class=\\"gl-display-flex gl-align-items-center\\">
- <div class=\\"gl-avatar gl-avatar-s24 gl-flex-shrink-0 gl-rounded-small
+ <div class=\\"gl-avatar gl-avatar-s32 gl-flex-shrink-0 gl-rounded-small
gl-display-flex gl-align-items-center gl-justify-content-center\\" aria-hidden=\\"true\\">
G</div>
- <div class=\\"gl-font-sm gl-line-height-normal gl-ml-3\\">
+ <div class=\\"gl-line-height-normal gl-ml-4\\">
<div>1-1s &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt; (2)</div>
<div class=\\"gl-text-gray-700\\">GitLab Support Team</div>
</div>
@@ -36,8 +36,8 @@ exports[`gfm_autocomplete/utils members config shows an avatar character, name,
exports[`gfm_autocomplete/utils members config shows the avatar, name and username in the menu item for a user 1`] = `
"
<div class=\\"gl-display-flex gl-align-items-center\\">
- <img class=\\"gl-avatar gl-avatar-s24 gl-flex-shrink-0 gl-avatar-circle\\" src=\\"/uploads/-/system/user/avatar/123456/avatar.png\\" alt=\\"\\" />
- <div class=\\"gl-font-sm gl-line-height-normal gl-ml-3\\">
+ <img class=\\"gl-avatar gl-avatar-s32 gl-flex-shrink-0 gl-avatar-circle\\" src=\\"/uploads/-/system/user/avatar/123456/avatar.png\\" alt=\\"\\" />
+ <div class=\\"gl-line-height-normal gl-ml-4\\">
<div>My Name &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;</div>
<div class=\\"gl-text-gray-700\\">@myusername</div>
</div>
diff --git a/spec/frontend/vue_shared/components/gl_countdown_spec.js b/spec/frontend/vue_shared/components/gl_countdown_spec.js
index fcc5c0cd310..82d18c7fd3f 100644
--- a/spec/frontend/vue_shared/components/gl_countdown_spec.js
+++ b/spec/frontend/vue_shared/components/gl_countdown_spec.js
@@ -1,5 +1,5 @@
-import mountComponent from 'helpers/vue_mount_component_helper';
import Vue from 'vue';
+import mountComponent from 'helpers/vue_mount_component_helper';
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
describe('GlCountdown', () => {
diff --git a/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js b/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js
index 6802499ed52..81518e67377 100644
--- a/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js
+++ b/spec/frontend/vue_shared/components/gl_modal_vuex_spec.js
@@ -3,6 +3,7 @@ import Vuex from 'vuex';
import { GlModal } from '@gitlab/ui';
import GlModalVuex from '~/vue_shared/components/gl_modal_vuex.vue';
import createState from '~/vuex_shared/modules/modal/state';
+import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
@@ -129,7 +130,7 @@ describe('GlModalVuex', () => {
wrapper.vm
.$nextTick()
.then(() => {
- expect(rootEmit).toHaveBeenCalledWith('bv::show::modal', TEST_MODAL_ID);
+ expect(rootEmit).toHaveBeenCalledWith(BV_SHOW_MODAL, TEST_MODAL_ID);
})
.then(done)
.catch(done.fail);
@@ -146,7 +147,7 @@ describe('GlModalVuex', () => {
wrapper.vm
.$nextTick()
.then(() => {
- expect(rootEmit).toHaveBeenCalledWith('bv::hide::modal', TEST_MODAL_ID);
+ expect(rootEmit).toHaveBeenCalledWith(BV_HIDE_MODAL, TEST_MODAL_ID);
})
.then(done)
.catch(done.fail);
diff --git a/spec/frontend/vue_shared/components/help_popover_spec.js b/spec/frontend/vue_shared/components/help_popover_spec.js
new file mode 100644
index 00000000000..112085e91e1
--- /dev/null
+++ b/spec/frontend/vue_shared/components/help_popover_spec.js
@@ -0,0 +1,65 @@
+import { mount } from '@vue/test-utils';
+import { GlButton, GlPopover } from '@gitlab/ui';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
+
+describe('HelpPopover', () => {
+ let wrapper;
+ const title = 'popover <strong>title</strong>';
+ const content = 'popover <b>content</b>';
+
+ const findQuestionButton = () => wrapper.find(GlButton);
+ const findPopover = () => wrapper.find(GlPopover);
+ const buildWrapper = (options = {}) => {
+ wrapper = mount(HelpPopover, {
+ propsData: {
+ options: {
+ title,
+ content,
+ ...options,
+ },
+ },
+ });
+ };
+
+ beforeEach(() => {
+ buildWrapper();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('renders a link button with an icon question', () => {
+ expect(findQuestionButton().props()).toMatchObject({
+ icon: 'question',
+ variant: 'link',
+ });
+ expect(findQuestionButton().attributes().tabindex).toBe('0');
+ });
+
+ it('renders popover that uses the question button as target', () => {
+ expect(findPopover().props().target()).toBe(findQuestionButton().vm.$el);
+ });
+
+ it('triggers popover on hover and focus', () => {
+ expect(findPopover().props().triggers).toBe('hover focus');
+ });
+
+ it('allows rendering title with HTML tags', () => {
+ expect(findPopover().find('strong').exists()).toBe(true);
+ });
+
+ it('allows rendering content with HTML tags', () => {
+ expect(findPopover().find('b').exists()).toBe(true);
+ });
+
+ it('binds other popover options to the popover instance', () => {
+ const placement = 'bottom';
+
+ wrapper.destroy();
+ buildWrapper({ placement });
+
+ expect(findPopover().props().placement).toBe(placement);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/issue/issue_milestone_spec.js b/spec/frontend/vue_shared/components/issue/issue_milestone_spec.js
index ffcb891c4fc..8143196c6e8 100644
--- a/spec/frontend/vue_shared/components/issue/issue_milestone_spec.js
+++ b/spec/frontend/vue_shared/components/issue/issue_milestone_spec.js
@@ -1,8 +1,8 @@
import Vue from 'vue';
import { shallowMount } from '@vue/test-utils';
-import { mockMilestone } from 'jest/boards/mock_data';
import { GlIcon } from '@gitlab/ui';
+import { mockMilestone } from 'jest/boards/mock_data';
import IssueMilestone from '~/vue_shared/components/issue/issue_milestone.vue';
const createComponent = (milestone = mockMilestone) => {
diff --git a/spec/frontend/vue_shared/components/markdown/field_spec.js b/spec/frontend/vue_shared/components/markdown/field_spec.js
index a2ce6f40193..97cc22e1418 100644
--- a/spec/frontend/vue_shared/components/markdown/field_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/field_spec.js
@@ -1,7 +1,7 @@
import { mount } from '@vue/test-utils';
-import { TEST_HOST, FIXTURES_PATH } from 'spec/test_constants';
import AxiosMockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
+import { TEST_HOST, FIXTURES_PATH } from 'spec/test_constants';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import axios from '~/lib/utils/axios_utils';
diff --git a/spec/frontend/vue_shared/components/modal_copy_button_spec.js b/spec/frontend/vue_shared/components/modal_copy_button_spec.js
index ca9f8ff54d4..97d4313b89e 100644
--- a/spec/frontend/vue_shared/components/modal_copy_button_spec.js
+++ b/spec/frontend/vue_shared/components/modal_copy_button_spec.js
@@ -1,5 +1,6 @@
import { shallowMount, createWrapper } from '@vue/test-utils';
import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
+import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
describe('modal copy button', () => {
let wrapper;
@@ -31,7 +32,7 @@ describe('modal copy button', () => {
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.emitted().success).not.toBeEmpty();
expect(document.execCommand).toHaveBeenCalledWith('copy');
- expect(root.emitted('bv::hide::tooltip')).toEqual([['test-id']]);
+ expect(root.emitted(BV_HIDE_TOOLTIP)).toEqual([['test-id']]);
});
});
it("should propagate the clipboard error event if execCommand doesn't work", () => {
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js
index 0e6f951bd53..594b1ab9d78 100644
--- a/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js
+++ b/spec/frontend/vue_shared/components/rich_content_editor/toolbar_item_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { GlIcon } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import ToolbarItem from '~/vue_shared/components/rich_content_editor/toolbar_item.vue';
describe('Toolbar Item', () => {
diff --git a/spec/frontend/vue_shared/components/runner_instructions/mock_data.js b/spec/frontend/vue_shared/components/runner_instructions/mock_data.js
new file mode 100644
index 00000000000..01f7f3d49c7
--- /dev/null
+++ b/spec/frontend/vue_shared/components/runner_instructions/mock_data.js
@@ -0,0 +1,107 @@
+export const mockGraphqlRunnerPlatforms = {
+ data: {
+ runnerPlatforms: {
+ nodes: [
+ {
+ name: 'linux',
+ humanReadableName: 'Linux',
+ architectures: {
+ nodes: [
+ {
+ name: 'amd64',
+ downloadLocation:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64',
+ __typename: 'RunnerArchitecture',
+ },
+ {
+ name: '386',
+ downloadLocation:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-386',
+ __typename: 'RunnerArchitecture',
+ },
+ {
+ name: 'arm',
+ downloadLocation:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm',
+ __typename: 'RunnerArchitecture',
+ },
+ {
+ name: 'arm64',
+ downloadLocation:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm64',
+ __typename: 'RunnerArchitecture',
+ },
+ ],
+ __typename: 'RunnerArchitectureConnection',
+ },
+ __typename: 'RunnerPlatform',
+ },
+ {
+ name: 'osx',
+ humanReadableName: 'macOS',
+ architectures: {
+ nodes: [
+ {
+ name: 'amd64',
+ downloadLocation:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64',
+ __typename: 'RunnerArchitecture',
+ },
+ ],
+ __typename: 'RunnerArchitectureConnection',
+ },
+ __typename: 'RunnerPlatform',
+ },
+ {
+ name: 'windows',
+ humanReadableName: 'Windows',
+ architectures: {
+ nodes: [
+ {
+ name: 'amd64',
+ downloadLocation:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe',
+ __typename: 'RunnerArchitecture',
+ },
+ {
+ name: '386',
+ downloadLocation:
+ 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-386.exe',
+ __typename: 'RunnerArchitecture',
+ },
+ ],
+ __typename: 'RunnerArchitectureConnection',
+ },
+ __typename: 'RunnerPlatform',
+ },
+ {
+ name: 'docker',
+ humanReadableName: 'Docker',
+ architectures: null,
+ __typename: 'RunnerPlatform',
+ },
+ {
+ name: 'kubernetes',
+ humanReadableName: 'Kubernetes',
+ architectures: null,
+ __typename: 'RunnerPlatform',
+ },
+ ],
+ __typename: 'RunnerPlatformConnection',
+ },
+ project: { id: 'gid://gitlab/Project/1', __typename: 'Project' },
+ group: null,
+ },
+};
+
+export const mockGraphqlInstructions = {
+ data: {
+ runnerSetup: {
+ installInstructions:
+ "# Download the binary for your system\nsudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64\n\n# Give it permissions to execute\nsudo chmod +x /usr/local/bin/gitlab-runner\n\n# Create a GitLab CI user\nsudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash\n\n# Install and run as service\nsudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner\nsudo gitlab-runner start\n",
+ registerInstructions:
+ 'sudo gitlab-runner register --url http://192.168.1.81:3000/ --registration-token GE5gsjeep_HAtBf9s3Yz',
+ __typename: 'RunnerSetup',
+ },
+ },
+};
diff --git a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js
new file mode 100644
index 00000000000..6e2ba603e04
--- /dev/null
+++ b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js
@@ -0,0 +1,113 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import RunnerInstructions from '~/vue_shared/components/runner_instructions/runner_instructions.vue';
+import getRunnerPlatforms from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_platforms.query.graphql';
+import getRunnerSetupInstructions from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_setup.query.graphql';
+
+import { mockGraphqlRunnerPlatforms, mockGraphqlInstructions } from './mock_data';
+
+const projectPath = 'gitlab-org/gitlab';
+const localVue = createLocalVue();
+localVue.use(VueApollo);
+
+describe('RunnerInstructions component', () => {
+ let wrapper;
+ let fakeApollo;
+
+ const findModalButton = () => wrapper.find('[data-testid="show-modal-button"]');
+ const findPlatformButtons = () => wrapper.findAll('[data-testid="platform-button"]');
+ const findArchitectureDropdownItems = () =>
+ wrapper.findAll('[data-testid="architecture-dropdown-item"]');
+ const findBinaryInstructionsSection = () => wrapper.find('[data-testid="binary-instructions"]');
+ const findRunnerInstructionsSection = () => wrapper.find('[data-testid="runner-instructions"]');
+
+ beforeEach(async () => {
+ const requestHandlers = [
+ [getRunnerPlatforms, jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms)],
+ [getRunnerSetupInstructions, jest.fn().mockResolvedValue(mockGraphqlInstructions)],
+ ];
+
+ fakeApollo = createMockApollo(requestHandlers);
+
+ wrapper = shallowMount(RunnerInstructions, {
+ provide: {
+ projectPath,
+ },
+ localVue,
+ apolloProvider: fakeApollo,
+ });
+
+ await wrapper.vm.$nextTick();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('should show the "Show Runner installation instructions" button', () => {
+ const button = findModalButton();
+
+ expect(button.exists()).toBe(true);
+ expect(button.text()).toBe('Show Runner installation instructions');
+ });
+
+ it('should contain a number of platforms buttons', () => {
+ const buttons = findPlatformButtons();
+
+ expect(buttons).toHaveLength(mockGraphqlRunnerPlatforms.data.runnerPlatforms.nodes.length);
+ });
+
+ it('should contain a number of dropdown items for the architecture options', () => {
+ const platformButton = findPlatformButtons().at(0);
+ platformButton.vm.$emit('click');
+
+ return wrapper.vm.$nextTick(() => {
+ const dropdownItems = findArchitectureDropdownItems();
+
+ expect(dropdownItems).toHaveLength(
+ mockGraphqlRunnerPlatforms.data.runnerPlatforms.nodes[0].architectures.nodes.length,
+ );
+ });
+ });
+
+ it('should display the binary installation instructions for a selected architecture', async () => {
+ const platformButton = findPlatformButtons().at(0);
+ platformButton.vm.$emit('click');
+
+ await wrapper.vm.$nextTick();
+
+ const dropdownItem = findArchitectureDropdownItems().at(0);
+ dropdownItem.vm.$emit('click');
+
+ await wrapper.vm.$nextTick();
+
+ const runner = findBinaryInstructionsSection();
+
+ expect(runner.text()).toMatch('sudo chmod +x /usr/local/bin/gitlab-runner');
+ expect(runner.text()).toMatch(
+ `sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash`,
+ );
+ expect(runner.text()).toMatch(
+ 'sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner',
+ );
+ expect(runner.text()).toMatch('sudo gitlab-runner start');
+ });
+
+ it('should display the runner register instructions for a selected architecture', async () => {
+ const platformButton = findPlatformButtons().at(0);
+ platformButton.vm.$emit('click');
+
+ await wrapper.vm.$nextTick();
+
+ const dropdownItem = findArchitectureDropdownItems().at(0);
+ dropdownItem.vm.$emit('click');
+
+ await wrapper.vm.$nextTick();
+
+ const runner = findRunnerInstructionsSection();
+
+ expect(runner.text()).toMatch(mockGraphqlInstructions.data.runnerSetup.registerInstructions);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap b/spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap
new file mode 100644
index 00000000000..51b8aa162bc
--- /dev/null
+++ b/spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap
@@ -0,0 +1,43 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Settings Block renders the correct markup 1`] = `
+<section
+ class="settings no-animate"
+>
+ <div
+ class="settings-header"
+ >
+ <h4>
+ <div
+ data-testid="title-slot"
+ />
+ </h4>
+
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
+ icon=""
+ size="medium"
+ variant="default"
+ >
+
+ Expand
+
+ </gl-button-stub>
+
+ <p>
+ <div
+ data-testid="description-slot"
+ />
+ </p>
+ </div>
+
+ <div
+ class="settings-content"
+ >
+ <div
+ data-testid="default-slot"
+ />
+ </div>
+</section>
+`;
diff --git a/spec/frontend/vue_shared/components/settings/settings_block_spec.js b/spec/frontend/vue_shared/components/settings/settings_block_spec.js
new file mode 100644
index 00000000000..b550c4cfcc3
--- /dev/null
+++ b/spec/frontend/vue_shared/components/settings/settings_block_spec.js
@@ -0,0 +1,86 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
+import component from '~/vue_shared/components/settings/settings_block.vue';
+
+describe('Settings Block', () => {
+ let wrapper;
+
+ const mountComponent = (propsData) => {
+ wrapper = shallowMount(component, {
+ propsData,
+ slots: {
+ title: '<div data-testid="title-slot"></div>',
+ description: '<div data-testid="description-slot"></div>',
+ default: '<div data-testid="default-slot"></div>',
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findDefaultSlot = () => wrapper.find('[data-testid="default-slot"]');
+ const findTitleSlot = () => wrapper.find('[data-testid="title-slot"]');
+ const findDescriptionSlot = () => wrapper.find('[data-testid="description-slot"]');
+ const findExpandButton = () => wrapper.find(GlButton);
+
+ it('renders the correct markup', () => {
+ mountComponent();
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('has a default slot', () => {
+ mountComponent();
+
+ expect(findDefaultSlot().exists()).toBe(true);
+ });
+
+ it('has a title slot', () => {
+ mountComponent();
+
+ expect(findTitleSlot().exists()).toBe(true);
+ });
+
+ it('has a description slot', () => {
+ mountComponent();
+
+ expect(findDescriptionSlot().exists()).toBe(true);
+ });
+
+ describe('expanded behaviour', () => {
+ it('is collapsed by default', () => {
+ mountComponent();
+
+ expect(wrapper.classes('expanded')).toBe(false);
+ });
+
+ it('adds expanded class when the expand button is clicked', async () => {
+ mountComponent();
+
+ expect(wrapper.classes('expanded')).toBe(false);
+ expect(findExpandButton().text()).toBe('Expand');
+
+ await findExpandButton().vm.$emit('click');
+
+ expect(wrapper.classes('expanded')).toBe(true);
+ expect(findExpandButton().text()).toBe('Collapse');
+ });
+
+ it('is expanded when `defaultExpanded` is true no matter what', async () => {
+ mountComponent({ defaultExpanded: true });
+
+ expect(wrapper.classes('expanded')).toBe(true);
+
+ await findExpandButton().vm.$emit('click');
+
+ expect(wrapper.classes('expanded')).toBe(true);
+
+ await findExpandButton().vm.$emit('click');
+
+ expect(wrapper.classes('expanded')).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/todo_button_spec.js b/spec/frontend/vue_shared/components/todo_button_spec.js
index 1f8a214d632..2066c3bd671 100644
--- a/spec/frontend/vue_shared/components/todo_button_spec.js
+++ b/spec/frontend/vue_shared/components/todo_button_spec.js
@@ -33,7 +33,7 @@ describe('Todo Button', () => {
it.each`
label | isTodo
${'Mark as done'} | ${true}
- ${'Add a To Do'} | ${false}
+ ${'Add a to do'} | ${false}
`('sets correct label when isTodo is $isTodo', ({ label, isTodo }) => {
createComponent({ isTodo });
diff --git a/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js b/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
index d151cd15bc4..3eae707daf8 100644
--- a/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
+++ b/spec/frontend/vue_shared/components/user_avatar/user_avatar_link_spec.js
@@ -1,7 +1,7 @@
import { each } from 'lodash';
-import { trimText } from 'helpers/text_helper';
import { shallowMount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
+import { trimText } from 'helpers/text_helper';
import { TEST_HOST } from 'spec/test_constants';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';