import { afterEach, describe, expect, test } from "vitest";
import { enableAutoUnmount, mount } from "@vue/test-utils";
import { nextTick, type ComponentPublicInstance, type PropType } from "vue";

import OTree from "@/components/tree/Tree.vue";
import OTreeItem from "@/components/tree/TreeItem.vue";

import type { OptionsProp } from "@/composables";
import type { TreeItemProps, TreeOptions } from "../props";

describe("OTree tests", () => {
    enableAutoUnmount(afterEach);

    const options: TreeOptions<string> = [
        {
            label: "Documents",
            icon: "folder",
            options: [
                {
                    label: "Work",
                    value: "work",
                    icon: "cog",
                    options: [
                        {
                            label: "Expenses.doc",
                            value: "expenses",
                            icon: "file",
                        },
                        {
                            label: "Resume.doc",
                            value: "resume",
                            icon: "file",
                        },
                    ],
                },
                {
                    label: "Home",
                    value: "home",
                    icon: "home",
                    options: [
                        {
                            label: "Invoices.txt",
                            value: "invoices",
                            icon: "file",
                        },
                    ],
                },
            ],
        },
        {
            label: "Events",
            value: "events",
            icon: "calendar",
            options: [
                {
                    label: "Meeting",
                    value: "meeting",
                    icon: "calendar-plus",
                },
                {
                    label: "Product Launch",
                    value: "product-launch",
                    icon: "calendar-plus",
                },
                {
                    label: "Report Review",
                    value: "report-review",
                    icon: "calendar-plus",
                },
            ],
        },
        {
            label: "Movies",
            value: "movies",
            icon: "star",
            options: [
                {
                    label: "Al Pacino",
                    value: "al-pacion",
                    icon: "star",
                    options: [
                        {
                            label: "Scarface",
                            value: "scarface",
                            icon: "video",
                        },
                        {
                            label: "Serpico",
                            value: "serpico",
                            icon: "video",
                        },
                    ],
                },
                {
                    label: "Robert De Niro",
                    value: "robert-de-niro",
                    icon: "star",
                    options: [
                        {
                            label: "Goodfellas",
                            value: "goodfellas",
                            icon: "video",
                        },
                        {
                            label: "Untouchables",
                            value: "untouchables",
                            icon: "video",
                        },
                    ],
                },
            ],
        },
    ];

    const componentWrapper = {
        components: {
            OTree,
            OTreeItem,
        },
        props: {
            items: {
                type: Array as PropType<TreeOptions<string>>,
                required: true,
            },
        },
        template: `
            <o-tree v-bind="$attrs">
                <o-tree-item v-for="el in items" :key="el.label" v-bind="el" />
            </o-tree>
            `,
    };

    test("render correctly", () => {
        const wrapper = mount(OTree);
        expect(!!wrapper.vm).toBeTruthy();
        expect(wrapper.exists()).toBeTruthy();
        expect(wrapper.attributes("data-oruga")).toBe("tree");
        expect(wrapper.html()).toMatchSnapshot();
        expect(wrapper.classes("o-tree")).toBeTruthy();
    });

    test("render empty list correctly", () => {
        const wrapper = mount(OTree, { props: { options: [] } });
        expect(wrapper.attributes("data-oruga")).toBe("tree");
        expect(wrapper.html()).toMatchSnapshot();

        const list = wrapper.find(".o-tree__list");
        expect(list.exists()).toBeTruthy();
        const items = list.findAll("*");
        expect(items.length).toBe(1);
    });

    test("render correctly with options", () => {
        const items = [
            { label: "label1", icon: "user" },
            { label: "label2", icon: "mobile" },
        ];

        const wrapper = mount(componentWrapper, {
            props: { items },
        });
        expect(wrapper.attributes("data-oruga")).toBe("tree");
        expect(wrapper.html()).toMatchSnapshot();

        const itemComps = wrapper.findAllComponents(OTreeItem);
        expect(itemComps.length).toBe(items.length);

        items.forEach((value, idx) => {
            expect(itemComps[idx].attributes("data-oruga")).toBe("tree-item");
            expect(itemComps[idx].text()).toBe(value.label);
            expect(itemComps[idx].classes()).toContain("o-tree__item");
        });
    });

    test("render correctly with deep options", () => {
        const wrapper = mount(OTree, { props: { options } });
        expect(!!wrapper.vm).toBeTruthy();
        expect(wrapper.exists()).toBeTruthy();
        expect(wrapper.attributes("data-oruga")).toBe("tree");
        expect(wrapper.html()).toMatchSnapshot();
        expect(wrapper.classes("o-tree")).toBeTruthy();

        const items = wrapper.findAllComponents(OTreeItem);
        expect(items.length).toBe(17);

        items.forEach((value, idx) => {
            expect(items[idx].attributes("data-oruga")).toBe("tree-item");
            expect(items[idx].classes()).toContain("o-tree__item");
        });
    });

    describe("handle options props correctly", () => {
        const options: TreeOptions<string> = [
            { label: "New York", value: "NY" },
            { label: "Rome", value: "RM" },
            { label: "London", value: "LDN" },
            { label: "Istanbul", value: "IST" },
            { label: "Paris", value: "PRS" },
        ];

        test("react accordingly when is using objects values", async () => {
            const wrapper = mount(OTree, {
                props: { options, selectable: true },
            });

            const items = wrapper.findAll('[data-oruga="tree-item"]');
            expect(items.length).toBe(options.length);

            items.forEach((item, index) => {
                expect(item.text()).toEqual(options[index].label);
            });

            const itemLabel = items[1].find(".o-tree__item-label");
            expect(itemLabel.exists()).toBeTruthy();
            await itemLabel.trigger("click");
            expect(items[0].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[1].classes("o-tree__item--selected")).toBeTruthy();
            expect(items[2].classes("o-tree__item--selected")).toBeFalsy();

            expect(wrapper.emitted("update:modelValue")).toHaveLength(1);
            expect(wrapper.emitted("update:modelValue")?.[0][0]).toStrictEqual(
                options[1].value,
            );
            expect(wrapper.emitted("select")).toHaveLength(1);
            expect(wrapper.emitted("select")?.[0][0]).toStrictEqual(
                options[1].value,
            );
        });

        test("handle options as primitves correctly", () => {
            const options: OptionsProp = ["Flint", "Silver", "Vane", 0, 1, 2];

            const wrapper = mount(OTree, { props: { options } });

            const items = wrapper.findAll('[data-oruga="tree-item"]');
            expect(items).toHaveLength(options.length);

            items.forEach((el, idx) => {
                expect(el.text()).toBe(String(options[idx]));
                expect(el.attributes("aria-disabled")).toBe("false");
                expect(el.attributes("aria-hidden")).toBe("false");
                expect(el.attributes("aria-selected")).toBe("false");
            });
        });

        test("handle options as object correctly", () => {
            const options: OptionsProp = {
                flint: "Flint",
                silver: "Silver",
                vane: "Vane",
                0: "Zero",
                1: "One",
                2: "Two",
            };

            const wrapper = mount(OTree, { props: { options } });

            const items = wrapper.findAll('[data-oruga="tree-item"]');
            expect(items).toHaveLength(Object.keys(options).length);

            items.forEach((el, idx) => {
                expect(el.text()).toBe(Object.entries(options)[idx][1]);
                expect(el.attributes("aria-disabled")).toBe("false");
                expect(el.attributes("aria-hidden")).toBe("false");
                expect(el.attributes("aria-selected")).toBe("false");
            });
        });

        test("handle options as options array correctly", () => {
            const options: TreeOptions<string | number> = [
                { label: "Flint", value: "flint" },
                { label: "Silver", value: "silver", disabled: true },
                { label: "Vane", value: "vane" },
                { label: "Zero", value: 0 },
                { label: "One", value: 1 },
                { label: "Two", value: 2, disabled: true },
            ];

            const wrapper = mount(OTree, { props: { options } });

            const items = wrapper.findAll('[data-oruga="tree-item"]');
            expect(items).toHaveLength(options.length);

            items.forEach((el, idx) => {
                expect(el.text()).toBe(options[idx].label);
                expect(el.attributes("aria-disabled")).toBe(
                    options[idx].disabled ? "true" : "false",
                );
                expect(el.attributes("aria-hidden")).toBe("false");
                expect(el.attributes("aria-selected")).toBe("false");
            });
        });

        test("handle grouped options correctly", () => {
            const options: TreeOptions<string | number | object> = [
                {
                    label: "Black Sails",
                    options: [
                        { label: "Flint", value: "flint" },
                        { label: "Silver", value: "silver" },
                        { label: "Vane", value: "vane" },
                        { label: "Billy", value: "billy" },
                    ],
                },
                {
                    label: "Breaking Bad",
                    options: {
                        heisenberg: "Heisenberg",
                        jesse: "Jesse",
                        saul: "Saul",
                        mike: "Mike",
                    },
                },
                {
                    label: "Game of Thrones",
                    disabled: true,
                    options: [
                        "Tyrion Lannister",
                        "Jamie Lannister",
                        "Daenerys Targaryen",
                        "Jon Snow",
                    ],
                },
            ];

            const wrapper = mount(OTree, { props: { options } });

            const items = wrapper.findAll('[data-oruga="tree-item"]');
            expect(items).toHaveLength(15);

            items.forEach((el, idx) => {
                const isGroup = idx % 5 == 0;
                const g_idx = Math.floor(idx / 5);
                const o_idx = (idx % 5) - 1;

                const option = options[g_idx];

                if (isGroup) {
                    const label = el.find(".o-tree__item-label");
                    expect(label.exists()).toBeTruthy();
                    expect(label.text()).toBe(option.label);
                    expect(el.attributes("aria-disabled")).toBe(
                        option.disabled ? "true" : "false",
                    );
                    expect(el.attributes("aria-hidden")).toBe("false");
                    expect(el.attributes("aria-selected")).toBe("false");
                } else {
                    const g_options = option.options ?? [];

                    let optionLabel;
                    if (idx < 5) {
                        optionLabel =
                            (g_options[o_idx] as TreeItemProps<string>).label ||
                            g_options[o_idx];
                    } else if (idx < 10) {
                        optionLabel = Object.entries(g_options)[o_idx][1];
                    } else {
                        optionLabel = g_options[o_idx];
                    }

                    expect(el.text()).toBe(optionLabel);
                    expect(el.attributes("aria-disabled")).toBe("false");
                    expect(el.attributes("aria-hidden")).toBe("false");
                    expect(el.attributes("aria-selected")).toBe("false");
                }
            });
        });
    });

    describe("test collapsable", () => {
        test("react accordingly when tree is not collapsable", async () => {
            const wrapper = mount(OTree, {
                props: { options, collapsable: false },
            });

            const items =
                wrapper.findAllComponents<ComponentPublicInstance>(OTreeItem);
            expect(items.length).toBe(17);

            const itemOne = items[0]; // Documents item
            expect(itemOne.find(".o-tree__item-label").text()).toBe(
                "Documents",
            );
            const itemTwo = items[6]; // Events item
            expect(itemTwo.find(".o-tree__item-label").text()).toBe("Events");
            const itemThree = items[10]; // Movies item
            expect(itemThree.find(".o-tree__item-label").text()).toBe("Movies");

            await itemOne.trigger("click");
            expect(itemOne.emitted("open")).toBeUndefined();
            expect(itemOne.emitted("close")).toBeUndefined();
            await itemTwo.trigger("click");
            expect(itemTwo.emitted("open")).toBeUndefined();
            expect(itemTwo.emitted("close")).toBeUndefined();
            await itemThree.trigger("click");
            expect(itemThree.emitted("open")).toBeUndefined();
            expect(itemThree.emitted("close")).toBeUndefined();
        });

        test("react accordingly when tree is collapsable and has no toggle icon", async () => {
            const wrapper = mount(OTree, {
                props: { options, collapsable: true, toggleIcon: "" },
            });
            await nextTick(); // await child component rendering

            const items =
                wrapper.findAllComponents<ComponentPublicInstance>(OTreeItem);
            expect(items.length).toBe(17);

            // Documents item
            const itemOne = items[0];
            const itemOneLabel = itemOne.find(".o-tree__item-label");
            expect(itemOneLabel.exists()).toBeTruthy();
            const itemOneToggle = itemOneLabel.find(
                ".o-tree__item-toggle-icon",
            );
            expect(itemOneToggle.exists()).toBeFalsy();
            expect(itemOneLabel.text()).toBe("Documents");
            // Events item
            const itemTwo = items[6];
            const itemTwoLabel = itemTwo.find(".o-tree__item-label");
            expect(itemTwoLabel.exists()).toBeTruthy();
            const itemTwoToggle = itemTwoLabel.find(
                ".o-tree__item-toggle-icon",
            );
            expect(itemTwoToggle.exists()).toBeFalsy();
            expect(itemTwoLabel.text()).toBe("Events");
            // Movies item
            const itemThree = items[10];
            const itemThreeLabel = itemThree.find(".o-tree__item-label");
            expect(itemThreeLabel.exists()).toBeTruthy();
            const itemThreeToggle = itemThreeLabel.find(
                ".o-tree__item-toggle-icon",
            );
            expect(itemThreeToggle.exists()).toBeFalsy();
            expect(itemThreeLabel.text()).toBe("Movies");

            // open tree sections
            await itemOneLabel.trigger("click");
            expect(itemOne.emitted("open")).toBeDefined();
            expect(itemOne.emitted("close")).toBeUndefined();
            await itemTwoLabel.trigger("click");
            expect(itemTwo.emitted("open")).toBeDefined();
            expect(itemTwo.emitted("close")).toBeUndefined();
            await itemThreeLabel.trigger("click");
            expect(itemThree.emitted("open")).toBeDefined();
            expect(itemThree.emitted("close")).toBeUndefined();

            // close all tree sections
            await itemOneLabel.trigger("click");
            expect(itemOne.emitted("open")).toBeDefined();
            expect(itemOne.emitted("close")).toBeDefined();
            await itemTwoLabel.trigger("click");
            expect(itemTwo.emitted("open")).toBeDefined();
            expect(itemTwo.emitted("close")).toBeDefined();
            await itemThreeLabel.trigger("click");
            expect(itemThree.emitted("open")).toBeDefined();
            expect(itemThree.emitted("close")).toBeDefined();
        });

        test("react accordingly when tree is collapsable and has toggle icon", async () => {
            const wrapper = mount(OTree, {
                props: {
                    options,
                    collapsable: true,
                    toggleIcon: "chevron-left",
                },
            });
            await nextTick(); // await child component rendering

            const items =
                wrapper.findAllComponents<ComponentPublicInstance>(OTreeItem);
            expect(items.length).toBe(17);

            // Documents item
            const itemOne = items[0];
            const itemOneLabel = itemOne.find(".o-tree__item-label");
            expect(itemOneLabel.exists()).toBeTruthy();
            const itemOneToggle = itemOneLabel.find(
                ".o-tree__item-toggle-icon",
            );
            expect(itemOneToggle.exists()).toBeTruthy();
            expect(itemOneLabel.text()).toBe("Documents");
            // Events item
            const itemTwo = items[6];
            const itemTwoLabel = itemTwo.find(".o-tree__item-label");
            expect(itemTwoLabel.exists()).toBeTruthy();
            const itemTwoToggle = itemTwoLabel.find(
                ".o-tree__item-toggle-icon",
            );
            expect(itemTwoToggle.exists()).toBeTruthy();
            expect(itemTwoLabel.text()).toBe("Events");
            // Movies item
            const itemThree = items[10];
            const itemThreeLabel = itemThree.find(".o-tree__item-label");
            expect(itemThreeLabel.exists()).toBeTruthy();
            const itemThreeToggle = itemThreeLabel.find(
                ".o-tree__item-toggle-icon",
            );
            expect(itemThreeToggle.exists()).toBeTruthy();
            expect(itemThreeLabel.text()).toBe("Movies");

            // open tree sections
            await itemOneToggle.trigger("click");
            expect(itemOne.emitted("open")).toBeDefined();
            expect(itemOne.emitted("close")).toBeUndefined();
            await itemTwoToggle.trigger("click");
            expect(itemTwo.emitted("open")).toBeDefined();
            expect(itemTwo.emitted("close")).toBeUndefined();
            await itemThreeToggle.trigger("click");
            expect(itemThree.emitted("open")).toBeDefined();
            expect(itemThree.emitted("close")).toBeUndefined();

            // close all tree sections
            await itemOneToggle.trigger("click");
            expect(itemOne.emitted("open")).toBeDefined();
            expect(itemOne.emitted("close")).toBeDefined();
            await itemTwoToggle.trigger("click");
            expect(itemTwo.emitted("open")).toBeDefined();
            expect(itemTwo.emitted("close")).toBeDefined();
            await itemThreeToggle.trigger("click");
            expect(itemThree.emitted("open")).toBeDefined();
            expect(itemThree.emitted("close")).toBeDefined();
        });
    });

    describe("test selectable", () => {
        const options: TreeOptions<string> = [
            { label: "New York", value: "NY" },
            { label: "Rome", value: "RM" },
            { label: "London", value: "LDN" },
            { label: "Istanbul", value: "IST" },
            { label: "Paris", value: "PRS" },
        ];

        test("react accordingly when new item is selected", async () => {
            const wrapper = mount(OTree, {
                props: {
                    options,
                    selectable: true,
                    modelValue: options[0].value,
                },
            });

            expect(wrapper.classes("o-tree--selectable")).toBeTruthy();

            const items = wrapper.findAll(".o-tree__item");
            expect(items.length).toBe(options.length);

            expect(items[0].classes("o-tree__item--selected")).toBeTruthy();
            expect(items[1].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[2].classes("o-tree__item--selected")).toBeFalsy();

            const itemLabel = items[2].find(".o-tree__item-label");
            expect(itemLabel.exists()).toBeTruthy();
            await itemLabel.trigger("click");

            expect(items[0].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[1].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[2].classes("o-tree__item--selected")).toBeTruthy();

            expect(wrapper.emitted("update:modelValue")).toHaveLength(1);
            expect(wrapper.emitted("update:modelValue")?.[0][0]).toBe(
                options[2].value,
            );
            expect(wrapper.emitted("select")).toHaveLength(1);
            expect(wrapper.emitted("select")?.[0][0]).toBe(options[2].value);
        });

        test("react accordingly when item is clicked without selectable", async () => {
            const wrapper = mount(OTree, {
                props: {
                    options,
                    selectable: false,
                },
            });

            const itemComps =
                wrapper.findAllComponents<ComponentPublicInstance>(
                    '[data-oruga="tree-item"]',
                );
            expect(itemComps.length).toBe(options.length);

            const treeItems = wrapper.findAll('[role="treeitem"]');
            expect(treeItems.length).toBe(options.length);

            await treeItems[0].trigger("click");
            await treeItems[1].trigger("click");
            expect(wrapper.emitted("update:modelValue")).toBeUndefined();
        });

        test("react accordingly when same item is deselected", async () => {
            const wrapper = mount(OTree, {
                props: {
                    options,
                    modelValue: options[0].value,
                    selectable: true,
                },
            });

            const items = wrapper.findAll(".o-tree__item");
            expect(items.length).toBe(options.length);

            expect(items[0].classes("o-tree__item--selected")).toBeTruthy();
            expect(items[1].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[2].classes("o-tree__item--selected")).toBeFalsy();

            const itemLabel = items[0].find(".o-tree__item-label");
            expect(itemLabel.exists()).toBeTruthy();
            await itemLabel.trigger("click");

            expect(items[0].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[1].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[2].classes("o-tree__item--selected")).toBeFalsy();

            expect(wrapper.emitted("update:modelValue")).toHaveLength(1);
            expect(wrapper.emitted("update:modelValue")?.[0][0]).toBe(
                undefined,
            );
            expect(wrapper.emitted("select")).toBeUndefined();
        });

        test("react accordingly when an item is selected with multiple prop", async () => {
            const wrapper = mount(OTree, {
                props: {
                    options,
                    selectable: true,
                    multiple: true,
                },
            });

            expect(wrapper.classes("o-tree--multiple")).toBeTruthy();

            const items = wrapper.findAll(".o-tree__item");
            expect(items.length).toBe(options.length);

            expect(items[0].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[1].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[2].classes("o-tree__item--selected")).toBeFalsy();

            let itemLabel = items[0].find(".o-tree__item-label");
            expect(itemLabel.exists()).toBeTruthy();

            await itemLabel.trigger("click");

            expect(items[0].classes("o-tree__item--selected")).toBeTruthy();
            expect(items[1].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[2].classes("o-tree__item--selected")).toBeFalsy();

            expect(wrapper.emitted("select")).toHaveLength(1);
            expect(wrapper.emitted("select")?.[0]).toContain(options[0].value);
            expect(wrapper.emitted("update:modelValue")).toHaveLength(1);
            expect(wrapper.emitted("update:modelValue")?.[0][0]).toHaveLength(
                1,
            );
            expect(wrapper.emitted("update:modelValue")?.[0][0]).toContain(
                options[0].value,
            );

            itemLabel = items[2].find(".o-tree__item-label");
            expect(itemLabel.exists()).toBeTruthy();

            await itemLabel.trigger("click");

            expect(items[0].classes("o-tree__item--selected")).toBeTruthy();
            expect(items[1].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[2].classes("o-tree__item--selected")).toBeTruthy();

            expect(wrapper.emitted("select")).toHaveLength(2);
            expect(wrapper.emitted("select")?.[1]).toContain(options[2].value);
            expect(wrapper.emitted("update:modelValue")).toHaveLength(2);
            expect(wrapper.emitted("update:modelValue")?.[1][0]).toHaveLength(
                2,
            );
            expect(wrapper.emitted("update:modelValue")?.[1][0]).toContain(
                options[0].value,
            );
            expect(wrapper.emitted("update:modelValue")?.[1][0]).toContain(
                options[2].value,
            );

            itemLabel = items[0].find(".o-tree__item-label");
            expect(itemLabel.exists()).toBeTruthy();

            await itemLabel.trigger("click");

            expect(items[0].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[1].classes("o-tree__item--selected")).toBeFalsy();
            expect(items[2].classes("o-tree__item--selected")).toBeTruthy();

            expect(wrapper.emitted("select")).toHaveLength(2);
            expect(wrapper.emitted("update:modelValue")).toHaveLength(3);
            expect(wrapper.emitted("update:modelValue")?.[2][0]).toHaveLength(
                1,
            );
            expect(wrapper.emitted("update:modelValue")?.[2][0]).not.toContain(
                options[0].value,
            );
            expect(wrapper.emitted("update:modelValue")?.[2][0]).toContain(
                options[2].value,
            );
        });

        test("react accordingly when tree is disabled", async () => {
            const wrapper = mount(OTree, {
                props: { options: options, disabled: true },
            });

            expect(wrapper.classes("o-tree--disabled")).toBeTruthy();

            const items = wrapper.findAll(".o-tree__item");
            expect(items.length).toBe(options.length);

            items.forEach((item) => {
                expect(item.classes("o-tree__item--selected")).toBeFalsy();
            });

            await items[0].trigger("click");

            items.forEach((item) => {
                expect(item.classes("o-tree__item--selected")).toBeFalsy();
            });

            expect(wrapper.emitted("update:modelValue")).toBeUndefined();
            expect(wrapper.emitted("select")).toBeUndefined();

            expect(wrapper.classes("o-tree--disabled")).toBeTruthy();
        });

        test("react accordingly when item has disabled prop", () => {
            const items: TreeOptions<string> = [
                { label: "label1", disabled: true },
                { label: "label2", disabled: false },
            ];
            const wrapper = mount(componentWrapper, { props: { items } });

            const itemComps =
                wrapper.findAllComponents<ComponentPublicInstance>(OTreeItem);
            expect(itemComps.length).toBe(items.length);

            const treeItems = wrapper.findAll('[role="treeitem"]');
            expect(treeItems.length).toBe(items.length);

            expect(treeItems[0].attributes("aria-disabled")).toBe("true");
            expect(itemComps[0].classes()).toContain("o-tree__item--disabled");
            expect(itemComps[1].attributes("aria-disabled")).toBe("false");
        });

        test("react accordingly when selected with keydown", async () => {
            const wrapper = mount(OTree, {
                props: { options, selectable: true },
            });

            const list = wrapper.find("ul");
            expect(list.exists()).toBeTruthy();

            await list.trigger("keydown", { code: "ArrowDown", key: "Down" });
            await list.trigger("keydown", { code: "Enter", key: "Enter" });

            expect(wrapper.emitted("select")).toStrictEqual([
                [options[0].value],
            ]);
            expect(wrapper.emitted("update:modelValue")).toStrictEqual([
                [options[0].value],
            ]);
        });
    });
});
