mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-09-20 13:09:27 +00:00
894 lines
26 KiB
TypeScript
894 lines
26 KiB
TypeScript
/**
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
* (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
import { mount } from "@vue/test-utils";
|
|
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
import { nextTick } from "vue";
|
|
import TimePicker from "../TimePicker.vue";
|
|
|
|
// Mock vue-i18n
|
|
vi.mock("vue-i18n", () => ({
|
|
useI18n: () => ({
|
|
t: (key: string) => {
|
|
const translations: Record<string, string> = {
|
|
hourTip: "Hour",
|
|
minuteTip: "Minute",
|
|
secondTip: "Second",
|
|
yearSuffix: "Year",
|
|
monthsHead: "January_February_March_April_May_June_July_August_September_October_November_December",
|
|
months: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
|
weeks: "Mon_Tue_Wed_Thu_Fri_Sat_Sun",
|
|
cancel: "Cancel",
|
|
confirm: "Confirm",
|
|
quarterHourCutTip: "Quarter Hour",
|
|
halfHourCutTip: "Half Hour",
|
|
hourCutTip: "Hour",
|
|
dayCutTip: "Day",
|
|
weekCutTip: "Week",
|
|
monthCutTip: "Month",
|
|
};
|
|
return translations[key] || key;
|
|
},
|
|
}),
|
|
}));
|
|
|
|
// Mock the useTimeout hook
|
|
vi.mock("@/hooks/useTimeout", () => ({
|
|
useTimeoutFn: vi.fn((callback: Function, delay: number) => {
|
|
setTimeout(callback, delay);
|
|
}),
|
|
}));
|
|
|
|
describe("TimePicker Component", () => {
|
|
let wrapper: any;
|
|
const mockDate = new Date(2024, 0, 15, 2, 30, 45);
|
|
const mockDateRange = [new Date(2024, 0, 10), new Date(2024, 0, 20)];
|
|
|
|
describe("Props", () => {
|
|
it("should render with default props", () => {
|
|
wrapper = mount(TimePicker);
|
|
expect(wrapper.exists()).toBe(true);
|
|
expect(wrapper.classes()).toContain("datepicker");
|
|
});
|
|
|
|
it("should render with custom position", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
position: "top",
|
|
type: "inline", // Make popup visible
|
|
},
|
|
});
|
|
expect(wrapper.find(".datepicker-popup").classes()).toContain("top");
|
|
});
|
|
|
|
it("should render with custom type", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
type: "inline",
|
|
},
|
|
});
|
|
expect(wrapper.find(".datepicker-popup").classes()).toContain("datepicker-inline");
|
|
});
|
|
|
|
it("should render with custom range separator", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
rangeSeparator: "to",
|
|
},
|
|
});
|
|
expect(wrapper.vm.rangeSeparator).toBe("to");
|
|
});
|
|
|
|
it("should render with clearable prop", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
clearable: true,
|
|
value: mockDate,
|
|
},
|
|
});
|
|
// Wait for the component to fully mount and update
|
|
await nextTick();
|
|
|
|
// The class is only applied when there's text and not disabled
|
|
expect(wrapper.vm.text).toBeTruthy();
|
|
// The class should be applied since we have clearable=true, text exists, and not disabled
|
|
expect(wrapper.classes()).toContain("datepicker__clearable");
|
|
});
|
|
|
|
it("should render with disabled prop", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
disabled: true,
|
|
},
|
|
});
|
|
expect(wrapper.find("input").attributes("disabled")).toBeDefined();
|
|
});
|
|
|
|
it("should render with custom placeholder", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
placeholder: "Select date",
|
|
},
|
|
});
|
|
expect(wrapper.find("input").attributes("placeholder")).toBe("Select date");
|
|
});
|
|
|
|
it("should render with custom format", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
format: "YYYY-MM-DD HH:mm:ss",
|
|
},
|
|
});
|
|
expect(wrapper.vm.format).toBe("YYYY-MM-DD HH:mm:ss");
|
|
});
|
|
|
|
it("should render with showButtons prop", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
showButtons: true,
|
|
type: "inline", // Make popup visible
|
|
},
|
|
});
|
|
expect(wrapper.find(".datepicker__buttons").exists()).toBe(true);
|
|
});
|
|
|
|
it("should render with maxRange array", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
maxRange: [new Date(2024, 0, 1), new Date(2024, 0, 31)],
|
|
},
|
|
});
|
|
expect(wrapper.vm.maxRange).toHaveLength(2);
|
|
});
|
|
});
|
|
|
|
describe("Computed Properties", () => {
|
|
it("should calculate range correctly for single date", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDate,
|
|
},
|
|
});
|
|
expect(wrapper.vm.range).toBe(false);
|
|
});
|
|
|
|
it("should calculate range correctly for date range", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
},
|
|
});
|
|
expect(wrapper.vm.range).toBe(true);
|
|
});
|
|
|
|
it("should format text correctly for single date", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDate,
|
|
},
|
|
});
|
|
expect(wrapper.vm.text).toBe("2024-01-15");
|
|
});
|
|
|
|
it("should format text correctly for date range", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
},
|
|
});
|
|
expect(wrapper.vm.text).toBe("2024-01-10 ~ 2024-01-20");
|
|
});
|
|
|
|
it("should format text with custom range separator", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
rangeSeparator: "to",
|
|
},
|
|
});
|
|
expect(wrapper.vm.text).toBe("2024-01-10 to 2024-01-20");
|
|
});
|
|
|
|
it("should return empty text for empty value", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: [],
|
|
},
|
|
});
|
|
expect(wrapper.vm.text).toBe("");
|
|
});
|
|
|
|
it("should get correct value for single date", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDate,
|
|
},
|
|
});
|
|
const result = wrapper.vm.get();
|
|
expect(result).toEqual(wrapper.vm.dates[0]);
|
|
});
|
|
|
|
it("should get correct value for date range", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
},
|
|
});
|
|
const result = wrapper.vm.get();
|
|
expect(result).toEqual(wrapper.vm.dates);
|
|
});
|
|
});
|
|
|
|
describe("Methods", () => {
|
|
it("should handle clear action", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDate,
|
|
},
|
|
});
|
|
wrapper.vm.cls();
|
|
expect(wrapper.emitted("clear")).toBeTruthy();
|
|
});
|
|
|
|
it("should handle clear action for range", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
},
|
|
});
|
|
wrapper.vm.cls();
|
|
expect(wrapper.emitted("clear")).toBeTruthy();
|
|
expect(wrapper.emitted("input")?.[0]).toEqual([[]]);
|
|
});
|
|
|
|
it("should validate input correctly for array", () => {
|
|
wrapper = mount(TimePicker);
|
|
const result = wrapper.vm.vi([mockDate, mockDate]);
|
|
expect(result).toHaveLength(2);
|
|
});
|
|
|
|
it("should validate input correctly for single date", () => {
|
|
wrapper = mount(TimePicker);
|
|
const result = wrapper.vm.vi(mockDate);
|
|
expect(result).toHaveLength(1);
|
|
});
|
|
|
|
it("should validate input correctly for empty value", () => {
|
|
wrapper = mount(TimePicker);
|
|
const result = wrapper.vm.vi(null);
|
|
expect(result).toHaveLength(1);
|
|
});
|
|
|
|
it("should handle ok event", () => {
|
|
wrapper = mount(TimePicker);
|
|
wrapper.vm.ok(false);
|
|
expect(wrapper.emitted("input")).toBeTruthy();
|
|
});
|
|
|
|
it("should handle ok event with leaveOpened", () => {
|
|
wrapper = mount(TimePicker);
|
|
wrapper.vm.ok(true);
|
|
expect(wrapper.emitted("input")).toBeTruthy();
|
|
});
|
|
|
|
it("should handle setDates for right position", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
},
|
|
});
|
|
const newDate = new Date(2024, 0, 25);
|
|
wrapper.vm.setDates(newDate, "right");
|
|
expect(wrapper.vm.dates[1]).toEqual(newDate);
|
|
});
|
|
|
|
it("should handle setDates for left position", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
},
|
|
});
|
|
const newDate = new Date(2024, 0, 5);
|
|
wrapper.vm.setDates(newDate, "left");
|
|
expect(wrapper.vm.dates[0]).toEqual(newDate);
|
|
});
|
|
|
|
it("should handle document click", () => {
|
|
wrapper = mount(TimePicker);
|
|
const mockEvent = {
|
|
target: document.createElement("div"),
|
|
} as unknown as MouseEvent;
|
|
wrapper.vm.datepicker = {
|
|
contains: vi.fn(() => true),
|
|
};
|
|
wrapper.vm.dc(mockEvent);
|
|
expect(wrapper.vm.show).toBe(true);
|
|
});
|
|
|
|
it("should handle document click outside", () => {
|
|
wrapper = mount(TimePicker);
|
|
const mockEvent = {
|
|
target: document.createElement("div"),
|
|
} as unknown as MouseEvent;
|
|
wrapper.vm.datepicker = {
|
|
contains: vi.fn(() => false),
|
|
};
|
|
wrapper.vm.dc(mockEvent);
|
|
expect(wrapper.vm.show).toBe(false);
|
|
});
|
|
|
|
it("should handle document click when disabled", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
disabled: true,
|
|
},
|
|
});
|
|
const mockEvent = {
|
|
target: document.createElement("div"),
|
|
} as unknown as MouseEvent;
|
|
wrapper.vm.datepicker = {
|
|
contains: vi.fn(() => true),
|
|
};
|
|
wrapper.vm.dc(mockEvent);
|
|
expect(wrapper.vm.show).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("Quick Pick Functionality", () => {
|
|
beforeEach(() => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
maxRange: [new Date(2024, 0, 1), new Date(2024, 0, 31)],
|
|
},
|
|
});
|
|
});
|
|
|
|
it("should have QUICK_PICK_TYPES constant defined", () => {
|
|
expect(wrapper.vm.QUICK_PICK_TYPES).toBeDefined();
|
|
expect(wrapper.vm.QUICK_PICK_TYPES.QUARTER).toBe("quarter");
|
|
expect(wrapper.vm.QUICK_PICK_TYPES.HALF).toBe("half");
|
|
expect(wrapper.vm.QUICK_PICK_TYPES.HOUR).toBe("hour");
|
|
expect(wrapper.vm.QUICK_PICK_TYPES.DAY).toBe("day");
|
|
expect(wrapper.vm.QUICK_PICK_TYPES.WEEK).toBe("week");
|
|
expect(wrapper.vm.QUICK_PICK_TYPES.MONTH).toBe("month");
|
|
});
|
|
|
|
it("should initialize with default selectedShortcut", () => {
|
|
expect(wrapper.vm.selectedShortcut).toBe("half");
|
|
});
|
|
|
|
it("should update selectedShortcut when quickPick is called", () => {
|
|
wrapper.vm.quickPick("quarter");
|
|
expect(wrapper.vm.selectedShortcut).toBe("quarter");
|
|
|
|
wrapper.vm.quickPick("day");
|
|
expect(wrapper.vm.selectedShortcut).toBe("day");
|
|
});
|
|
|
|
it("should handle quarter hour quick pick", () => {
|
|
wrapper.vm.quickPick("quarter");
|
|
|
|
expect(wrapper.vm.selectedShortcut).toBe("quarter");
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
expect(wrapper.vm.dates[0].getTime()).toBeLessThan(wrapper.vm.dates[1].getTime());
|
|
});
|
|
|
|
it("should handle half hour quick pick", () => {
|
|
wrapper.vm.quickPick("half");
|
|
|
|
expect(wrapper.vm.selectedShortcut).toBe("half");
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
expect(wrapper.vm.dates[0].getTime()).toBeLessThan(wrapper.vm.dates[1].getTime());
|
|
});
|
|
|
|
it("should handle hour quick pick", () => {
|
|
wrapper.vm.quickPick("hour");
|
|
|
|
expect(wrapper.vm.selectedShortcut).toBe("hour");
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
expect(wrapper.vm.dates[0].getTime()).toBeLessThan(wrapper.vm.dates[1].getTime());
|
|
});
|
|
|
|
it("should handle day quick pick", () => {
|
|
wrapper.vm.quickPick("day");
|
|
|
|
expect(wrapper.vm.selectedShortcut).toBe("day");
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
expect(wrapper.vm.dates[0].getTime()).toBeLessThan(wrapper.vm.dates[1].getTime());
|
|
});
|
|
|
|
it("should handle week quick pick", () => {
|
|
wrapper.vm.quickPick("week");
|
|
|
|
expect(wrapper.vm.selectedShortcut).toBe("week");
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
expect(wrapper.vm.dates[0].getTime()).toBeLessThan(wrapper.vm.dates[1].getTime());
|
|
});
|
|
|
|
it("should handle month quick pick", () => {
|
|
wrapper.vm.quickPick("month");
|
|
|
|
expect(wrapper.vm.selectedShortcut).toBe("month");
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
expect(wrapper.vm.dates[0].getTime()).toBeLessThan(wrapper.vm.dates[1].getTime());
|
|
});
|
|
|
|
it("should handle unknown quick pick type", () => {
|
|
wrapper.vm.quickPick("unknown" as any);
|
|
|
|
expect(wrapper.vm.selectedShortcut).toBe("unknown");
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
expect(wrapper.vm.dates[0]).toBeInstanceOf(Date);
|
|
expect(wrapper.vm.dates[1]).toBeInstanceOf(Date);
|
|
});
|
|
|
|
it("should apply selected style to active shortcut button", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
type: "inline",
|
|
maxRange: [new Date(2024, 0, 1), new Date(2024, 0, 31)],
|
|
},
|
|
});
|
|
|
|
// Force range mode by setting dates directly and wait for reactivity
|
|
wrapper.vm.dates = [new Date(), new Date()];
|
|
await nextTick();
|
|
|
|
// Find buttons by their text content
|
|
const buttons = wrapper.findAll(".datepicker-popup__shortcut");
|
|
const halfButton = buttons.find((btn: any) => btn.text().includes("Half Hour"));
|
|
const quarterButton = buttons.find((btn: any) => btn.text().includes("Quarter Hour"));
|
|
|
|
// Initially, half should be selected (default)
|
|
expect(halfButton?.classes()).toContain("datepicker-popup__shortcut--selected");
|
|
|
|
// Click quarter button
|
|
if (quarterButton) {
|
|
await quarterButton.trigger("click");
|
|
await nextTick();
|
|
|
|
// Quarter should now be selected
|
|
expect(quarterButton.classes()).toContain("datepicker-popup__shortcut--selected");
|
|
expect(halfButton?.classes()).not.toContain("datepicker-popup__shortcut--selected");
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Button Actions", () => {
|
|
beforeEach(() => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
showButtons: true,
|
|
},
|
|
});
|
|
});
|
|
|
|
it("should handle submit action", () => {
|
|
wrapper.vm.dates = [mockDate];
|
|
wrapper.vm.submit();
|
|
|
|
expect(wrapper.emitted("confirm")).toBeTruthy();
|
|
expect(wrapper.vm.show).toBe(false);
|
|
});
|
|
|
|
it("should handle cancel action", () => {
|
|
wrapper.vm.dates = [mockDate];
|
|
wrapper.vm.cancel();
|
|
|
|
expect(wrapper.emitted("cancel")).toBeTruthy();
|
|
expect(wrapper.vm.show).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("Template Rendering", () => {
|
|
it("should render input field", () => {
|
|
wrapper = mount(TimePicker);
|
|
expect(wrapper.find("input").exists()).toBe(true);
|
|
});
|
|
|
|
it("should render input with custom class", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
inputClass: "custom-input",
|
|
},
|
|
});
|
|
expect(wrapper.find("input").classes()).toContain("custom-input");
|
|
});
|
|
|
|
it("should render input with placeholder", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
placeholder: "Select date",
|
|
},
|
|
});
|
|
expect(wrapper.find("input").attributes("placeholder")).toBe("Select date");
|
|
});
|
|
|
|
it("should render disabled input", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
disabled: true,
|
|
},
|
|
});
|
|
expect(wrapper.find("input").attributes("disabled")).toBeDefined();
|
|
});
|
|
|
|
it("should render clear button when clearable and has value", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
clearable: true,
|
|
value: mockDate,
|
|
},
|
|
});
|
|
expect(wrapper.find(".datepicker-close").exists()).toBe(true);
|
|
});
|
|
|
|
it("should not render clear button when not clearable", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
clearable: false,
|
|
},
|
|
});
|
|
// The clear button is always rendered but only visible on hover when clearable
|
|
expect(wrapper.find(".datepicker-close").exists()).toBe(true);
|
|
});
|
|
|
|
it("should render popup with correct position class", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
position: "bottom",
|
|
type: "inline", // Make popup visible
|
|
},
|
|
});
|
|
expect(wrapper.find(".datepicker-popup").classes()).toContain("bottom");
|
|
});
|
|
|
|
it("should render inline popup", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
type: "inline",
|
|
},
|
|
});
|
|
expect(wrapper.find(".datepicker-popup").classes()).toContain("datepicker-inline");
|
|
});
|
|
|
|
it("should render sidebar for range mode", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
type: "inline",
|
|
},
|
|
});
|
|
// Force range mode by setting dates directly and wait for reactivity
|
|
wrapper.vm.dates = [new Date(), new Date()];
|
|
await nextTick();
|
|
expect(wrapper.vm.range).toBe(true);
|
|
expect(wrapper.find(".datepicker-popup__sidebar").exists()).toBe(true);
|
|
});
|
|
|
|
it("should render quick pick buttons", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
type: "inline",
|
|
},
|
|
});
|
|
// Force range mode by setting dates directly and wait for reactivity
|
|
wrapper.vm.dates = [new Date(), new Date()];
|
|
await nextTick();
|
|
const buttons = wrapper.findAll(".datepicker-popup__shortcut");
|
|
expect(buttons).toHaveLength(6); // quarter, half, hour, day, week, month
|
|
});
|
|
|
|
it("should render DateCalendar components", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
type: "inline",
|
|
},
|
|
});
|
|
expect(wrapper.findComponent({ name: "DateCalendar" }).exists()).toBe(true);
|
|
});
|
|
|
|
it("should render two DateCalendar components for range", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
type: "inline",
|
|
},
|
|
});
|
|
const calendars = wrapper.findAllComponents({ name: "DateCalendar" });
|
|
expect(calendars).toHaveLength(1);
|
|
});
|
|
|
|
it("should render buttons when showButtons is true", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
showButtons: true,
|
|
type: "inline",
|
|
},
|
|
});
|
|
expect(wrapper.find(".datepicker__buttons").exists()).toBe(true);
|
|
});
|
|
|
|
it("should not render buttons when showButtons is false", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
showButtons: false,
|
|
type: "inline",
|
|
},
|
|
});
|
|
expect(wrapper.find(".datepicker__buttons").exists()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("Event Handling", () => {
|
|
it("should emit clear event when clear button is clicked", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
clearable: true,
|
|
value: mockDate,
|
|
},
|
|
});
|
|
await wrapper.find(".datepicker-close").trigger("click");
|
|
expect(wrapper.emitted("clear")).toBeTruthy();
|
|
});
|
|
|
|
it("should handle DateCalendar ok event", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
type: "inline",
|
|
},
|
|
});
|
|
const calendar = wrapper.findComponent({ name: "DateCalendar" });
|
|
calendar.vm.$emit("ok", true);
|
|
expect(wrapper.emitted("input")).toBeTruthy();
|
|
});
|
|
|
|
it("should handle DateCalendar setDates event", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
type: "inline",
|
|
},
|
|
});
|
|
const calendar = wrapper.findComponent({ name: "DateCalendar" });
|
|
calendar.vm.$emit("setDates", mockDate, "left");
|
|
expect(wrapper.vm.dates[0]).toEqual(mockDate);
|
|
});
|
|
|
|
it("should handle submit button click", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
showButtons: true,
|
|
type: "inline",
|
|
},
|
|
});
|
|
await wrapper.find(".datepicker__button-select").trigger("click");
|
|
expect(wrapper.emitted("confirm")).toBeTruthy();
|
|
});
|
|
|
|
it("should handle cancel button click", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
showButtons: true,
|
|
type: "inline",
|
|
},
|
|
});
|
|
await wrapper.find(".datepicker__button-cancel").trigger("click");
|
|
expect(wrapper.emitted("cancel")).toBeTruthy();
|
|
});
|
|
|
|
it("should handle quick pick button clicks", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
type: "inline",
|
|
maxRange: [new Date(2024, 0, 1), new Date(2024, 0, 31)],
|
|
},
|
|
});
|
|
|
|
// Force range mode by setting dates directly
|
|
wrapper.vm.dates = [new Date(), new Date()];
|
|
await nextTick();
|
|
|
|
// Find and click a quick pick button
|
|
const buttons = wrapper.findAll(".datepicker-popup__shortcut");
|
|
const quarterButton = buttons.find((btn: any) => btn.text().includes("Quarter Hour"));
|
|
|
|
if (quarterButton) {
|
|
await quarterButton.trigger("click");
|
|
await nextTick();
|
|
expect(wrapper.vm.selectedShortcut).toBe("quarter");
|
|
} else {
|
|
// If not in range mode, test the quickPick method directly
|
|
wrapper.vm.quickPick("quarter");
|
|
expect(wrapper.vm.selectedShortcut).toBe("quarter");
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Lifecycle", () => {
|
|
it("should add document event listener on mount", () => {
|
|
const addEventListenerSpy = vi.spyOn(document, "addEventListener");
|
|
wrapper = mount(TimePicker);
|
|
expect(addEventListenerSpy).toHaveBeenCalledWith("click", expect.any(Function), true);
|
|
addEventListenerSpy.mockRestore();
|
|
});
|
|
|
|
it("should remove document event listener on unmount", () => {
|
|
const removeEventListenerSpy = vi.spyOn(document, "removeEventListener");
|
|
wrapper = mount(TimePicker);
|
|
wrapper.unmount();
|
|
expect(removeEventListenerSpy).toHaveBeenCalledWith("click", expect.any(Function), true);
|
|
removeEventListenerSpy.mockRestore();
|
|
});
|
|
|
|
it("should initialize dates from props value", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDate,
|
|
},
|
|
});
|
|
expect(wrapper.vm.dates).toHaveLength(1);
|
|
expect(wrapper.vm.inputDates).toHaveLength(1);
|
|
});
|
|
|
|
it("should initialize dates from array value", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
},
|
|
});
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
expect(wrapper.vm.inputDates).toHaveLength(2);
|
|
});
|
|
|
|
it("should watch for value prop changes", async () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDate,
|
|
},
|
|
});
|
|
|
|
await wrapper.setProps({ value: mockDateRange });
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
});
|
|
});
|
|
|
|
describe("Edge Cases", () => {
|
|
it("should handle null value", () => {
|
|
wrapper = mount(TimePicker as any, {
|
|
props: {
|
|
value: null,
|
|
},
|
|
});
|
|
expect(wrapper.vm.dates).toHaveLength(1);
|
|
});
|
|
|
|
it("should handle undefined value", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: undefined,
|
|
},
|
|
});
|
|
expect(wrapper.vm.dates).toHaveLength(1);
|
|
});
|
|
|
|
it("should handle empty array value", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: [],
|
|
},
|
|
});
|
|
expect(wrapper.vm.dates).toHaveLength(2);
|
|
});
|
|
|
|
it("should handle single item array", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: [mockDate],
|
|
},
|
|
});
|
|
expect(wrapper.vm.dates).toHaveLength(1);
|
|
});
|
|
|
|
it("should handle string value", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: "2024-01-15",
|
|
},
|
|
});
|
|
expect(wrapper.vm.dates).toHaveLength(1);
|
|
});
|
|
|
|
it("should handle invalid date string", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: "invalid-date",
|
|
},
|
|
});
|
|
expect(wrapper.vm.dates).toHaveLength(1);
|
|
expect(wrapper.vm.dates[0]).toBeInstanceOf(Date);
|
|
});
|
|
});
|
|
|
|
describe("Accessibility", () => {
|
|
it("should have proper tabindex on popup", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
type: "inline",
|
|
},
|
|
});
|
|
|
|
const popup = wrapper.find(".datepicker-popup");
|
|
expect(popup.attributes("tabindex")).toBe("-1");
|
|
});
|
|
|
|
it("should have proper button types", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
showButtons: true,
|
|
type: "inline",
|
|
},
|
|
});
|
|
|
|
const submitButton = wrapper.find(".datepicker__button-select");
|
|
const cancelButton = wrapper.find(".datepicker__button-cancel");
|
|
|
|
expect(submitButton.element.tagName).toBe("BUTTON");
|
|
expect(cancelButton.element.tagName).toBe("BUTTON");
|
|
});
|
|
|
|
it("should have proper button types for quick pick", () => {
|
|
wrapper = mount(TimePicker, {
|
|
props: {
|
|
value: mockDateRange,
|
|
type: "inline",
|
|
},
|
|
});
|
|
|
|
const quickPickButtons = wrapper.findAll(".datepicker-popup__shortcut");
|
|
quickPickButtons.forEach((button: any) => {
|
|
expect(button.attributes("type")).toBe("button");
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Internationalization", () => {
|
|
it("should use i18n translations", () => {
|
|
wrapper = mount(TimePicker);
|
|
|
|
expect(wrapper.vm.local.cancelTip).toBe("Cancel");
|
|
expect(wrapper.vm.local.submitTip).toBe("Confirm");
|
|
expect(wrapper.vm.local.quarterHourCutTip).toBe("Quarter Hour");
|
|
expect(wrapper.vm.local.halfHourCutTip).toBe("Half Hour");
|
|
expect(wrapper.vm.local.hourCutTip).toBe("Hour");
|
|
expect(wrapper.vm.local.dayCutTip).toBe("Day");
|
|
expect(wrapper.vm.local.weekCutTip).toBe("Week");
|
|
expect(wrapper.vm.local.monthCutTip).toBe("Month");
|
|
});
|
|
|
|
it("should handle month names correctly", () => {
|
|
wrapper = mount(TimePicker);
|
|
|
|
expect(wrapper.vm.local.monthsHead).toHaveLength(12);
|
|
expect(wrapper.vm.local.months).toHaveLength(12);
|
|
expect(wrapper.vm.local.weeks).toHaveLength(7);
|
|
});
|
|
});
|
|
});
|