2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-06-07 07:12:23 +03:00

add Jest suite from vue-cli-3 branch

This commit is contained in:
Jeff
2019-02-10 14:38:30 -08:00
parent 4ed24ab2e3
commit e03c642615
13 changed files with 1330 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
import { shallowMount } from "@vue/test-utils";
import VueSelect from "../src/components/Select";
/**
* Trigger a submit event on the search
* input with a provided search text.
*
* @param Wrapper {Wrapper<Vue>}
* @param searchText
*/
export const searchSubmit = (Wrapper, searchText = false) => {
if (searchText) {
Wrapper.vm.search = searchText;
}
Wrapper.find({ ref: "search" }).trigger("keydown", {
keyCode: 13
});
};
/**
* Create a new VueSelect instance with
* a provided set of props.
* @param propsData
* @returns {Wrapper<Vue>}
*/
export const selectWithProps = (propsData = {}) => {
return shallowMount(VueSelect, { propsData });
};
+8
View File
@@ -0,0 +1,8 @@
module.exports = {
env: {
jest: true
},
rules: {
'import/no-extraneous-dependencies': 'off'
}
}
+89
View File
@@ -0,0 +1,89 @@
import { selectWithProps } from "../helpers";
describe("Asynchronous Loading", () => {
it("can toggle the loading class", () => {
const Select = selectWithProps();
Select.vm.toggleLoading();
expect(Select.vm.mutableLoading).toEqual(true);
Select.vm.toggleLoading(true);
expect(Select.vm.mutableLoading).toEqual(true);
});
it("should trigger the onSearch callback when the search text changes", () => {
const propsData = { onSearch: () => {} };
const spy = jest.spyOn(propsData, "onSearch");
const Select = selectWithProps(propsData);
Select.vm.search = "foo";
expect(spy).toHaveBeenCalled();
});
it("should not trigger the onSearch callback if the search text is empty", () => {
let calledWith = [];
const propsData = {
onSearch: search => {
calledWith.push(search);
}
};
const spy = jest.spyOn(propsData, "onSearch");
const Select = selectWithProps(propsData);
Select.vm.search = "foo";
Select.vm.search = "";
expect(spy).toHaveBeenCalledTimes(1);
expect(calledWith).toEqual(["foo"]);
});
it("should trigger the search event when the search text changes", () => {
const Select = selectWithProps();
Select.vm.search = "foo";
const events = Select.emitted("search");
expect(events).toContainEqual(["foo", Select.vm.toggleLoading]);
expect(events.length).toEqual(1);
});
it("should not trigger the search event if the search text is empty", () => {
const Select = selectWithProps();
Select.vm.search = "foo";
Select.vm.search = "";
const events = Select.emitted("search");
expect(events).toContainEqual(["foo", Select.vm.toggleLoading]);
expect(events.length).toEqual(1);
});
it("can set loading to false from the onSearch callback", () => {
const Select = selectWithProps({
onSearch: (search, loading) => loading(false)
});
Select.vm.search = "foo";
expect(Select.vm.mutableLoading).toEqual(false);
});
it("can set loading to true from the onSearch callback", () => {
const Select = selectWithProps({
onSearch: (search, loading) => loading(true)
});
Select.vm.search = "foo";
expect(Select.vm.mutableLoading).toEqual(true);
});
it("will sync mutable loading with the loading prop", () => {
const Select = selectWithProps({ loading: false });
Select.setProps({ loading: true });
expect(Select.vm.mutableLoading).toEqual(true);
});
});
+87
View File
@@ -0,0 +1,87 @@
import { selectWithProps } from "../helpers";
describe("Removing values", () => {
it("can remove the given tag when its close icon is clicked", () => {
const Select = selectWithProps({ multiple: true, value: ["foo"] });
Select.find(".close").trigger("click");
expect(Select.vm.mutableValue).toEqual([]);
});
it("should not remove tag when close icon is clicked and component is disabled", () => {
const Select = selectWithProps({
value: ["one"],
options: ["one", "two", "three"],
multiple: true,
disabled: true
});
Select.find(".close").trigger("click");
expect(Select.vm.mutableValue).toEqual(["one"]);
});
it("should remove the last item in the value array on delete keypress when multiple is true", () => {
const Select = selectWithProps({
multiple: true,
value: ["one", "two"],
options: ["one", "two", "three"]
});
Select.vm.maybeDeleteValue();
expect(Select.vm.mutableValue).toEqual(["one"]);
});
it("should set value to null on delete keypress when multiple is false", () => {
const Select = selectWithProps({
value: "one",
options: ["one", "two", "three"]
});
Select.vm.maybeDeleteValue();
expect(Select.vm.mutableValue).toEqual(null);
});
describe("Clear button", () => {
it("should be displayed on single select when value is selected", () => {
const Select = selectWithProps({
options: ["foo", "bar"],
value: "foo"
});
expect(Select.vm.showClearButton).toEqual(true);
});
it("should not be displayed on multiple select", () => {
const Select = selectWithProps({
options: ["foo", "bar"],
value: "foo",
multiple: true
});
expect(Select.vm.showClearButton).toEqual(false);
});
it("should remove selected value when clicked", () => {
const Select = selectWithProps({
options: ["foo", "bar"],
value: "foo"
});
expect(Select.vm.mutableValue).toEqual("foo");
Select.find("button.clear").trigger("click");
expect(Select.vm.mutableValue).toEqual(null);
});
it("should be disabled when component is disabled", () => {
const Select = selectWithProps({
options: ["foo", "bar"],
value: "foo",
disabled: true
});
expect(Select.find("button.clear").attributes().disabled).toEqual(
"disabled"
);
});
});
});
+135
View File
@@ -0,0 +1,135 @@
import { selectWithProps } from "../helpers";
describe("Toggling Dropdown", () => {
it("should not open the dropdown when the el is clicked but the component is disabled", () => {
const Select = selectWithProps({ disabled: true });
Select.vm.toggleDropdown({ target: Select.vm.$refs.search });
expect(Select.vm.open).toEqual(false);
});
it("should open the dropdown when the el is clicked", () => {
const Select = selectWithProps({
value: [{ label: "one" }],
options: [{ label: "one" }]
});
Select.vm.toggleDropdown({ target: Select.vm.$refs.search });
expect(Select.vm.open).toEqual(true);
});
it("should open the dropdown when the selected tag is clicked", () => {
const Select = selectWithProps({
value: [{ label: "one" }],
options: [{ label: "one" }]
});
const selectedTag = Select.find(".selected-tag").element;
Select.vm.toggleDropdown({ target: selectedTag });
expect(Select.vm.open).toEqual(true);
});
it("can close the dropdown when the el is clicked", () => {
const Select = selectWithProps();
const spy = jest.spyOn(Select.vm.$refs.search, "blur");
Select.vm.open = true;
Select.vm.toggleDropdown({ target: Select.vm.$el });
expect(spy).toHaveBeenCalled();
});
it("closes the dropdown when an option is selected, multiple is true, and closeOnSelect option is true", () => {
const Select = selectWithProps({
value: [],
options: ["one", "two", "three"],
multiple: true
});
Select.vm.open = true;
Select.vm.select("one");
expect(Select.vm.open).toEqual(false);
});
it("does not close the dropdown when the el is clicked, multiple is true, and closeOnSelect option is false", () => {
const Select = selectWithProps({
value: [],
options: ["one", "two", "three"],
multiple: true,
closeOnSelect: false
});
// const vm = new Vue({
// template:
// '<div><v-select ref="select" :options="options" multiple :closeOnSelect="false" :value="value"></v-select></div>',
// components: { vSelect },
// }).$mount();
Select.vm.open = true;
Select.vm.select("one");
expect(Select.vm.open).toEqual(true);
});
it("should close the dropdown on search blur", () => {
const Select = selectWithProps({
options: [{ label: "one" }]
});
Select.vm.open = true;
Select.find({ ref: "search" }).trigger("blur");
expect(Select.vm.open).toEqual(false);
});
it("will close the dropdown and emit the search:blur event from onSearchBlur", () => {
const Select = selectWithProps();
const spy = jest.spyOn(Select.vm, "$emit");
Select.vm.open = true;
Select.vm.onSearchBlur();
expect(Select.vm.open).toEqual(false);
expect(spy).toHaveBeenCalledWith("search:blur");
});
it("will open the dropdown and emit the search:focus event from onSearchFocus", () => {
const Select = selectWithProps();
const spy = jest.spyOn(Select.vm, "$emit");
Select.vm.onSearchFocus();
expect(Select.vm.open).toEqual(true);
expect(spy).toHaveBeenCalledWith("search:focus");
});
it("will close the dropdown on escape, if search is empty", () => {
const Select = selectWithProps();
const spy = jest.spyOn(Select.vm.$refs.search, "blur");
Select.vm.open = true;
Select.vm.onEscape();
expect(spy).toHaveBeenCalled();
});
it("should remove existing search text on escape keyup", () => {
const Select = selectWithProps({
value: [{ label: "one" }],
options: [{ label: "one" }]
});
Select.vm.search = "foo";
Select.vm.onEscape();
expect(Select.vm.search).toEqual("");
});
it("should have an open class when dropdown is active", () => {
const Select = selectWithProps();
expect(Select.vm.dropdownClasses.open).toEqual(false);
Select.vm.open = true;
expect(Select.vm.dropdownClasses.open).toEqual(true);
});
});
+75
View File
@@ -0,0 +1,75 @@
import { shallowMount } from "@vue/test-utils";
import VueSelect from "../../src/components/Select";
describe("Filtering Options", () => {
it("should filter an array of strings", () => {
const Select = shallowMount(VueSelect, {
propsData: { options: ["foo", "bar", "baz"] }
});
Select.vm.search = "ba";
expect(Select.vm.filteredOptions).toEqual(["bar", "baz"]);
});
it("should not filter the array of strings if filterable is false", () => {
const Select = shallowMount(VueSelect, {
propsData: { options: ["foo", "bar", "baz"], filterable: false }
});
Select.vm.search = "ba";
expect(Select.vm.filteredOptions).toEqual(["foo", "bar", "baz"]);
});
it("should filter without case-sensitivity", () => {
const Select = shallowMount(VueSelect, {
propsData: { options: ["Foo", "Bar", "Baz"] }
});
Select.vm.search = "ba";
expect(Select.vm.filteredOptions).toEqual(["Bar", "Baz"]);
});
it("can filter an array of objects based on the objects label key", () => {
const Select = shallowMount(VueSelect, {
propsData: {
options: [{ label: "Foo" }, { label: "Bar" }, { label: "Baz" }]
}
});
Select.vm.search = "ba";
expect(Select.vm.filteredOptions).toEqual([
{ label: "Bar" },
{ label: "Baz" }
]);
});
it("can determine if a given option should match the current search text", () => {
const Select = shallowMount(VueSelect, {
propsData: {
options: [{ label: "Aoo" }, { label: "Bar" }, { label: "Baz" }],
filterBy: (option, label, search) =>
label.match(new RegExp("^" + search, "i"))
}
});
Select.vm.search = "a";
expect(Select.vm.filteredOptions).toEqual([{ label: "Aoo" }]);
});
it("can use a custom filtering method", () => {
const Select = shallowMount(VueSelect, {
propsData: {
options: ["foo", "bar", "baz"],
filterBy: (option, label) => label.includes("o")
}
});
Select.vm.search = "a";
expect(Select.vm.filteredOptions).toEqual(["foo"]);
});
it("can filter arrays of numbers", () => {
const Select = shallowMount(VueSelect, {
propsData: {
options: [1, 5, 10]
}
});
Select.vm.search = "1";
expect(Select.vm.filteredOptions).toEqual([1, 10]);
});
});
+42
View File
@@ -0,0 +1,42 @@
import VueSelect from "../../src/components/Select";
import { shallowMount } from "@vue/test-utils";
import { selectWithProps } from "../helpers";
describe("Labels", () => {
it("can generate labels using a custom label key", () => {
const Select = selectWithProps({
options: [{ name: "Foo" }],
label: "name",
value: { name: "Foo" }
});
expect(Select.find(".selected-tag").text()).toBe("Foo");
});
it("will console.warn when options contain objects without a valid label key", () => {
const spy = jest.spyOn(console, "warn").mockImplementation(() => {});
const Select = selectWithProps({
options: [{}]
});
Select.vm.open = true;
expect(spy).toHaveBeenCalledWith(
'[vue-select warn]: Label key "option.label" does not exist in options object {}.' +
"\nhttp://sagalbot.github.io/vue-select/#ex-labels"
);
});
it("should display a placeholder if the value is empty", () => {
const Select = shallowMount(VueSelect, {
propsData: {
options: ["one"]
},
attrs: {
placeholder: "foo"
}
});
expect(Select.vm.searchPlaceholder).toEqual("foo");
Select.vm.mutableValue = "one";
expect(Select.vm.searchPlaceholder).not.toBeDefined();
});
});
+43
View File
@@ -0,0 +1,43 @@
import { shallowMount } from "@vue/test-utils";
import VueSelect from "../../src/components/Select";
describe("Single value options", () => {
it("should reset the search input on focus lost", () => {
const Select = shallowMount(VueSelect);
Select.vm.open = true;
Select.vm.search = "t";
expect(Select.vm.search).toEqual("t");
Select.vm.onSearchBlur();
expect(Select.vm.search).toEqual("");
});
it('should apply the "hidden" class to the search input when a value is present', () => {
const Select = shallowMount(VueSelect, { propsData: { value: "foo" } });
expect(Select.vm.inputClasses.hidden).toEqual(true);
});
it('should not apply the "hidden" class to the search input when a value is present, and the dropdown is open', () => {
const Select = shallowMount(VueSelect, { propsData: { value: "foo" } });
Select.vm.toggleDropdown({ target: Select.vm.$refs.search });
expect(Select.vm.open).toEqual(true);
expect(Select.vm.inputClasses.hidden).toEqual(false);
});
it("should not reset the search input on focus lost when clearSearchOnSelect is false", () => {
const Select = shallowMount(VueSelect, {
propsData: { value: "foo", clearSearchOnSelect: false }
});
expect(Select.vm.clearSearchOnSelect).toEqual(false);
Select.vm.open = true;
Select.vm.search = "t";
expect(Select.vm.search).toEqual("t");
Select.vm.onSearchBlur();
expect(Select.vm.search).toEqual("t");
});
});
+215
View File
@@ -0,0 +1,215 @@
import { mount, shallowMount } from "@vue/test-utils";
import VueSelect from "../../src/components/Select";
describe("When index prop is defined", () => {
it("can accept an array of objects and pre-selected value (single)", () => {
const Select = shallowMount(VueSelect, {
propsData: {
index: "value",
value: "foo",
options: [{ label: "This is Foo", value: "foo" }]
}
});
expect(Select.vm.mutableValue).toEqual("foo");
});
it("can determine if an object is pre-selected", () => {
const Select = shallowMount(VueSelect, {
propsData: {
index: "id",
value: "foo",
options: [
{
id: "foo",
label: "This is Foo"
}
]
}
});
expect(
Select.vm.isOptionSelected({
id: "foo",
label: "This is Foo"
})
).toEqual(true);
});
it("can determine if an object is selected after it has been chosen", () => {
const Select = shallowMount(VueSelect, {
propsData: {
index: "id",
options: [{ id: "foo", label: "FooBar" }]
}
});
Select.vm.select({ id: "foo", label: "FooBar" });
expect(
Select.vm.isOptionSelected({
id: "foo",
label: "This is Foo"
})
).toEqual(true);
});
it("can accept an array of objects and pre-selected values (multiple)", () => {
const Select = shallowMount(VueSelect, {
propsData: {
multiple: true,
index: "value",
value: ["foo", "bar"],
options: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" }
]
}
});
expect(Select.vm.mutableValue).toEqual(["foo", "bar"]);
});
it("can deselect a pre-selected object", () => {
const Select = shallowMount(VueSelect, {
propsData: {
multiple: true,
index: "value",
value: ["foo", "bar"],
options: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" }
]
}
});
Select.vm.deselect("foo");
expect(Select.vm.mutableValue.length).toEqual(1);
expect(Select.vm.mutableValue).toEqual(["bar"]);
});
it("can deselect an option when multiple is false", () => {
const Select = shallowMount(VueSelect, {
propsData: {
index: "value",
value: "foo",
options: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" }
]
}
});
Select.vm.deselect("foo");
expect(Select.vm.mutableValue).toEqual(null);
});
it("can use v-model syntax for a two way binding to a parent component", () => {
const Parent = mount({
data: () => ({
index: "value",
value: "foo",
options: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" },
{ label: "This is Baz", value: "baz" }
]
}),
template: `<div><v-select :index="index" :options="options" v-model="value"></v-select></div>`,
components: { "v-select": VueSelect }
});
const Select = Parent.find(VueSelect);
expect(Select.vm.value).toEqual("foo");
expect(Select.vm.mutableValue).toEqual("foo");
Select.vm.mutableValue = "bar";
expect(Parent.vm.value).toEqual("bar");
});
it("can generate labels using a custom label key", () => {
const Select = shallowMount(VueSelect, {
propsData: {
multiple: true,
index: "value",
value: ["baz"],
label: "name",
options: [{ value: "foo", name: "Foo" }, { value: "baz", name: "Baz" }]
}
});
expect(Select.find(".selected-tag").text()).toContain("Baz");
});
it("will console.warn when attempting to select an option with an undefined index", () => {
const spy = jest.spyOn(console, "warn").mockImplementation(() => {});
const Select = shallowMount(VueSelect, {
propsData: {
index: "value",
options: [{ label: "Foo" }]
}
});
Select.vm.select({ label: "Foo" });
expect(spy).toHaveBeenCalledWith(
`[vue-select warn]: Index key "option.value" does not exist in options object {"label":"Foo"}.`
);
});
it("can find the original option within this.options", () => {
const optionToFind = { id: 1, label: "Foo" };
const Select = shallowMount(VueSelect, {
propsData: {
index: "id",
options: [optionToFind, { id: 2, label: "Bar" }]
}
});
expect(Select.vm.findOptionByIndexValue(1)).toEqual(optionToFind);
expect(Select.vm.findOptionByIndexValue(optionToFind)).toEqual(
optionToFind
);
});
describe("And when option[index] is a nested object", () => {
it("can determine if an object is pre-selected", () => {
const nestedOption = { value: { nested: true }, label: "foo" };
const Select = shallowMount(VueSelect, {
propsData: {
index: "value",
value: {
nested: true
},
options: [nestedOption]
}
});
expect(Select.vm.isOptionSelected({ nested: true })).toEqual(true);
});
it("can determine if an object is selected after it is chosen", () => {
const nestedOption = { value: { nested: true }, label: "foo" };
const Select = shallowMount(VueSelect, {
propsData: {
index: "value",
options: [nestedOption]
}
});
Select.vm.select(nestedOption);
expect(Select.vm.isOptionSelected(nestedOption)).toEqual(true);
});
it("can determine a selected values label", () => {
const nestedOption = { value: { nested: true }, label: "foo" };
const Select = shallowMount(VueSelect, {
propsData: {
index: "value",
value: { nested: true },
options: [nestedOption]
}
});
expect(Select.vm.getOptionLabel({ nested: true })).toEqual("foo");
});
});
});
+20
View File
@@ -0,0 +1,20 @@
import { shallowMount } from "@vue/test-utils";
import VueSelect from "../../src/components/Select";
describe("Reset on options change", () => {
it("should not reset the selected value by default when the options property changes", () => {
const Select = shallowMount(VueSelect, {
propsData: { value: "one", options: ["one"] }
});
Select.vm.mutableOptions = ["four", "five", "six"];
expect(Select.vm.mutableValue).toEqual("one");
});
it("should reset the selected value when the options property changes", () => {
const Select = shallowMount(VueSelect, {
propsData: { resetOnOptionsChange: true, value: "one", options: ["one"] }
});
Select.vm.mutableOptions = ["four", "five", "six"];
expect(Select.vm.mutableValue).toEqual(null);
});
});
+217
View File
@@ -0,0 +1,217 @@
import { mount, shallowMount } from "@vue/test-utils";
import VueSelect from "@/components/Select.vue";
describe("VS - Selecting Values", () => {
let defaultProps;
beforeEach(() => {
defaultProps = {
value: "one",
options: ["one", "two", "three"]
};
});
it("can accept an array with pre-selected values", () => {
const Select = shallowMount(VueSelect, {
propsData: defaultProps
});
expect(Select.mutableValue).toEqual(Select.value);
});
it("can accept an array of objects and pre-selected value (single)", () => {
const Select = shallowMount(VueSelect, {
propsData: {
value: { label: "This is Foo", value: "foo" },
options: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" }
]
}
});
expect(Select.mutableValue).toEqual(Select.value);
});
it("can accept an array of objects and pre-selected values (multiple)", () => {
const Select = shallowMount(VueSelect, {
propsData: {
value: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" }
],
options: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" }
]
},
multiple: true
});
expect(Select.mutableValue).toEqual(Select.value);
});
it("can select an option on tab", () => {
const Select = shallowMount(VueSelect, {
propsData: {
selectOnTab: true
}
});
const spy = jest.spyOn(Select.vm, "typeAheadSelect");
Select.find({ ref: "search" }).trigger("keydown", {
keyCode: 9
});
expect(spy).toHaveBeenCalledWith();
});
it("can deselect a pre-selected object", () => {
const Select = shallowMount(VueSelect, {
propsData: {
multiple: true,
value: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" }
],
options: [
{ label: "This is Foo", value: "foo" },
{ label: "This is Bar", value: "bar" }
]
}
});
Select.vm.deselect({ label: "This is Foo", value: "foo" });
expect(Select.vm.mutableValue.length).toEqual(1);
});
it("can deselect a pre-selected string", () => {
const Select = shallowMount(VueSelect, {
propsData: {
multiple: true,
value: ["foo", "bar"],
options: ["foo", "bar"]
}
});
Select.vm.deselect("foo");
expect(Select.vm.mutableValue.length).toEqual(1);
});
it("can deselect an option when multiple is false", () => {
const Select = shallowMount(VueSelect, {
propsData: {
value: "foo"
}
});
Select.vm.deselect("foo");
expect(Select.vm.mutableValue).toEqual(null);
});
it("can determine if the value prop is empty", () => {
const Select = shallowMount(VueSelect, {
propsData: {
value: [],
options: ["one", "two", "three"]
}
});
const select = Select.vm;
expect(select.isValueEmpty).toEqual(true);
select.select(["one"]);
expect(select.isValueEmpty).toEqual(false);
select.select("one");
expect(select.isValueEmpty).toEqual(false);
select.select({ label: "foo", value: "foo" });
expect(select.isValueEmpty).toEqual(false);
select.select("");
expect(select.isValueEmpty).toEqual(true);
select.select(null);
expect(select.isValueEmpty).toEqual(true);
});
it("should reset the selected values when the multiple property changes", () => {
const Select = shallowMount(VueSelect, {
propsData: {
value: ["one"],
multiple: true,
options: ["one", "two", "three"]
}
});
expect(Select.vm.mutableValue).toEqual(["one"]);
Select.setProps({ multiple: false });
expect(Select.vm.mutableValue).toEqual(null);
Select.setProps({ multiple: true });
expect(Select.vm.mutableValue).toEqual([]);
});
it("can retain values present in a new array of options", () => {
const Select = shallowMount(VueSelect, {
propsData: {
value: ["one"],
options: ["one", "two", "three"]
}
});
Select.setProps({ options: ["one", "five", "six"] });
expect(Select.vm.mutableValue).toEqual(["one"]);
});
it("can determine if an object is already selected", () => {
const Select = shallowMount(VueSelect, {
propsData: {
value: [{ label: "one" }],
options: [{ label: "one" }]
}
});
expect(Select.vm.isOptionSelected({ label: "one" })).toEqual(true);
});
it("can use v-model syntax for a two way binding to a parent component", () => {
const Parent = mount({
data: () => ({ value: "foo", options: ["foo", "bar", "baz"] }),
template: `<div><v-select :options="options" v-model="value" /></div>`,
components: { "v-select": VueSelect }
});
const Select = Parent.find(VueSelect);
expect(Select.vm.value).toEqual("foo");
expect(Select.vm.mutableValue).toEqual("foo");
Select.vm.mutableValue = "bar";
expect(Parent.vm.value).toEqual("bar");
});
it("can check if a string value is selected when the value is an object and multiple is true", () => {
const Select = shallowMount(VueSelect, {
propsData: {
multiple: true,
value: [{ label: "foo", value: "bar" }]
}
});
expect(Select.vm.isOptionSelected("foo")).toEqual(true);
});
describe("change Event", () => {
it("will trigger the input event when the selection changes", () => {
const Select = shallowMount(VueSelect);
Select.vm.$data.mutableValue = "bar";
expect(Select.emitted("input")[0]).toEqual(["bar"]);
});
it("should run change when multiple is true and the value changes", () => {
const Select = shallowMount(VueSelect, {
propsData: { multiple: true, value: ["foo"], options: ["foo", "bar"] }
});
Select.vm.$data.mutableValue = ["bar"];
expect(Select.emitted("input")[0]).toEqual([["bar"]]);
});
});
});
+224
View File
@@ -0,0 +1,224 @@
import { searchSubmit, selectWithProps } from "../helpers";
describe("When Tagging Is Enabled", () => {
it("can determine if a given option string already exists", () => {
const Select = selectWithProps({ taggable: true, options: ["one", "two"] });
expect(Select.vm.optionExists("one")).toEqual(true);
expect(Select.vm.optionExists("three")).toEqual(false);
});
it("can determine if a given option object already exists", () => {
const Select = selectWithProps({
taggable: true,
options: [{ label: "one" }, { label: "two" }]
});
expect(Select.vm.optionExists("one")).toEqual(true);
expect(Select.vm.optionExists("three")).toEqual(false);
});
it("can determine if a given option object already exists when using custom labels", () => {
const Select = selectWithProps({
taggable: true,
options: [{ foo: "one" }, { foo: "two" }],
label: "foo"
});
expect(Select.vm.optionExists("one")).toEqual(true);
expect(Select.vm.optionExists("three")).toEqual(false);
});
it("can add the current search text as the first item in the options list", () => {
const Select = selectWithProps({
taggable: true,
multiple: true,
value: ["one"],
options: ["one", "two"]
});
Select.vm.search = "three";
expect(Select.vm.filteredOptions).toEqual(["three"]);
});
it("can select the current search text as a string", () => {
const Select = selectWithProps({
taggable: true,
multiple: true,
value: ["one"],
options: ["one", "two"]
});
searchSubmit(Select, "three");
expect(Select.vm.mutableValue).toEqual(["one", "three"]);
});
it("can select the current search text as an object", () => {
const Select = selectWithProps({
taggable: true,
multiple: true,
value: [{ label: "one" }],
options: [{ label: "one" }]
});
searchSubmit(Select, "two");
expect(Select.vm.mutableValue).toEqual([
{ label: "one" },
{ label: "two" }
]);
});
it("should add a freshly created option/tag to the options list when pushTags is true", () => {
const Select = selectWithProps({
pushTags: true,
taggable: true,
multiple: true,
value: ["one"],
options: ["one", "two"]
});
searchSubmit(Select, "three");
expect(Select.vm.mutableOptions).toEqual(["one", "two", "three"]);
});
it("should add a freshly created option/tag to the options list when pushTags is true and filterable is false", () => {
const Select = selectWithProps({
filterable: false,
pushTags: true,
taggable: true,
multiple: true,
value: ["one"],
options: ["one", "two"]
});
searchSubmit(Select, "three");
expect(Select.vm.mutableOptions).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", () => {
const Select = selectWithProps({
pushTags: false,
taggable: true,
multiple: true,
value: ["one"],
options: ["one", "two"]
});
searchSubmit(Select, "three");
expect(Select.vm.mutableOptions).toEqual(["one", "two"]);
});
it("wont add a freshly created option/tag to the options list when pushTags is false and filterable is false", () => {
const Select = selectWithProps({
filterable: false,
pushTags: false,
taggable: true,
multiple: true,
value: ["one"],
options: ["one", "two"]
});
searchSubmit(Select, "three");
expect(Select.vm.mutableOptions).toEqual(["one", "two"]);
expect(Select.vm.filteredOptions).toEqual(["one", "two"]);
});
it("should select an existing option if the search string matches a string from options", () => {
let two = "two";
const Select = selectWithProps({
taggable: true,
multiple: true,
value: null,
options: ["one", two]
});
Select.vm.search = "two";
searchSubmit(Select);
expect(Select.vm.mutableValue[0]).toBe(two);
});
it("should select an existing option if the search string matches an objects label from options", () => {
let two = { label: "two" };
const Select = selectWithProps({
taggable: true,
options: [{ label: "one" }, two]
});
Select.vm.search = "two";
searchSubmit(Select);
expect(Select.vm.mutableValue.label).toBe(two.label);
});
it("should select an existing option if the search string matches an objects label from options when filter-options is false", () => {
let two = { label: "two" };
const Select = selectWithProps({
taggable: true,
filterable: false,
options: [{ label: "one" }, two]
});
Select.vm.search = "two";
searchSubmit(Select);
expect(Select.vm.mutableValue.label).toBe(two.label);
});
it("should not reset the selected value when the options property changes", () => {
const Select = selectWithProps({
taggable: true,
multiple: true,
value: [{ label: "one" }],
options: [{ label: "one" }]
});
Select.vm.mutableOptions = [{ label: "two" }];
expect(Select.vm.mutableValue).toEqual([{ label: "one" }]);
});
it("should not reset the selected value when the options property changes when filterable is false", () => {
const Select = selectWithProps({
taggable: true,
multiple: true,
filterable: false,
value: [{ label: "one" }],
options: [{ label: "one" }]
});
Select.vm.mutableOptions = [{ label: "two" }];
expect(Select.vm.mutableValue).toEqual([{ label: "one" }]);
});
it("should not allow duplicate tags when using string options", () => {
const Select = selectWithProps({
taggable: true,
multiple: true
});
searchSubmit(Select, "one");
expect(Select.vm.mutableValue).toEqual(["one"]);
expect(Select.vm.search).toEqual("");
searchSubmit(Select, "one");
expect(Select.vm.mutableValue).toEqual(["one"]);
expect(Select.vm.search).toEqual("");
});
it("should not allow duplicate tags when using object options", () => {
const Select = selectWithProps({
taggable: true,
multiple: true,
options: [{ label: "two" }]
});
searchSubmit(Select, "one");
expect(Select.vm.mutableValue).toEqual([{ label: "one" }]);
expect(Select.vm.search).toEqual("");
searchSubmit(Select, "one");
expect(Select.vm.mutableValue).toEqual([{ label: "one" }]);
expect(Select.vm.search).toEqual("");
});
});
+147
View File
@@ -0,0 +1,147 @@
import { shallowMount } from "@vue/test-utils";
import VueSelect from "../../src/components/Select";
describe("Moving the Typeahead Pointer", () => {
const mountDefault = () =>
shallowMount(VueSelect, {
propsData: { options: ["one", "two", "three"] }
});
it("should set the pointer to zero when the filteredOptions change", () => {
const Select = mountDefault();
Select.vm.search = "two";
expect(Select.vm.typeAheadPointer).toEqual(0);
});
it("should move the pointer visually up the list on up arrow keyDown", () => {
const Select = mountDefault();
Select.vm.typeAheadPointer = 1;
Select.find({ ref: "search" }).trigger("keydown", { keyCode: 38 });
expect(Select.vm.typeAheadPointer).toEqual(0);
});
it("should move the pointer visually down the list on down arrow keyDown", () => {
const Select = mountDefault();
Select.vm.typeAheadPointer = 1;
Select.find({ ref: "search" }).trigger("keydown", { keyCode: 40 });
expect(Select.vm.typeAheadPointer).toEqual(2);
});
it("should not move the pointer past the end of the list", () => {
const Select = mountDefault();
Select.vm.typeAheadPointer = 2;
Select.vm.typeAheadDown();
expect(Select.vm.typeAheadPointer).toEqual(2);
});
describe("Automatic Scrolling", () => {
it("should check if the scroll position needs to be adjusted on up arrow keyDown", () => {
const Select = mountDefault();
const spy = jest.spyOn(Select.vm, "maybeAdjustScroll");
Select.vm.typeAheadPointer = 1;
Select.find({ ref: "search" }).trigger("keydown", { keyCode: 38 });
expect(spy).toHaveBeenCalled();
});
it("should check if the scroll position needs to be adjusted on down arrow keyDown", () => {
const Select = mountDefault();
const spy = jest.spyOn(Select.vm, "maybeAdjustScroll");
Select.vm.typeAheadPointer = 1;
Select.find({ ref: "search" }).trigger("keydown", { keyCode: 40 });
expect(spy).toHaveBeenCalled();
});
it("should check if the scroll position needs to be adjusted when filtered options changes", () => {
const Select = mountDefault();
const spy = jest.spyOn(Select.vm, "maybeAdjustScroll");
Select.vm.search = "two";
expect(spy).toHaveBeenCalled();
});
it("should scroll up if the pointer is above the current viewport bounds", () => {
const Select = mountDefault();
const spy = jest.spyOn(Select.vm, "scrollTo");
Select.setMethods({
pixelsToPointerTop() {
return 1;
},
viewport() {
return { top: 2, bottom: 0 };
}
});
Select.vm.maybeAdjustScroll();
expect(spy).toHaveBeenCalledWith(1);
});
it("should scroll down if the pointer is below the current viewport bounds", () => {
const Select = mountDefault();
const spy = jest.spyOn(Select.vm, "scrollTo");
Select.setMethods({
pixelsToPointerBottom() {
return 2;
},
viewport() {
return { top: 0, bottom: 1 };
}
});
Select.vm.maybeAdjustScroll();
expect(spy).toHaveBeenCalledWith(
Select.vm.viewport().top + Select.vm.pointerHeight()
);
});
});
describe("Measuring pixel distances", () => {
it("should calculate pointerHeight as the offsetHeight of the pointer element if it exists", () => {
const Select = mountDefault();
// Drop down must be open for $refs to exist
Select.vm.open = true;
/**
* Since JSDom doesn't render layouts, set the offsetHeight explicitly
* to 25px for each list item.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
*/
let i = 0;
for (let option of Select.vm.$refs.dropdownMenu.children) {
Object.defineProperty(option, "offsetHeight", {
value: 1 + i
});
i++;
}
// Fresh instances start with the pointer at -1
Select.vm.typeAheadPointer = -1;
expect(Select.vm.pointerHeight()).toEqual(0);
Select.vm.typeAheadPointer = 0;
expect(Select.vm.pointerHeight()).toEqual(1);
Select.vm.typeAheadPointer = 1;
expect(Select.vm.pointerHeight()).toEqual(2);
Select.vm.typeAheadPointer = 2;
expect(Select.vm.pointerHeight()).toEqual(3);
});
});
});