-
Base Multiselect Component
+
+
+
+ {{ placeholder }}
+
+
+
+
+
+
+
+
-
-
diff --git a/src/components/SingleSelect.vue b/src/components/SingleSelect.vue
index f6cdede..0c7c4eb 100644
--- a/src/components/SingleSelect.vue
+++ b/src/components/SingleSelect.vue
@@ -1,69 +1,98 @@
-
-
-
+
+
+ {{ selectedLabel }}
+ {{ placeholder }}
+
+
+
+
+ -
+ {{ getLabel(option) }}
+
+
+
+
diff --git a/src/composables/useDropdown.js b/src/composables/useDropdown.js
new file mode 100644
index 0000000..20f1e97
--- /dev/null
+++ b/src/composables/useDropdown.js
@@ -0,0 +1,13 @@
+import { ref } from 'vue'
+
+export function useDropdown() {
+ const isOpen = ref(false)
+
+ const toggleDropdown = () => {
+ isOpen.value = !isOpen.value
+ }
+ const closeDropdown = () => {
+ isOpen.value = false
+ }
+ return { isOpen, toggleDropdown, closeDropdown }
+}
diff --git a/src/composables/click-outside.js b/src/directives/click-outside.js
similarity index 100%
rename from src/composables/click-outside.js
rename to src/directives/click-outside.js
diff --git a/src/main.js b/src/main.js
index 98ce12f..c3dd019 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,11 +1,11 @@
// directives
-import clickOutside from "./composables/click-outside.js";
+import clickOutside from './directives/click-outside.js'
-import { createApp } from "vue";
-import App from "./App.vue";
+import { createApp } from 'vue'
+import App from './App.vue'
-const app = createApp(App);
+const app = createApp(App)
-app.directive("click-outside", clickOutside);
+app.directive('click-outside', clickOutside)
-app.mount("#app");
+app.mount('#app')
diff --git a/tests/base-multiselect.test.js b/tests/base-multiselect.test.js
new file mode 100644
index 0000000..008bd59
--- /dev/null
+++ b/tests/base-multiselect.test.js
@@ -0,0 +1,41 @@
+import { describe, it, expect } from "vitest";
+import { mount } from "@vue/test-utils";
+import BaseMultiselect from "../src/components/BaseMultiselect.vue";
+
+const clickOutsideStub = {
+ beforeMount() {},
+ unmounted() {}
+};
+
+describe("BaseMultiselect wrapper behavior", () => {
+ it("renders placeholder when modelValue is empty", () => {
+ const wrapper = mount(BaseMultiselect, {
+ props: { options: ["A", "B"], modelValue: null, placeholder: "Select..." },
+ global: { directives: { "click-outside": clickOutsideStub } }
+ });
+ expect(wrapper.find(".selected-display").text()).toContain("Select...");
+ });
+
+ it("toggles dropdown visibility on click", async () => {
+ const wrapper = mount(BaseMultiselect, {
+ props: { options: ["A", "B"], modelValue: null },
+ global: { directives: { "click-outside": clickOutsideStub } }
+ });
+ expect(wrapper.find(".options-dropdown").exists()).toBe(false);
+ await wrapper.find(".selected-display").trigger("click");
+ expect(wrapper.find(".options-dropdown").exists()).toBe(true);
+ });
+
+ it("emits search on input", async () => {
+ const wrapper = mount(BaseMultiselect, {
+ props: { options: ["A", "B"], modelValue: null },
+ global: { directives: { "click-outside": clickOutsideStub } }
+ });
+ const input = wrapper.find(".search-input");
+ await input.setValue("B");
+ await input.trigger("input");
+ const events = wrapper.emitted("search");
+ expect(events).toBeTruthy();
+ expect(events[0][0]).toBe("B");
+ });
+});
\ No newline at end of file
diff --git a/tests/example.test.js b/tests/example.test.js
deleted file mode 100644
index f1e49df..0000000
--- a/tests/example.test.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import { describe, it, expect } from "vitest";
-import { mount } from "@vue/test-utils";
-import BaseMultiselect from "../src/components/BaseMultiselect.vue";
-
-describe("BaseMultiselect Component", () => {
- it("should render without errors", () => {
- const wrapper = mount(BaseMultiselect);
- expect(wrapper.exists()).toBe(true);
- expect(wrapper.text()).toContain("Base Multiselect Component");
- });
-});
diff --git a/tests/single-select-variant.test.js b/tests/single-select-variant.test.js
index 40da67b..16e8c62 100644
--- a/tests/single-select-variant.test.js
+++ b/tests/single-select-variant.test.js
@@ -2,12 +2,19 @@ import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import Variant from "../src/components/variants/SingleSelectSimple.vue";
+const clickOutsideStub = {
+ beforeMount() {},
+ unmounted() {}
+};
+
describe("SingleSelect simple variant", () => {
- it("renders two select elements with initial values", () => {
- const wrapper = mount(Variant);
- const selects = wrapper.findAll("select");
- expect(selects.length).toBe(2);
- expect(selects[0].element.value).toBe("Apple");
- expect(selects[1].element.value).toBe("1");
+ it("renders two SingleSelects with initial labels", () => {
+ const wrapper = mount(Variant, {
+ global: { directives: { "click-outside": clickOutsideStub } }
+ });
+ const displays = wrapper.findAll(".selected-display");
+ expect(displays.length).toBe(2);
+ expect(displays[0].text()).toContain("Apple");
+ expect(displays[1].text()).toContain("One");
});
});
diff --git a/tests/single-select.test.js b/tests/single-select.test.js
index 1a5d82d..05de8ed 100644
--- a/tests/single-select.test.js
+++ b/tests/single-select.test.js
@@ -2,13 +2,22 @@ import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import SingleSelect from "../src/components/SingleSelect.vue";
+const clickOutsideStub = {
+ beforeMount() {},
+ unmounted() {}
+};
+
describe("SingleSelect Component", () => {
it("emits selected primitive value", async () => {
const wrapper = mount(SingleSelect, {
- props: { options: ["a", "b", "c"] }
+ props: { options: ["a", "b", "c"], modelValue: "" },
+ global: { directives: { "click-outside": clickOutsideStub } }
});
- await wrapper.find("select").setValue("b");
+ await wrapper.find(".selected-display").trigger("click");
+ const options = wrapper.findAll(".single-select-options li");
+ expect(options.length).toBe(3);
+ await options[1].trigger("click");
expect(wrapper.emitted()["update:modelValue"][0]).toEqual(["b"]);
});
@@ -18,9 +27,15 @@ describe("SingleSelect Component", () => {
{ label: "One", value: 1 },
{ label: "Two", value: 2 }
];
- const wrapper = mount(SingleSelect, { props: { options } });
+ const wrapper = mount(SingleSelect, {
+ props: { options, modelValue: "" },
+ global: { directives: { "click-outside": clickOutsideStub } }
+ });
- await wrapper.find("select").setValue("2");
+ await wrapper.find(".selected-display").trigger("click");
+ const items = wrapper.findAll(".single-select-options li");
+ expect(items.length).toBe(2);
+ await items[1].trigger("click");
expect(wrapper.emitted()["update:modelValue"][0]).toEqual([options[1]]);
});