vueless
Version:
Vue Styleless UI Component Library, powered by Tailwind CSS.
277 lines (212 loc) • 8.42 kB
text/typescript
import { mount } from "@vue/test-utils";
import { describe, it, expect, afterEach } from "vitest";
import UNotify from "../UNotify.vue";
import UIcon from "../../ui.image-icon/UIcon.vue";
import { NotificationType } from "../constants";
import { LocaleSymbol } from "../../composables/useLocale";
import { createVuelessAdapter } from "../../adapter.locale/vueless";
import type { Props, Notification } from "../types";
describe("UNotify.vue", () => {
// Create mock locale instance
const mockLocale = createVuelessAdapter();
// Helper function to mount component with locale
function mountWithLocale(props = {}) {
return mount(UNotify, {
props,
global: {
provide: {
[LocaleSymbol]: mockLocale,
},
},
});
}
// Mock notification data
const mockNotification: Notification = {
id: "test-id",
type: NotificationType.Success,
label: "Success",
description: "Operation completed successfully",
};
// Mock window event dispatch
function dispatchNotifyEvent(eventName: string, detail: Notification) {
const event = new CustomEvent(eventName, { detail });
window.dispatchEvent(event);
}
// Clean up after each test
afterEach(() => {
dispatchNotifyEvent("notifyClearAll", {} as Notification);
});
// Props tests
describe("Props", () => {
// XPosition prop
it("applies the correct xPosition style", async () => {
const positions = ["left", "center", "right"];
for (const position of positions) {
const component = mountWithLocale({
xPosition: position as Props["xPosition"],
});
// Add a notification to ensure the component is rendered
dispatchNotifyEvent("notifyStart", mockNotification);
await component.vm.$nextTick();
// Check the component's style directly
const style = component.attributes("style") || "";
// For center position, we expect a calculated left value
if (position === "center") {
expect(style).toContain("left:");
} else {
expect(style).toContain(`${position}: 0px`);
}
}
});
// YPosition prop
it("applies the correct yPosition style", async () => {
const positions = ["top", "bottom"];
for (const position of positions) {
const component = mountWithLocale({
yPosition: position as Props["yPosition"],
});
// Add a notification to ensure the component is rendered
dispatchNotifyEvent("notifyStart", mockNotification);
await component.vm.$nextTick();
// Check the component's style directly
const style = component.attributes("style") || "";
expect(style).toContain(`${position}: 0px`);
}
});
// DataTest prop
it("applies the correct data-test attribute", () => {
const dataTest = "test-notify";
const component = mountWithLocale({
dataTest,
});
expect(component.attributes("data-test")).toBe(dataTest);
});
});
// Event handling tests
describe("Event Handling", () => {
// notifyStart event
it("adds notification when notifyStart event is dispatched", async () => {
const component = mountWithLocale();
dispatchNotifyEvent("notifyStart", mockNotification);
await component.vm.$nextTick();
expect(component.text()).toContain(mockNotification.label);
expect(component.text()).toContain(mockNotification.description);
});
// notifyEnd event
it("removes notification when notifyEnd event is dispatched", async () => {
const component = mountWithLocale();
// Add notification
dispatchNotifyEvent("notifyStart", mockNotification);
await component.vm.$nextTick();
// Verify it's added
expect(component.text()).toContain(mockNotification.label);
// Get the initial notification count
const initialCount = component.findAllComponents(UIcon).length;
expect(initialCount).toBeGreaterThan(0);
// Remove notification
dispatchNotifyEvent("notifyEnd", mockNotification);
await component.vm.$nextTick();
await new Promise((resolve) => setTimeout(resolve, 0)); // Wait for any async updates
// Verify the notification count has decreased
const finalCount = component.findAllComponents(UIcon).length;
expect(finalCount).toBeLessThan(initialCount);
});
// notifyClearAll event
it("clears all notifications when notifyClearAll event is dispatched", async () => {
const component = mountWithLocale();
// Add multiple notifications
dispatchNotifyEvent("notifyStart", {
...mockNotification,
id: "id1",
label: "Notification 1",
});
dispatchNotifyEvent("notifyStart", {
...mockNotification,
id: "id2",
label: "Notification 2",
});
await component.vm.$nextTick();
// Verify they're added
expect(component.text()).toContain("Notification 1");
expect(component.text()).toContain("Notification 2");
// Clear all notifications
dispatchNotifyEvent("notifyClearAll", {} as Notification);
await component.vm.$nextTick();
// Verify they're all removed
expect(component.text()).not.toContain("Notification 1");
expect(component.text()).not.toContain("Notification 2");
});
// Close button click
it("removes notification when close button is clicked", async () => {
const component = mountWithLocale();
// Add notification
dispatchNotifyEvent("notifyStart", mockNotification);
await component.vm.$nextTick();
// Verify it's added
expect(component.text()).toContain(mockNotification.label);
// Directly call the onClickClose method as a fallback for testing
// @ts-expect-error - Accessing private property for testing
if (component.vm.notifications.length > 0) {
// @ts-expect-error - Accessing private method for testing
component.vm.onClickClose(mockNotification);
await component.vm.$nextTick();
}
// Verify the notification was removed from the internal array
// @ts-expect-error - Accessing private property for testing
expect(component.vm.notifications.length).toBe(0);
});
});
// Notification type tests
describe("Notification Types", () => {
// Success notification
it("renders success notification with correct icon", async () => {
const component = mountWithLocale();
dispatchNotifyEvent("notifyStart", {
...mockNotification,
type: NotificationType.Success,
});
await component.vm.$nextTick();
const icons = component.findAllComponents(UIcon);
expect(icons.length).toBeGreaterThan(0);
// Find the success icon by its name prop
const successIcon = icons.find((icon) => icon.props("name") === "check_circle");
expect(successIcon).toBeDefined();
});
// Warning notification
it("renders warning notification with correct icon", async () => {
const component = mountWithLocale();
dispatchNotifyEvent("notifyStart", {
...mockNotification,
type: NotificationType.Warning,
});
await component.vm.$nextTick();
const icons = component.findAllComponents(UIcon);
expect(icons.length).toBeGreaterThan(0);
// Find the warning icon by its name prop
const warningIcon = icons.find((icon) => icon.props("name") === "warning");
expect(warningIcon).toBeDefined();
});
// Error notification
it("renders error notification with correct icon", async () => {
const component = mountWithLocale();
dispatchNotifyEvent("notifyStart", {
...mockNotification,
type: NotificationType.Error,
});
await component.vm.$nextTick();
const icons = component.findAllComponents(UIcon);
expect(icons.length).toBeGreaterThan(0);
// Find the error icon by its name prop
const errorIcon = icons.find((icon) => icon.props("name") === "error");
expect(errorIcon).toBeDefined();
});
});
// Exposed refs tests
describe("Exposed refs", () => {
// notificationRef
it("exposes notificationRef", () => {
const component = mountWithLocale();
expect(component.vm.notificationRef).toBeDefined();
});
});
});