Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
b2ee478d3e
commit
9cc33a92d0
|
|
@ -1,5 +1,11 @@
|
|||
<script>
|
||||
import { GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import {
|
||||
GlDropdown,
|
||||
GlSearchBoxByType,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
GlLoadingIcon,
|
||||
} from '@gitlab/ui';
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import {
|
||||
I18N_NO_RESULTS_MESSAGE,
|
||||
|
|
@ -10,7 +16,11 @@ import {
|
|||
export default {
|
||||
name: 'BranchesDropdown',
|
||||
components: {
|
||||
GlCollapsibleListbox,
|
||||
GlDropdown,
|
||||
GlSearchBoxByType,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
|
|
@ -36,16 +46,13 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapGetters(['joinedBranches']),
|
||||
...mapState(['isFetching']),
|
||||
...mapState(['isFetching', 'branch', 'branches']),
|
||||
filteredResults() {
|
||||
const lowerCasedSearchTerm = this.searchTerm.toLowerCase();
|
||||
return this.joinedBranches.filter((resultString) =>
|
||||
resultString.toLowerCase().includes(lowerCasedSearchTerm),
|
||||
);
|
||||
},
|
||||
listboxItems() {
|
||||
return this.filteredResults.map((value) => ({ value, text: value }));
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// Parent component can set the branch value (e.g. when the user selects a different project)
|
||||
|
|
@ -61,6 +68,10 @@ export default {
|
|||
...mapActions(['fetchBranches']),
|
||||
selectBranch(branch) {
|
||||
this.$emit('selectBranch', branch);
|
||||
this.searchTerm = branch; // enables isSelected to work as expected
|
||||
},
|
||||
isSelected(selectedBranch) {
|
||||
return selectedBranch === this.branch;
|
||||
},
|
||||
searchTermChanged(value) {
|
||||
this.searchTerm = value;
|
||||
|
|
@ -70,16 +81,36 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-collapsible-listbox
|
||||
:header-text="$options.i18n.branchHeaderTitle"
|
||||
:toggle-text="value"
|
||||
:items="listboxItems"
|
||||
searchable
|
||||
:search-placeholder="$options.i18n.branchSearchPlaceholder"
|
||||
:searching="isFetching"
|
||||
:selected="value"
|
||||
:no-results-text="$options.i18n.noResultsMessage"
|
||||
@search="searchTermChanged"
|
||||
@select="selectBranch"
|
||||
/>
|
||||
<gl-dropdown :text="value" :header-text="$options.i18n.branchHeaderTitle">
|
||||
<gl-search-box-by-type
|
||||
:value="searchTerm"
|
||||
trim
|
||||
autocomplete="off"
|
||||
:debounce="250"
|
||||
:placeholder="$options.i18n.branchSearchPlaceholder"
|
||||
data-testid="dropdown-search-box"
|
||||
@input="searchTermChanged"
|
||||
/>
|
||||
<gl-dropdown-item
|
||||
v-for="branch in filteredResults"
|
||||
v-show="!isFetching"
|
||||
:key="branch"
|
||||
:name="branch"
|
||||
:is-checked="isSelected(branch)"
|
||||
is-check-item
|
||||
data-testid="dropdown-item"
|
||||
@click="selectBranch(branch)"
|
||||
>
|
||||
{{ branch }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-text v-show="isFetching" data-testid="dropdown-text-loading-icon">
|
||||
<gl-loading-icon size="sm" class="gl-mx-auto" />
|
||||
</gl-dropdown-text>
|
||||
<gl-dropdown-text
|
||||
v-if="!filteredResults.length && !isFetching"
|
||||
data-testid="empty-result-message"
|
||||
>
|
||||
<span class="gl-text-gray-500">{{ $options.i18n.noResultsMessage }}</span>
|
||||
</gl-dropdown-text>
|
||||
</gl-dropdown>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,11 @@ export default {
|
|||
:value="targetProjectId"
|
||||
/>
|
||||
|
||||
<projects-dropdown :value="targetProjectName" @selectProject="setSelectedProject" />
|
||||
<projects-dropdown
|
||||
class="gl-w-half"
|
||||
:value="targetProjectName"
|
||||
@selectProject="setSelectedProject"
|
||||
/>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-group
|
||||
|
|
@ -151,7 +155,12 @@ export default {
|
|||
>
|
||||
<input id="start_branch" type="hidden" name="start_branch" :value="branch" />
|
||||
|
||||
<branches-dropdown :value="branch" :blanked="isRevert" @selectBranch="setBranch" />
|
||||
<branches-dropdown
|
||||
class="gl-w-half"
|
||||
:value="branch"
|
||||
:blanked="isRevert"
|
||||
@selectBranch="setBranch"
|
||||
/>
|
||||
</gl-form-group>
|
||||
|
||||
<gl-form-checkbox
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import { GlDropdown, GlSearchBoxByType, GlDropdownItem, GlDropdownText } from '@gitlab/ui';
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import {
|
||||
I18N_NO_RESULTS_MESSAGE,
|
||||
|
|
@ -10,7 +10,10 @@ import {
|
|||
export default {
|
||||
name: 'ProjectsDropdown',
|
||||
components: {
|
||||
GlCollapsibleListbox,
|
||||
GlDropdown,
|
||||
GlSearchBoxByType,
|
||||
GlDropdownItem,
|
||||
GlDropdownText,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
|
|
@ -38,20 +41,17 @@ export default {
|
|||
project.name.toLowerCase().includes(lowerCasedFilterTerm),
|
||||
);
|
||||
},
|
||||
listboxItems() {
|
||||
return this.filteredResults.map(({ id, name }) => ({ value: id, text: name }));
|
||||
},
|
||||
selectedProject() {
|
||||
return this.sortedProjects.find((project) => project.id === this.targetProjectId) || {};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
selectProject(value) {
|
||||
this.$emit('selectProject', value);
|
||||
|
||||
// when we select a project, we want the dropdown to filter to the selected project
|
||||
const project = this.listboxItems.find((x) => x.value === value);
|
||||
this.filterTerm = project?.text || '';
|
||||
selectProject(project) {
|
||||
this.$emit('selectProject', project.id);
|
||||
this.filterTerm = project.name; // when we select a project, we want the dropdown to filter to the selected project
|
||||
},
|
||||
isSelected(selectedProject) {
|
||||
return selectedProject === this.selectedProject;
|
||||
},
|
||||
filterTermChanged(value) {
|
||||
this.filterTerm = value;
|
||||
|
|
@ -60,15 +60,28 @@ export default {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<gl-collapsible-listbox
|
||||
:header-text="$options.i18n.projectHeaderTitle"
|
||||
:items="listboxItems"
|
||||
searchable
|
||||
:search-placeholder="$options.i18n.projectSearchPlaceholder"
|
||||
:selected="selectedProject.id"
|
||||
:toggle-text="selectedProject.name"
|
||||
:no-results-text="$options.i18n.noResultsMessage"
|
||||
@search="filterTermChanged"
|
||||
@select="selectProject"
|
||||
/>
|
||||
<gl-dropdown :text="selectedProject.name" :header-text="$options.i18n.projectHeaderTitle">
|
||||
<gl-search-box-by-type
|
||||
:value="filterTerm"
|
||||
trim
|
||||
autocomplete="off"
|
||||
:placeholder="$options.i18n.projectSearchPlaceholder"
|
||||
data-testid="dropdown-search-box"
|
||||
@input="filterTermChanged"
|
||||
/>
|
||||
<gl-dropdown-item
|
||||
v-for="project in filteredResults"
|
||||
:key="project.name"
|
||||
:name="project.name"
|
||||
:is-checked="isSelected(project)"
|
||||
is-check-item
|
||||
data-testid="dropdown-item"
|
||||
@click="selectProject(project)"
|
||||
>
|
||||
{{ project.name }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-text v-if="!filteredResults.length" data-testid="empty-result-message">
|
||||
<span class="gl-text-gray-500">{{ $options.i18n.noResultsMessage }}</span>
|
||||
</gl-dropdown-text>
|
||||
</gl-dropdown>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -122,9 +122,9 @@ for details.
|
|||
- [Viewing projects and designs data from a primary site is not possible when using a unified URL](../index.md#view-replication-data-on-the-primary-site).
|
||||
|
||||
- When secondary proxying is used together with separate URLs, registering [GitLab runners](https://docs.gitlab.com/runner/) to clone from
|
||||
secondary sites is not supported. The runner registration will succeed, but the clone URL will default to the primary site. The runner
|
||||
secondary sites is not supported. The runner registration succeeds, but the clone URL defaults to the primary site. The runner
|
||||
[clone URL](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) is configured per GitLab deployment
|
||||
and cannot be configured per Geo site. Therefore, all runners will clone from the primary site (or configured clone URL) irrespective of
|
||||
and cannot be configured per Geo site. Therefore, all runners clone from the primary site (or configured clone URL) irrespective of
|
||||
which Geo site they register on. For information about GitLab CI using a specific Geo secondary to clone from, see issue
|
||||
[3294](https://gitlab.com/gitlab-org/gitlab/-/issues/3294#note_1009488466).
|
||||
|
||||
|
|
@ -147,7 +147,7 @@ secondary Geo sites are able to support write requests. Certain **read** request
|
|||
sites for improved latency and bandwidth nearby. All write requests are proxied to the primary site.
|
||||
|
||||
The following table details the components currently tested through the Geo secondary site Workhorse proxy.
|
||||
It does not cover all data types, more will be added in the future as they are tested.
|
||||
It does not cover all data types.
|
||||
|
||||
| Feature / component | Accelerated reads? |
|
||||
|:----------------------------------------------------|:-----------------------|
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: "To determine the technical writer assigned to the Stage/Group associated
|
|||
description: 'Learn how to install, configure, update, and maintain your GitLab instance.'
|
||||
---
|
||||
|
||||
# Administrator documentation **(FREE SELF)**
|
||||
# Administer GitLab **(FREE SELF)**
|
||||
|
||||
If you use GitLab.com, only GitLab team members have access to administration tools and settings.
|
||||
If you use a self-managed GitLab instance, learn how to administer it.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ group: Integrations
|
|||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# API Docs **(FREE)**
|
||||
# GitLab APIs **(FREE)**
|
||||
|
||||
Use the GitLab APIs to automate GitLab.
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
comments: false
|
||||
---
|
||||
|
||||
# GitLab integrations **(FREE)**
|
||||
# Integrate with GitLab **(FREE)**
|
||||
|
||||
You can integrate GitLab with external services for enhanced functionality.
|
||||
|
||||
|
|
|
|||
|
|
@ -360,13 +360,14 @@ including a large number of false positives.
|
|||
|:------------------------------------------------|:--------------|:------------------------------|
|
||||
| `DAST_ADVERTISE_SCAN` | boolean | Set to `true` to add a `Via` header to every request sent, advertising that the request was sent as part of a GitLab DAST scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334947) in GitLab 14.1. |
|
||||
| `DAST_AGGREGATE_VULNERABILITIES` | boolean | Vulnerability aggregation is set to `true` by default. To disable this feature and see each vulnerability individually set to `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254043) in GitLab 14.0. |
|
||||
| `DAST_ALLOWED_HOSTS` | Comma-separated list of strings | Hostnames included in this variable are considered in scope when crawled. By default the `DAST_WEBSITE` hostname is included in the allowed hosts list. Headers set using `DAST_REQUEST_HEADERS` are added to every request made to these hostnames. Example, `site.com,another.com`. |
|
||||
| `DAST_API_HOST_OVERRIDE` <sup>1</sup> | string | **{warning}** **[Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/383467)** in GitLab 15.7. Replaced by [DAST API scan](../dast_api/index.md#available-cicd-variables). Used to override domains defined in API specification files. Only supported when importing the API specification from a URL. Example: `example.com:8080`. |
|
||||
| `DAST_API_SPECIFICATION` <sup>1</sup> | URL or string | **{warning}** **[Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/383467)** in GitLab 15.7. Replaced by [DAST API scan](../dast_api/index.md#available-cicd-variables). The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
|
||||
| `DAST_AUTH_EXCLUDE_URLS` | URLs | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/289959)** in GitLab 14.0. Replaced by `DAST_EXCLUDE_URLS`. The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. |
|
||||
| `DAST_AUTO_UPDATE_ADDONS` | boolean | ZAP add-ons are pinned to specific versions in the DAST Docker image. Set to `true` to download the latest versions when the scan starts. Default: `false`. |
|
||||
| `DAST_DEBUG` <sup>1</sup> | boolean | Enable debug message output. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
|
||||
| `DAST_EXCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to exclude them from running during the scan. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). For example, `HTTP Parameter Override` has a rule ID of `10026`. Cannot be used when `DAST_ONLY_INCLUDE_RULES` is set. **Note:** In earlier versions of GitLab the excluded rules were executed but vulnerabilities they generated were suppressed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118641) in GitLab 12.10. |
|
||||
| `DAST_EXCLUDE_URLS` <sup>1</sup> | URLs | The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Example, `http://example.com/sign-out`. |
|
||||
| `DAST_EXCLUDE_URLS` <sup>1</sup> | URLs | The URLs to skip during the authenticated scan; comma-separated. Regular expression syntax can be used to match multiple URLs. For example, `.*` matches an arbitrary character sequence. Example, `http://example.com/sign-out`. |
|
||||
| `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | boolean | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/293595)** in GitLab 14.0. Set to `true` to require domain validation when running DAST full scans. Default: `false` |
|
||||
| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan) instead of a [ZAP Baseline Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan). Default: `false` |
|
||||
| `DAST_HTML_REPORT` | string | **{warning}** **[Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/384340)** in GitLab 15.7. The filename of the HTML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
|
||||
|
|
|
|||
|
|
@ -78,9 +78,9 @@ RSpec.describe 'Cherry-pick Commits', :js, feature_category: :source_code_manage
|
|||
end
|
||||
|
||||
page.within("#{modal_selector} .dropdown-menu") do
|
||||
fill_in 'Search branches', with: 'feature'
|
||||
find('[data-testid="dropdown-search-box"]').set('feature')
|
||||
wait_for_requests
|
||||
find('.gl-dropdown-item-text-wrapper', exact_text: 'feature').click
|
||||
click_button 'feature'
|
||||
end
|
||||
|
||||
submit_cherry_pick
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import { GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
|
||||
import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
|
@ -33,7 +34,12 @@ describe('BranchesDropdown', () => {
|
|||
}),
|
||||
);
|
||||
};
|
||||
const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
|
||||
|
||||
const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
|
||||
const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index);
|
||||
const findNoResults = () => wrapper.findByTestId('empty-result-message');
|
||||
const findLoading = () => wrapper.findByTestId('dropdown-text-loading-icon');
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
|
|
@ -49,6 +55,72 @@ describe('BranchesDropdown', () => {
|
|||
it('invokes fetchBranches', () => {
|
||||
expect(spyFetchBranches).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('with a value but visually blanked', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ value: '_main_', blanked: true }, { branch: '_main_' });
|
||||
});
|
||||
|
||||
it('renders all branches', () => {
|
||||
expect(findAllDropdownItems()).toHaveLength(3);
|
||||
expect(findDropdownItemByIndex(0).text()).toBe('_main_');
|
||||
expect(findDropdownItemByIndex(1).text()).toBe('_branch_1_');
|
||||
expect(findDropdownItemByIndex(2).text()).toBe('_branch_2_');
|
||||
});
|
||||
|
||||
it('selects the active branch', () => {
|
||||
expect(wrapper.vm.isSelected('_main_')).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Loading states', () => {
|
||||
it('shows loading icon while fetching', () => {
|
||||
createComponent({ value: '' }, { isFetching: true });
|
||||
|
||||
expect(findLoading().isVisible()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not show loading icon', () => {
|
||||
createComponent({ value: '' });
|
||||
|
||||
expect(findLoading().isVisible()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('No branches found', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ value: '_non_existent_branch_' });
|
||||
});
|
||||
|
||||
it('renders empty results message', () => {
|
||||
expect(findNoResults().text()).toBe('No matching results');
|
||||
});
|
||||
|
||||
it('shows GlSearchBoxByType with default attributes', () => {
|
||||
expect(findSearchBoxByType().exists()).toBe(true);
|
||||
expect(findSearchBoxByType().vm.$attrs).toMatchObject({
|
||||
placeholder: 'Search branches',
|
||||
debounce: DEFAULT_DEBOUNCE_AND_THROTTLE_MS,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Search term is empty', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ value: '' });
|
||||
});
|
||||
|
||||
it('renders all branches when search term is empty', () => {
|
||||
expect(findAllDropdownItems()).toHaveLength(3);
|
||||
expect(findDropdownItemByIndex(0).text()).toBe('_main_');
|
||||
expect(findDropdownItemByIndex(1).text()).toBe('_branch_1_');
|
||||
expect(findDropdownItemByIndex(2).text()).toBe('_branch_2_');
|
||||
});
|
||||
|
||||
it('should not be selected on the inactive branch', () => {
|
||||
expect(wrapper.vm.isSelected('_main_')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('When searching', () => {
|
||||
|
|
@ -59,7 +131,7 @@ describe('BranchesDropdown', () => {
|
|||
it('invokes fetchBranches', async () => {
|
||||
const spy = jest.spyOn(wrapper.vm, 'fetchBranches');
|
||||
|
||||
findDropdown().vm.$emit('search', '_anything_');
|
||||
findSearchBoxByType().vm.$emit('input', '_anything_');
|
||||
|
||||
await nextTick();
|
||||
|
||||
|
|
@ -68,13 +140,46 @@ describe('BranchesDropdown', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Branches found', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ value: '_branch_1_' }, { branch: '_branch_1_' });
|
||||
});
|
||||
|
||||
it('renders only the branch searched for', () => {
|
||||
expect(findAllDropdownItems()).toHaveLength(1);
|
||||
expect(findDropdownItemByIndex(0).text()).toBe('_branch_1_');
|
||||
});
|
||||
|
||||
it('should not display empty results message', () => {
|
||||
expect(findNoResults().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('should signify this branch is selected', () => {
|
||||
expect(wrapper.vm.isSelected('_branch_1_')).toBe(true);
|
||||
});
|
||||
|
||||
it('should signify the branch is not selected', () => {
|
||||
expect(wrapper.vm.isSelected('_not_selected_branch_')).toBe(false);
|
||||
});
|
||||
|
||||
describe('Custom events', () => {
|
||||
it('should emit selectBranch if an branch is clicked', () => {
|
||||
findDropdownItemByIndex(0).vm.$emit('click');
|
||||
|
||||
expect(wrapper.emitted('selectBranch')).toEqual([['_branch_1_']]);
|
||||
expect(wrapper.vm.searchTerm).toBe('_branch_1_');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Case insensitive for search term', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ value: '_BrAnCh_1_' });
|
||||
});
|
||||
|
||||
it('returns only the branch searched for', () => {
|
||||
expect(findDropdown().props('items')).toEqual([{ text: '_branch_1_', value: '_branch_1_' }]);
|
||||
it('renders only the branch searched for', () => {
|
||||
expect(findAllDropdownItems()).toHaveLength(1);
|
||||
expect(findDropdownItemByIndex(0).text()).toBe('_branch_1_');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlCollapsibleListbox } from '@gitlab/ui';
|
||||
import { GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
|
|
@ -35,23 +35,78 @@ describe('ProjectsDropdown', () => {
|
|||
);
|
||||
};
|
||||
|
||||
const findDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
|
||||
const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
|
||||
const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
|
||||
const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index);
|
||||
const findNoResults = () => wrapper.findByTestId('empty-result-message');
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
spyFetchProjects.mockReset();
|
||||
});
|
||||
|
||||
describe('No projects found', () => {
|
||||
beforeEach(() => {
|
||||
createComponent('_non_existent_project_');
|
||||
});
|
||||
|
||||
it('renders empty results message', () => {
|
||||
expect(findNoResults().text()).toBe('No matching results');
|
||||
});
|
||||
|
||||
it('shows GlSearchBoxByType with default attributes', () => {
|
||||
expect(findSearchBoxByType().exists()).toBe(true);
|
||||
expect(findSearchBoxByType().vm.$attrs).toMatchObject({
|
||||
placeholder: 'Search projects',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Search term is empty', () => {
|
||||
beforeEach(() => {
|
||||
createComponent('');
|
||||
});
|
||||
|
||||
it('renders all projects when search term is empty', () => {
|
||||
expect(findAllDropdownItems()).toHaveLength(3);
|
||||
expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
|
||||
expect(findDropdownItemByIndex(1).text()).toBe('_project_2_');
|
||||
expect(findDropdownItemByIndex(2).text()).toBe('_project_3_');
|
||||
});
|
||||
|
||||
it('should not be selected on the inactive project', () => {
|
||||
expect(wrapper.vm.isSelected('_project_1_')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Projects found', () => {
|
||||
beforeEach(() => {
|
||||
createComponent('_project_1_', { targetProjectId: '1' });
|
||||
});
|
||||
|
||||
it('renders only the project searched for', () => {
|
||||
expect(findAllDropdownItems()).toHaveLength(1);
|
||||
expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
|
||||
});
|
||||
|
||||
it('should not display empty results message', () => {
|
||||
expect(findNoResults().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('should signify this project is selected', () => {
|
||||
expect(findDropdownItemByIndex(0).props('isChecked')).toBe(true);
|
||||
});
|
||||
|
||||
it('should signify the project is not selected', () => {
|
||||
expect(wrapper.vm.isSelected('_not_selected_project_')).toBe(false);
|
||||
});
|
||||
|
||||
describe('Custom events', () => {
|
||||
it('should emit selectProject if a project is clicked', () => {
|
||||
findDropdown().vm.$emit('select', '1');
|
||||
findDropdownItemByIndex(0).vm.$emit('click');
|
||||
|
||||
expect(wrapper.emitted('selectProject')).toEqual([['1']]);
|
||||
expect(wrapper.vm.filterTerm).toBe('_project_1_');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -62,7 +117,8 @@ describe('ProjectsDropdown', () => {
|
|||
});
|
||||
|
||||
it('renders only the project searched for', () => {
|
||||
expect(findDropdown().props('items')).toEqual([{ text: '_project_1_', value: '1' }]);
|
||||
expect(findAllDropdownItems()).toHaveLength(1);
|
||||
expect(findDropdownItemByIndex(0).text()).toBe('_project_1_');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue