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>2021-03-16 21:18:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-16 21:18:33 +0300
commitf64a639bcfa1fc2bc89ca7db268f594306edfd7c (patch)
treea2c3c2ebcc3b45e596949db485d6ed18ffaacfa1 /spec/frontend/vue_shared/components
parentbfbc3e0d6583ea1a91f627528bedc3d65ba4b10f (diff)
Add latest changes from gitlab-org/gitlab@13-10-stable-eev13.10.0-rc40
Diffstat (limited to 'spec/frontend/vue_shared/components')
-rw-r--r--spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/multiselect_dropdown_spec.js4
-rw-r--r--spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap90
-rw-r--r--spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js122
-rw-r--r--spec/frontend/vue_shared/components/settings/__snapshots__/settings_block_spec.js.snap2
-rw-r--r--spec/frontend/vue_shared/components/settings/settings_block_spec.js21
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js44
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js1
-rw-r--r--spec/frontend/vue_shared/components/tabs/tab_spec.js32
-rw-r--r--spec/frontend/vue_shared/components/tabs/tabs_spec.js61
-rw-r--r--spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js11
-rw-r--r--spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap67
-rw-r--r--spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js34
-rw-r--r--spec/frontend/vue_shared/components/user_access_role_badge_spec.js26
-rw-r--r--spec/frontend/vue_shared/components/user_popover/user_popover_spec.js25
16 files changed, 355 insertions, 192 deletions
diff --git a/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js b/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js
index f34a2db0851..99bf0d84d0c 100644
--- a/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js
+++ b/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js
@@ -88,7 +88,7 @@ describe('RelatedIssuableItem', () => {
const stateTitle = tokenState().attributes('title');
const formattedCreateDate = formatDate(props.createdAt);
- expect(stateTitle).toContain('<span class="bold">Opened</span>');
+ expect(stateTitle).toContain('<span class="bold">Created</span>');
expect(stateTitle).toContain(`<span class="text-tertiary">${formattedCreateDate}</span>`);
});
diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
index bf65adc866d..5364e2d5f52 100644
--- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
@@ -1,5 +1,6 @@
import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import ApplySuggestion from '~/vue_shared/components/markdown/apply_suggestion.vue';
import SuggestionDiffHeader from '~/vue_shared/components/markdown/suggestion_diff_header.vue';
const DEFAULT_PROPS = {
@@ -38,7 +39,7 @@ describe('Suggestion Diff component', () => {
wrapper.destroy();
});
- const findApplyButton = () => wrapper.find('.js-apply-btn');
+ const findApplyButton = () => wrapper.find(ApplySuggestion);
const findApplyBatchButton = () => wrapper.find('.js-apply-batch-btn');
const findAddToBatchButton = () => wrapper.find('.js-add-to-batch-btn');
const findRemoveFromBatchButton = () => wrapper.find('.js-remove-from-batch-btn');
@@ -88,7 +89,7 @@ describe('Suggestion Diff component', () => {
beforeEach(() => {
createComponent();
- findApplyButton().vm.$emit('click');
+ findApplyButton().vm.$emit('apply');
});
it('emits apply', () => {
diff --git a/spec/frontend/vue_shared/components/multiselect_dropdown_spec.js b/spec/frontend/vue_shared/components/multiselect_dropdown_spec.js
index 99671f1ffb7..566ca1817f2 100644
--- a/spec/frontend/vue_shared/components/multiselect_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/multiselect_dropdown_spec.js
@@ -1,3 +1,4 @@
+import { GlDropdown } from '@gitlab/ui';
import { getByText } from '@testing-library/dom';
import { shallowMount } from '@vue/test-utils';
import MultiSelectDropdown from '~/vue_shared/components/sidebar/multiselect_dropdown.vue';
@@ -25,6 +26,9 @@ describe('MultiSelectDropdown Component', () => {
slots: {
search: '<p>Search</p>',
},
+ stubs: {
+ GlDropdown,
+ },
});
expect(getByText(wrapper.element, 'Search')).toBeDefined();
});
diff --git a/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap b/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
index da49778f216..30b7f0c2d28 100644
--- a/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
+++ b/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
@@ -2,20 +2,26 @@
exports[`Package code instruction multiline to match the snapshot 1`] = `
<div>
- <pre
- class="gl-font-monospace"
- data-testid="multiline-instruction"
+ <label
+ for="instruction-input_3"
>
- this is some
+ foo_label
+ </label>
+
+ <div>
+ <pre
+ class="gl-font-monospace"
+ data-testid="multiline-instruction"
+ >
+ this is some
multiline text
- </pre>
+ </pre>
+ </div>
</div>
`;
exports[`Package code instruction single line to match the default snapshot 1`] = `
-<div
- class="gl-mb-3"
->
+<div>
<label
for="instruction-input_2"
>
@@ -23,42 +29,46 @@ exports[`Package code instruction single line to match the default snapshot 1`]
</label>
<div
- class="input-group gl-mb-3"
+ class="gl-mb-3"
>
- <input
- class="form-control gl-font-monospace"
- data-testid="instruction-input"
- id="instruction-input_2"
- readonly="readonly"
- type="text"
- />
-
- <span
- class="input-group-append"
- data-testid="instruction-button"
+ <div
+ class="input-group gl-mb-3"
>
- <button
- aria-label="Copy this value"
- class="btn input-group-text btn-default btn-md gl-button btn-default-secondary btn-icon"
- data-clipboard-text="npm i @my-package"
- title="Copy npm install command"
- type="button"
+ <input
+ class="form-control gl-font-monospace"
+ data-testid="instruction-input"
+ id="instruction-input_2"
+ readonly="readonly"
+ type="text"
+ />
+
+ <span
+ class="input-group-append"
+ data-testid="instruction-button"
>
- <!---->
-
- <svg
- aria-hidden="true"
- class="gl-button-icon gl-icon s16"
- data-testid="copy-to-clipboard-icon"
+ <button
+ aria-label="Copy this value"
+ class="btn input-group-text btn-default btn-md gl-button btn-default-secondary btn-icon"
+ data-clipboard-text="npm i @my-package"
+ title="Copy npm install command"
+ type="button"
>
- <use
- href="#copy-to-clipboard"
- />
- </svg>
-
- <!---->
- </button>
- </span>
+ <!---->
+
+ <svg
+ aria-hidden="true"
+ class="gl-button-icon gl-icon s16"
+ data-testid="copy-to-clipboard-icon"
+ >
+ <use
+ href="#copy-to-clipboard"
+ />
+ </svg>
+
+ <!---->
+ </button>
+ </span>
+ </div>
</div>
</div>
`;
diff --git a/spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js b/spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js
new file mode 100644
index 00000000000..c65ded000d3
--- /dev/null
+++ b/spec/frontend/vue_shared/components/registry/persisted_dropdown_selection_spec.js
@@ -0,0 +1,122 @@
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
+import component from '~/vue_shared/components/registry/persisted_dropdown_selection.vue';
+
+describe('Persisted dropdown selection', () => {
+ let wrapper;
+
+ const defaultProps = {
+ storageKey: 'foo_bar',
+ options: [
+ { value: 'maven', label: 'Maven' },
+ { value: 'gradle', label: 'Gradle' },
+ ],
+ };
+
+ function createComponent({ props = {}, data = {} } = {}) {
+ wrapper = shallowMount(component, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ data() {
+ return data;
+ },
+ });
+ }
+
+ const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('local storage sync', () => {
+ it('uses the local storage sync component', () => {
+ createComponent();
+
+ expect(findLocalStorageSync().exists()).toBe(true);
+ });
+
+ it('passes the right props', () => {
+ createComponent({ data: { selected: 'foo' } });
+
+ expect(findLocalStorageSync().props()).toMatchObject({
+ storageKey: defaultProps.storageKey,
+ value: 'foo',
+ });
+ });
+
+ it('on input event updates the model and emits event', async () => {
+ const inputPayload = 'bar';
+ createComponent();
+ findLocalStorageSync().vm.$emit('input', inputPayload);
+
+ await nextTick();
+
+ expect(wrapper.emitted('change')).toStrictEqual([[inputPayload]]);
+ expect(findLocalStorageSync().props('value')).toBe(inputPayload);
+ });
+ });
+
+ describe('dropdown', () => {
+ it('has a dropdown component', () => {
+ createComponent();
+
+ expect(findDropdown().exists()).toBe(true);
+ });
+
+ describe('dropdown text', () => {
+ it('when no selection shows the first', () => {
+ createComponent();
+
+ expect(findDropdown().props('text')).toBe('Maven');
+ });
+
+ it('when an option is selected, shows that option label', () => {
+ createComponent({ data: { selected: defaultProps.options[1].value } });
+
+ expect(findDropdown().props('text')).toBe('Gradle');
+ });
+ });
+
+ describe('dropdown items', () => {
+ it('has one item for each option', () => {
+ createComponent();
+
+ expect(findDropdownItems()).toHaveLength(defaultProps.options.length);
+ });
+
+ it('binds the correct props', () => {
+ createComponent({ data: { selected: defaultProps.options[0].value } });
+
+ expect(findDropdownItems().at(0).props()).toMatchObject({
+ isChecked: true,
+ isCheckItem: true,
+ });
+
+ expect(findDropdownItems().at(1).props()).toMatchObject({
+ isChecked: false,
+ isCheckItem: true,
+ });
+ });
+
+ it('on click updates the data and emits event', async () => {
+ createComponent({ data: { selected: defaultProps.options[0].value } });
+ expect(findDropdownItems().at(0).props('isChecked')).toBe(true);
+
+ findDropdownItems().at(1).vm.$emit('click');
+
+ await nextTick();
+
+ expect(wrapper.emitted('change')).toStrictEqual([['gradle']]);
+ expect(findDropdownItems().at(0).props('isChecked')).toBe(false);
+ expect(findDropdownItems().at(1).props('isChecked')).toBe(true);
+ });
+ });
+ });
+});
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
index 51b8aa162bc..ed085fb66dc 100644
--- 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
@@ -2,7 +2,7 @@
exports[`Settings Block renders the correct markup 1`] = `
<section
- class="settings no-animate"
+ class="settings"
>
<div
class="settings-header"
diff --git a/spec/frontend/vue_shared/components/settings/settings_block_spec.js b/spec/frontend/vue_shared/components/settings/settings_block_spec.js
index 2db0b001b5b..be5a15631eb 100644
--- a/spec/frontend/vue_shared/components/settings/settings_block_spec.js
+++ b/spec/frontend/vue_shared/components/settings/settings_block_spec.js
@@ -50,6 +50,27 @@ describe('Settings Block', () => {
expect(findDescriptionSlot().exists()).toBe(true);
});
+ describe('slide animation behaviour', () => {
+ it('is animated by default', () => {
+ mountComponent();
+
+ expect(wrapper.classes('no-animate')).toBe(false);
+ });
+
+ it.each`
+ slideAnimated | noAnimatedClass
+ ${true} | ${false}
+ ${false} | ${true}
+ `(
+ 'sets the correct state when slideAnimated is $slideAnimated',
+ ({ slideAnimated, noAnimatedClass }) => {
+ mountComponent({ slideAnimated });
+
+ expect(wrapper.classes('no-animate')).toBe(noAnimatedClass);
+ },
+ );
+ });
+
describe('expanded behaviour', () => {
it('is collapsed by default', () => {
mountComponent();
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js
index 0d1d6ebcfe5..c90e63313b2 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_value_spec.js
@@ -11,32 +11,31 @@ import { mockConfig, mockRegularLabel, mockScopedLabel } from './mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
-const createComponent = (initialState = mockConfig, slots = {}) => {
- const store = new Vuex.Store(labelsSelectModule());
-
- store.dispatch('setInitialState', initialState);
-
- return shallowMount(DropdownValue, {
- localVue,
- store,
- slots,
- });
-};
-
describe('DropdownValue', () => {
let wrapper;
- beforeEach(() => {
- wrapper = createComponent();
- });
+ const createComponent = (initialState = {}, slots = {}) => {
+ const store = new Vuex.Store(labelsSelectModule());
+
+ store.dispatch('setInitialState', { ...mockConfig, ...initialState });
+
+ wrapper = shallowMount(DropdownValue, {
+ localVue,
+ store,
+ slots,
+ });
+ };
afterEach(() => {
wrapper.destroy();
+ wrapper = null;
});
describe('methods', () => {
describe('labelFilterUrl', () => {
it('returns a label filter URL based on provided label param', () => {
+ createComponent();
+
expect(wrapper.vm.labelFilterUrl(mockRegularLabel)).toBe(
'/gitlab-org/my-project/issues?label_name[]=Foo%20Label',
);
@@ -44,6 +43,10 @@ describe('DropdownValue', () => {
});
describe('scopedLabel', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
it('returns `true` when provided label param is a scoped label', () => {
expect(wrapper.vm.scopedLabel(mockScopedLabel)).toBe(true);
});
@@ -56,28 +59,29 @@ describe('DropdownValue', () => {
describe('template', () => {
it('renders class `has-labels` on component container element when `selectedLabels` is not empty', () => {
+ createComponent();
+
expect(wrapper.attributes('class')).toContain('has-labels');
});
it('renders element containing `None` when `selectedLabels` is empty', () => {
- const wrapperNoLabels = createComponent(
+ createComponent(
{
- ...mockConfig,
selectedLabels: [],
},
{
default: 'None',
},
);
- const noneEl = wrapperNoLabels.find('span.text-secondary');
+ const noneEl = wrapper.find('span.text-secondary');
expect(noneEl.exists()).toBe(true);
expect(noneEl.text()).toBe('None');
-
- wrapperNoLabels.destroy();
});
it('renders labels when `selectedLabels` is not empty', () => {
+ createComponent();
+
expect(wrapper.findAll(GlLabel).length).toBe(2);
});
});
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
index 85a14226585..f293b8422e7 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
@@ -47,6 +47,7 @@ export const mockConfig = {
labelsFetchPath: '/gitlab-org/my-project/-/labels.json',
labelsManagePath: '/gitlab-org/my-project/-/labels',
labelsFilterBasePath: '/gitlab-org/my-project/issues',
+ labelsFilterParam: 'label_name',
};
export const mockSuggestedColors = {
diff --git a/spec/frontend/vue_shared/components/tabs/tab_spec.js b/spec/frontend/vue_shared/components/tabs/tab_spec.js
deleted file mode 100644
index ee0c983c764..00000000000
--- a/spec/frontend/vue_shared/components/tabs/tab_spec.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import Vue from 'vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
-import Tab from '~/vue_shared/components/tabs/tab.vue';
-
-describe('Tab component', () => {
- const Component = Vue.extend(Tab);
- let vm;
-
- beforeEach(() => {
- vm = mountComponent(Component);
- });
-
- it('sets localActive to equal active', (done) => {
- vm.active = true;
-
- vm.$nextTick(() => {
- expect(vm.localActive).toBe(true);
-
- done();
- });
- });
-
- it('sets active class', (done) => {
- vm.active = true;
-
- vm.$nextTick(() => {
- expect(vm.$el.classList).toContain('active');
-
- done();
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/tabs/tabs_spec.js b/spec/frontend/vue_shared/components/tabs/tabs_spec.js
deleted file mode 100644
index fe7be5be899..00000000000
--- a/spec/frontend/vue_shared/components/tabs/tabs_spec.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import Vue from 'vue';
-import Tab from '~/vue_shared/components/tabs/tab.vue';
-import Tabs from '~/vue_shared/components/tabs/tabs';
-
-describe('Tabs component', () => {
- let vm;
-
- beforeEach(() => {
- vm = new Vue({
- components: {
- Tabs,
- Tab,
- },
- render(h) {
- return h('div', [
- h('tabs', [
- h('tab', { attrs: { title: 'Testing', active: true } }, 'First tab'),
- h('tab', [h('template', { slot: 'title' }, 'Test slot'), 'Second tab']),
- ]),
- ]);
- },
- }).$mount();
-
- return vm.$nextTick();
- });
-
- describe('tab links', () => {
- it('renders links for tabs', () => {
- expect(vm.$el.querySelectorAll('a').length).toBe(2);
- });
-
- it('renders link titles from props', () => {
- expect(vm.$el.querySelector('a').textContent).toContain('Testing');
- });
-
- it('renders link titles from slot', () => {
- expect(vm.$el.querySelectorAll('a')[1].textContent).toContain('Test slot');
- });
-
- it('renders active class', () => {
- expect(vm.$el.querySelector('a').classList).toContain('active');
- });
-
- it('updates active class on click', () => {
- vm.$el.querySelectorAll('a')[1].click();
-
- return vm.$nextTick(() => {
- expect(vm.$el.querySelector('a').classList).not.toContain('active');
- expect(vm.$el.querySelectorAll('a')[1].classList).toContain('active');
- });
- });
- });
-
- describe('content', () => {
- it('renders content panes', () => {
- expect(vm.$el.querySelectorAll('.tab-pane').length).toBe(2);
- expect(vm.$el.querySelectorAll('.tab-pane')[0].textContent).toContain('First tab');
- expect(vm.$el.querySelectorAll('.tab-pane')[1].textContent).toContain('Second tab');
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js b/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
index 27c9b099306..380b7231acd 100644
--- a/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
+++ b/spec/frontend/vue_shared/components/tooltip_on_truncate_spec.js
@@ -11,6 +11,15 @@ jest.mock('~/lib/utils/dom_utils', () => ({
throw new Error('this needs to be mocked');
}),
}));
+jest.mock('@gitlab/ui', () => ({
+ GlTooltipDirective: {
+ bind(el, binding) {
+ el.classList.add('gl-tooltip');
+ el.setAttribute('data-original-title', el.title);
+ el.dataset.placement = binding.value.placement;
+ },
+ },
+}));
describe('TooltipOnTruncate component', () => {
let wrapper;
@@ -52,7 +61,7 @@ describe('TooltipOnTruncate component', () => {
wrapper = parent.find(TooltipOnTruncate);
};
- const hasTooltip = () => wrapper.classes('js-show-tooltip');
+ const hasTooltip = () => wrapper.classes('gl-tooltip');
afterEach(() => {
wrapper.destroy();
diff --git a/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap b/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
index d2fe3cd76cb..af4fa462cbf 100644
--- a/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
+++ b/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
@@ -19,6 +19,7 @@ exports[`Upload dropzone component correctly overrides description and drop mess
<p
class="gl-mb-0"
+ data-testid="upload-text"
>
<span>
Test %{linkStart}description%{linkEnd} message.
@@ -98,10 +99,15 @@ exports[`Upload dropzone component when dragging renders correct template when d
<p
class="gl-mb-0"
+ data-testid="upload-text"
>
- <gl-sprintf-stub
- message="Drop or %{linkStart}upload%{linkEnd} files to attach"
- />
+ Drop or
+ <gl-link-stub>
+
+ upload
+
+ </gl-link-stub>
+ files to attach
</p>
</div>
</button>
@@ -178,10 +184,15 @@ exports[`Upload dropzone component when dragging renders correct template when d
<p
class="gl-mb-0"
+ data-testid="upload-text"
>
- <gl-sprintf-stub
- message="Drop or %{linkStart}upload%{linkEnd} files to attach"
- />
+ Drop or
+ <gl-link-stub>
+
+ upload
+
+ </gl-link-stub>
+ files to attach
</p>
</div>
</button>
@@ -258,10 +269,15 @@ exports[`Upload dropzone component when dragging renders correct template when d
<p
class="gl-mb-0"
+ data-testid="upload-text"
>
- <gl-sprintf-stub
- message="Drop or %{linkStart}upload%{linkEnd} files to attach"
- />
+ Drop or
+ <gl-link-stub>
+
+ upload
+
+ </gl-link-stub>
+ files to attach
</p>
</div>
</button>
@@ -337,10 +353,15 @@ exports[`Upload dropzone component when dragging renders correct template when d
<p
class="gl-mb-0"
+ data-testid="upload-text"
>
- <gl-sprintf-stub
- message="Drop or %{linkStart}upload%{linkEnd} files to attach"
- />
+ Drop or
+ <gl-link-stub>
+
+ upload
+
+ </gl-link-stub>
+ files to attach
</p>
</div>
</button>
@@ -416,10 +437,15 @@ exports[`Upload dropzone component when dragging renders correct template when d
<p
class="gl-mb-0"
+ data-testid="upload-text"
>
- <gl-sprintf-stub
- message="Drop or %{linkStart}upload%{linkEnd} files to attach"
- />
+ Drop or
+ <gl-link-stub>
+
+ upload
+
+ </gl-link-stub>
+ files to attach
</p>
</div>
</button>
@@ -495,10 +521,15 @@ exports[`Upload dropzone component when no slot provided renders default dropzon
<p
class="gl-mb-0"
+ data-testid="upload-text"
>
- <gl-sprintf-stub
- message="Drop or %{linkStart}upload%{linkEnd} files to attach"
- />
+ Drop or
+ <gl-link-stub>
+
+ upload
+
+ </gl-link-stub>
+ files to attach
</p>
</div>
</button>
diff --git a/spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js b/spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js
index ace486b1f32..b3cdbccb271 100644
--- a/spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js
+++ b/spec/frontend/vue_shared/components/upload_dropzone/upload_dropzone_spec.js
@@ -1,4 +1,4 @@
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
@@ -14,6 +14,7 @@ describe('Upload dropzone component', () => {
const findDropzoneCard = () => wrapper.find('.upload-dropzone-card');
const findDropzoneArea = () => wrapper.find('[data-testid="dropzone-area"]');
const findIcon = () => wrapper.find(GlIcon);
+ const findUploadText = () => wrapper.find('[data-testid="upload-text"]').text();
function createComponent({ slots = {}, data = {}, props = {} } = {}) {
wrapper = shallowMount(UploadDropzone, {
@@ -22,6 +23,9 @@ describe('Upload dropzone component', () => {
displayAsCard: true,
...props,
},
+ stubs: {
+ GlSprintf,
+ },
data() {
return data;
},
@@ -30,6 +34,7 @@ describe('Upload dropzone component', () => {
afterEach(() => {
wrapper.destroy();
+ wrapper = null;
});
describe('when slot provided', () => {
@@ -60,6 +65,18 @@ describe('Upload dropzone component', () => {
});
});
+ describe('upload text', () => {
+ it.each`
+ collection | description | props | expected
+ ${'multiple'} | ${'by default'} | ${null} | ${'files to attach'}
+ ${'singular'} | ${'when singleFileSelection'} | ${{ singleFileSelection: true }} | ${'file to attach'}
+ `('displays $collection version $description', ({ props, expected }) => {
+ createComponent({ props });
+
+ expect(findUploadText()).toContain(expected);
+ });
+ });
+
describe('when dragging', () => {
it.each`
description | eventPayload
@@ -141,6 +158,21 @@ describe('Upload dropzone component', () => {
wrapper.vm.ondrop(mockEvent);
expect(wrapper.emitted()).not.toHaveProperty('error');
});
+
+ describe('singleFileSelection = true', () => {
+ it('emits a single file on drop', () => {
+ createComponent({
+ data: mockData,
+ props: { singleFileSelection: true },
+ });
+
+ const mockFile = { type: 'image/jpg' };
+ const mockEvent = mockDragEvent({ files: [mockFile] });
+
+ wrapper.vm.ondrop(mockEvent);
+ expect(wrapper.emitted().change[0]).toEqual([mockFile]);
+ });
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/user_access_role_badge_spec.js b/spec/frontend/vue_shared/components/user_access_role_badge_spec.js
new file mode 100644
index 00000000000..7f25f7c08e7
--- /dev/null
+++ b/spec/frontend/vue_shared/components/user_access_role_badge_spec.js
@@ -0,0 +1,26 @@
+import { GlBadge } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
+
+describe('UserAccessRoleBadge', () => {
+ let wrapper;
+
+ const createComponent = ({ slots } = {}) => {
+ wrapper = shallowMount(UserAccessRoleBadge, {
+ slots,
+ });
+ };
+
+ it('renders slot content inside GlBadge', () => {
+ createComponent({
+ slots: {
+ default: 'test slot content',
+ },
+ });
+
+ const badge = wrapper.find(GlBadge);
+
+ expect(badge.exists()).toBe(true);
+ expect(badge.html()).toContain('test slot content');
+ });
+});
diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
index a6c5e23ae14..184a1e458b5 100644
--- a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
+++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
@@ -9,6 +9,7 @@ const DEFAULT_PROPS = {
username: 'root',
name: 'Administrator',
location: 'Vienna',
+ bot: false,
bio: null,
workInformation: null,
status: null,
@@ -18,14 +19,10 @@ const DEFAULT_PROPS = {
describe('User Popover Component', () => {
const fixtureTemplate = 'merge_requests/diff_comment.html';
- preloadFixtures(fixtureTemplate);
let wrapper;
beforeEach(() => {
- window.gon.features = {
- securityAutoFix: true,
- };
loadFixtures(fixtureTemplate);
});
@@ -37,6 +34,7 @@ describe('User Popover Component', () => {
const findUserStatus = () => wrapper.find('.js-user-status');
const findTarget = () => document.querySelector('.js-user-link');
const findUserName = () => wrapper.find(UserNameWithStatus);
+ const findSecurityBotDocsLink = () => findByTestId('user-popover-bot-docs-link');
const createWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(UserPopover, {
@@ -86,6 +84,12 @@ describe('User Popover Component', () => {
expect(iconEl.props('name')).toEqual('location');
});
+
+ it("should not show a link to bot's documentation", () => {
+ createWrapper();
+ const securityBotDocsLink = findSecurityBotDocsLink();
+ expect(securityBotDocsLink.exists()).toBe(false);
+ });
});
describe('job data', () => {
@@ -230,14 +234,14 @@ describe('User Popover Component', () => {
});
});
- describe('security bot', () => {
+ describe('bot user', () => {
const SECURITY_BOT_USER = {
...DEFAULT_PROPS.user,
name: 'GitLab Security Bot',
username: 'GitLab-Security-Bot',
websiteUrl: '/security/bot/docs',
+ bot: true,
};
- const findSecurityBotDocsLink = () => findByTestId('user-popover-bot-docs-link');
it("shows a link to the bot's documentation", () => {
createWrapper({ user: SECURITY_BOT_USER });
@@ -245,14 +249,5 @@ describe('User Popover Component', () => {
expect(securityBotDocsLink.exists()).toBe(true);
expect(securityBotDocsLink.attributes('href')).toBe(SECURITY_BOT_USER.websiteUrl);
});
-
- it('does not show the link if the feature flag is disabled', () => {
- window.gon.features = {
- securityAutoFix: false,
- };
- createWrapper({ user: SECURITY_BOT_USER });
-
- expect(findSecurityBotDocsLink().exists()).toBe(false);
- });
});
});