summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Eastwood <contact@ericeastwood.com>2018-01-18 02:02:21 -0600
committerEric Eastwood <contact@ericeastwood.com>2018-01-18 23:04:50 -0600
commitea04d1ab3a77f737181ddf84de840330158bbf89 (patch)
tree9b94ab3f41765095513b507a7ad206234f48149f
parent5392568e1eb3f666280a6c6f329a8ed2afcbd7d8 (diff)
downloadgitlab-ce-42157-41989-fix-duplicate-in-create-item-dropdown.tar.gz
Fix duplicate item in protected branch/tag dropdown42157-41989-fix-duplicate-in-create-item-dropdown
Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/42157 Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/41989
-rw-r--r--app/assets/javascripts/create_item_dropdown.js12
-rw-r--r--changelogs/unreleased/42157-41989-fix-duplicate-in-create-item-dropdown.yml5
-rw-r--r--spec/javascripts/create_item_dropdown_spec.js106
-rw-r--r--spec/javascripts/fixtures/create_item_dropdown.html.haml13
4 files changed, 135 insertions, 1 deletions
diff --git a/app/assets/javascripts/create_item_dropdown.js b/app/assets/javascripts/create_item_dropdown.js
index c3eceb285f5..488db023ee7 100644
--- a/app/assets/javascripts/create_item_dropdown.js
+++ b/app/assets/javascripts/create_item_dropdown.js
@@ -65,7 +65,17 @@ export default class CreateItemDropdown {
getData(term, callback) {
this.getDataOption(term, (data = []) => {
- callback(data.concat(this.selectedItem || []));
+ // Ensure the selected item isn't already in the data to avoid duplicates
+ const alreadyHasSelectedItem = this.selectedItem && data.some(item =>
+ item.id === this.selectedItem.id,
+ );
+
+ let uniqueData = data;
+ if (!alreadyHasSelectedItem) {
+ uniqueData = data.concat(this.selectedItem || []);
+ }
+
+ callback(uniqueData);
});
}
diff --git a/changelogs/unreleased/42157-41989-fix-duplicate-in-create-item-dropdown.yml b/changelogs/unreleased/42157-41989-fix-duplicate-in-create-item-dropdown.yml
new file mode 100644
index 00000000000..ac8e4b034b5
--- /dev/null
+++ b/changelogs/unreleased/42157-41989-fix-duplicate-in-create-item-dropdown.yml
@@ -0,0 +1,5 @@
+---
+title: Fix duplicate item in protected branch/tag dropdown
+merge_request:
+author:
+type: fixed
diff --git a/spec/javascripts/create_item_dropdown_spec.js b/spec/javascripts/create_item_dropdown_spec.js
new file mode 100644
index 00000000000..c8b00a4f553
--- /dev/null
+++ b/spec/javascripts/create_item_dropdown_spec.js
@@ -0,0 +1,106 @@
+import CreateItemDropdown from '~/create_item_dropdown';
+
+const DROPDOWN_ITEM_DATA = [{
+ title: 'one',
+ id: 'one',
+ text: 'one',
+}, {
+ title: 'two',
+ id: 'two',
+ text: 'two',
+}, {
+ title: 'three',
+ id: 'three',
+ text: 'three',
+}];
+
+describe('CreateItemDropdown', () => {
+ preloadFixtures('static/create_item_dropdown.html.raw');
+
+ let $wrapperEl;
+
+ beforeEach(() => {
+ loadFixtures('static/create_item_dropdown.html.raw');
+ $wrapperEl = $('.js-create-item-dropdown-fixture-root');
+
+ // eslint-disable-next-line no-new
+ new CreateItemDropdown({
+ $dropdown: $wrapperEl.find('.js-dropdown-menu-toggle'),
+ defaultToggleLabel: 'All variables',
+ fieldName: 'variable[environment]',
+ getData: (term, callback) => {
+ callback(DROPDOWN_ITEM_DATA);
+ },
+ });
+ });
+
+ afterEach(() => {
+ $wrapperEl.remove();
+ });
+
+ it('should have a dropdown item for each piece of data', () => {
+ // Get the data in the dropdown
+ $('.js-dropdown-menu-toggle').click();
+
+ const $itemEls = $wrapperEl.find('.js-dropdown-content a');
+ expect($itemEls.length).toEqual(DROPDOWN_ITEM_DATA.length);
+ });
+
+ describe('created items', () => {
+ const NEW_ITEM_TEXT = 'foobarbaz';
+
+ function createItemAndClearInput(text) {
+ // Filter for the new item
+ $wrapperEl.find('.dropdown-input-field')
+ .val(text)
+ .trigger('input');
+
+ // Create the new item
+ const $createButton = $wrapperEl.find('.js-dropdown-create-new-item');
+ $createButton.click();
+
+ // Clear out the filter
+ $wrapperEl.find('.dropdown-input-field')
+ .val('')
+ .trigger('input');
+ }
+
+ beforeEach(() => {
+ // Open the dropdown
+ $('.js-dropdown-menu-toggle').click();
+
+ // Filter for the new item
+ $wrapperEl.find('.dropdown-input-field')
+ .val(NEW_ITEM_TEXT)
+ .trigger('input');
+ });
+
+ it('create new item button should include the filter text', () => {
+ expect($wrapperEl.find('.js-dropdown-create-new-item code').text()).toEqual(NEW_ITEM_TEXT);
+ });
+
+ it('should update the dropdown with the newly created item', () => {
+ // Create the new item
+ const $createButton = $wrapperEl.find('.js-dropdown-create-new-item');
+ $createButton.click();
+
+ expect($wrapperEl.find('.dropdown-toggle-text').text()).toEqual(NEW_ITEM_TEXT);
+ expect($wrapperEl.find('input[name="variable[environment]"]').val()).toEqual(NEW_ITEM_TEXT);
+ });
+
+ it('should include newly created item in dropdown list', () => {
+ createItemAndClearInput(NEW_ITEM_TEXT);
+
+ const $itemEls = $wrapperEl.find('.js-dropdown-content a');
+ expect($itemEls.length).toEqual(1 + DROPDOWN_ITEM_DATA.length);
+ expect($($itemEls.get(DROPDOWN_ITEM_DATA.length)).text()).toEqual(NEW_ITEM_TEXT);
+ });
+
+ it('should not duplicate an item when trying to create an existing item', () => {
+ createItemAndClearInput(DROPDOWN_ITEM_DATA[0].text);
+
+ const $itemEls = $wrapperEl.find('.js-dropdown-content a');
+ expect($itemEls.length).toEqual(DROPDOWN_ITEM_DATA.length);
+ });
+ });
+});
diff --git a/spec/javascripts/fixtures/create_item_dropdown.html.haml b/spec/javascripts/fixtures/create_item_dropdown.html.haml
new file mode 100644
index 00000000000..d4d91b93caf
--- /dev/null
+++ b/spec/javascripts/fixtures/create_item_dropdown.html.haml
@@ -0,0 +1,13 @@
+.js-create-item-dropdown-fixture-root
+ %input{ name: 'variable[environment]', type: 'hidden' }
+ = dropdown_tag('some label',
+ options: { toggle_class: 'js-dropdown-menu-toggle',
+ content_class: 'js-dropdown-content',
+ filter: true,
+ dropdown_class: "dropdown-menu-selectable",
+ footer_content: true }) do
+ %ul.dropdown-footer-list
+ %li
+ %button{ class: "dropdown-create-new-item-button js-dropdown-create-new-item" }
+ Create wildcard
+ %code