From f0e669c02277b3b3923618dc4f228c913651ed4e Mon Sep 17 00:00:00 2001 From: Jeff Sagal Date: Sun, 12 Apr 2020 12:36:19 -0700 Subject: [PATCH] fix: create option not being called (#1158) Closes #1156 --- src/components/Select.vue | 11 ++++--- src/mixins/typeAheadPointer.js | 6 ---- tests/helpers.js | 17 +++++++++++ tests/unit/CreateOption.spec.js | 30 ++++++++++++++++++ tests/unit/Reduce.spec.js | 5 +++ tests/unit/Tagging.spec.js | 54 ++++++++++++++++++--------------- 6 files changed, 88 insertions(+), 35 deletions(-) create mode 100644 tests/unit/CreateOption.spec.js diff --git a/src/components/Select.vue b/src/components/Select.vue index ab4b9a7..38072ad 100644 --- a/src/components/Select.vue +++ b/src/components/Select.vue @@ -695,7 +695,7 @@ */ onAfterSelect(option) { if (this.closeOnSelect) { - this.open = !this.open + this.open = !this.open; this.searchEl.blur() } @@ -1153,10 +1153,13 @@ } let options = this.search.length ? this.filter(optionList, this.search, this) : optionList; - if (this.taggable && this.search.length && !this.optionExists(this.createOption(this.search))) { - options.unshift(this.search) + if (this.taggable && this.search.length) { + const createdOption = this.createOption(this.search); + if (!this.optionExists(createdOption)) { + options.unshift(createdOption); + } } - return options + return options; }, /** diff --git a/src/mixins/typeAheadPointer.js b/src/mixins/typeAheadPointer.js index 725796a..2001738 100644 --- a/src/mixins/typeAheadPointer.js +++ b/src/mixins/typeAheadPointer.js @@ -61,12 +61,6 @@ export default { if (typeAheadOption) { this.select(typeAheadOption); - } else if (this.taggable && this.search.length) { - this.select(this.createOption(this.search)); - } - - if (this.clearSearchOnSelect) { - this.search = ""; } } } diff --git a/tests/helpers.js b/tests/helpers.js index 77c5988..e055155 100755 --- a/tests/helpers.js +++ b/tests/helpers.js @@ -16,6 +16,23 @@ export const searchSubmit = (Wrapper, searchText = false) => { Wrapper.find({ ref: "search" }).trigger("keydown.enter") }; +/** + * Focus the input, enter some search text, hit return. + * @param Wrapper {Wrapper} + * @param searchText + * @return {Promise} + */ +export const selectTag = async (Wrapper, searchText) => { + Wrapper.vm.$refs.search.focus(); + await Wrapper.vm.$nextTick(); + + Wrapper.vm.search = searchText; + await Wrapper.vm.$nextTick(); + + Wrapper.find({ ref: "search" }).trigger("keydown.enter"); + await Wrapper.vm.$nextTick(); +}; + /** * Create a new VueSelect instance with * a provided set of props. diff --git a/tests/unit/CreateOption.spec.js b/tests/unit/CreateOption.spec.js new file mode 100644 index 0000000..89ff219 --- /dev/null +++ b/tests/unit/CreateOption.spec.js @@ -0,0 +1,30 @@ +import { searchSubmit, selectTag, selectWithProps } from "../helpers"; + +describe("CreateOption When Tagging Is Enabled", () => { + it("can select the current search text as a string", async () => { + const Select = selectWithProps({ + taggable: true, + multiple: true, + options: ["one", "two"], + createOption: option => "four" + }); + + await selectTag(Select, "three"); + expect(Select.vm.selectedValue).toEqual(["four"]); + }); + + it("can select the current search text as an object", async () => { + const Select = selectWithProps({ + taggable: true, + multiple: false, + value: null, + options: [], + label: "name", + createOption: title => ({ name: title }) + }); + + await selectTag(Select, "two"); + + expect(Select.emitted("input")[0]).toEqual([{ name: "two" }]); + }); +}); diff --git a/tests/unit/Reduce.spec.js b/tests/unit/Reduce.spec.js index 020f7c0..d656716 100755 --- a/tests/unit/Reduce.spec.js +++ b/tests/unit/Reduce.spec.js @@ -245,7 +245,12 @@ describe("When reduce prop is defined", () => { const Select = Parent.vm.$children[0]; // When + Select.$refs.search.focus(); + await Select.$nextTick(); + Select.search = 'hello'; + await Select.$nextTick(); + Select.typeAheadSelect(); await Select.$nextTick(); diff --git a/tests/unit/Tagging.spec.js b/tests/unit/Tagging.spec.js index 8b9d918..c5c11dc 100755 --- a/tests/unit/Tagging.spec.js +++ b/tests/unit/Tagging.spec.js @@ -1,4 +1,9 @@ -import { mountDefault, searchSubmit, selectWithProps } from '../helpers'; +import { + mountDefault, + searchSubmit, + selectTag, + selectWithProps, +} from '../helpers'; import Select from '../../src/components/Select'; describe("When Tagging Is Enabled", () => { @@ -32,7 +37,7 @@ describe("When Tagging Is Enabled", () => { expect(Select.vm.optionExists(createOption("three"))).toEqual(false); }); - it("can add the current search text as the first item in the options list", () => { + it("can add the current search text as the first item in the options list", async () => { const Select = selectWithProps({ taggable: true, multiple: true, @@ -41,36 +46,37 @@ describe("When Tagging Is Enabled", () => { }); Select.vm.search = "three"; + await Select.vm.$nextTick(); expect(Select.vm.filteredOptions).toEqual(["three"]); }); - it("can select the current search text as a string", () => { + it("can select the current search text as a string", async () => { const Select = selectWithProps({ taggable: true, multiple: true, options: ["one", "two"] }); - searchSubmit(Select, "three"); + await selectTag(Select, "three"); expect(Select.vm.selectedValue).toEqual(["three"]); }); - it("can select the current search text as an object", () => { + it("can select the current search text as an object", async () => { const Select = selectWithProps({ taggable: true, multiple: true, options: [{ label: "one" }] }); - searchSubmit(Select, "two"); + await selectTag(Select, "two"); expect(Select.vm.selectedValue).toEqual([ { label: "two" } ]); }); - it("should add a freshly created option/tag to the options list when pushTags is true", () => { + it("should add a freshly created option/tag to the options list when pushTags is true", async () => { const Select = selectWithProps({ pushTags: true, taggable: true, @@ -79,12 +85,12 @@ describe("When Tagging Is Enabled", () => { options: ["one", "two"] }); - searchSubmit(Select, "three"); + await selectTag(Select, "three"); expect(Select.vm.pushedTags).toEqual(["three"]); expect(Select.vm.optionList).toEqual(["one", "two", "three"]); }); - it("should pushTags even if the consumer has defined a createOption callback", () => { + it("should pushTags even if the consumer has defined a createOption callback", async () => { const Select = selectWithProps({ pushTags: true, taggable: true, @@ -92,13 +98,13 @@ describe("When Tagging Is Enabled", () => { options: ["one", "two"] }); - searchSubmit(Select, "three"); + await selectTag(Select, "three"); expect(Select.vm.pushedTags).toEqual(["three"]); expect(Select.vm.optionList).toEqual(["one", "two", "three"]); }); - it("should add a freshly created option/tag to the options list when pushTags is true and filterable is false", () => { + it("should add a freshly created option/tag to the options list when pushTags is true and filterable is false", async () => { const Select = selectWithProps({ filterable: false, pushTags: true, @@ -108,13 +114,13 @@ describe("When Tagging Is Enabled", () => { options: ["one", "two"] }); - searchSubmit(Select, "three"); + await selectTag(Select, "three"); expect(Select.vm.pushedTags).toEqual(["three"]); expect(Select.vm.optionList).toEqual(["one", "two", "three"]); expect(Select.vm.filteredOptions).toEqual(["one", "two", "three"]); }); - it("wont add a freshly created option/tag to the options list when pushTags is false", () => { + it("wont add a freshly created option/tag to the options list when pushTags is false", async () => { const Select = selectWithProps({ pushTags: false, taggable: true, @@ -123,11 +129,11 @@ describe("When Tagging Is Enabled", () => { options: ["one", "two"] }); - searchSubmit(Select, "three"); + await selectTag(Select, "three"); expect(Select.vm.optionList).toEqual(["one", "two"]); }); - it("wont add a freshly created option/tag to the options list when pushTags is false and filterable is false", () => { + it("wont add a freshly created option/tag to the options list when pushTags is false and filterable is false", async () => { const Select = selectWithProps({ filterable: false, pushTags: false, @@ -137,7 +143,7 @@ describe("When Tagging Is Enabled", () => { options: ["one", "two"] }); - searchSubmit(Select, "three"); + await selectTag(Select, "three"); expect(Select.vm.optionList).toEqual(["one", "two"]); expect(Select.vm.filteredOptions).toEqual(["one", "two"]); }); @@ -150,9 +156,7 @@ describe("When Tagging Is Enabled", () => { options: ["one", two] }); - Select.vm.search = "two"; - - searchSubmit(Select); + await selectTag(Select, "two"); expect(Select.vm.selectedValue).toEqual([two]); }); @@ -211,22 +215,22 @@ describe("When Tagging Is Enabled", () => { expect(Select.vm.selectedValue).toEqual([{ label: "one" }]); }); - it("should not allow duplicate tags when using string options", () => { + it("should not allow duplicate tags when using string options", async () => { const Select = selectWithProps({ taggable: true, multiple: true }); - searchSubmit(Select, "one"); + await selectTag(Select, "one"); expect(Select.vm.selectedValue).toEqual(["one"]); expect(Select.vm.search).toEqual(""); - searchSubmit(Select, "one"); + await selectTag(Select, "one"); expect(Select.vm.selectedValue).toEqual(["one"]); expect(Select.vm.search).toEqual(""); }); - it("should not allow duplicate tags when using object options", () => { + it("should not allow duplicate tags when using object options", async () => { const Select = selectWithProps({ taggable: true, multiple: true, @@ -234,12 +238,12 @@ describe("When Tagging Is Enabled", () => { }); const spy = jest.spyOn(Select.vm, 'select'); - searchSubmit(Select, "one"); + await selectTag(Select, "one"); expect(Select.vm.selectedValue).toEqual([{ label: "one" }]); expect(spy).lastCalledWith({label: 'one'}); expect(Select.vm.search).toEqual(""); - searchSubmit(Select, "one"); + await selectTag(Select, "one"); expect(Select.vm.selectedValue).toEqual([{ label: "one" }]); expect(Select.vm.search).toEqual(""); });