Newer
Older
gnexus-ui-kit / tests / unit / gn-toast-provider.spec.js
@Eugene Sukhodolskiy Eugene Sukhodolskiy 1 day ago 3 KB Add Vue adapter behavior contract tests
import { beforeEach, describe, expect, it } from "vitest";
import { mount } from "@vue/test-utils";
import { defineComponent, h, nextTick } from "vue";
import GnToastProvider from "../../src/vue/components/GnToastProvider.js";
import { useToast } from "../../src/vue/composables/useToast.js";
import { raf } from "../setup.js";

let toast;

const Host = defineComponent({
	setup() {
		toast = useToast();
		return () => h("div", { class: "host" });
	}
});

const mountProvider = (props = {}) => {
	const wrapper = mount(GnToastProvider, {
		props,
		slots: { default: () => h(Host) },
		attachTo: document.body
	});
	return wrapper;
};

beforeEach(() => {
	document.body.innerHTML = "";
});

describe("GnToastProvider", () => {
	it("shows one toast at a time: a new toast replaces the previous one", async () => {
		const wrapper = mountProvider({ lifetime: 0 });

		toast.success({ title: "First" });
		await nextTick();
		await raf();
		let toasts = document.querySelectorAll(".toast");
		expect(toasts).toHaveLength(1);
		expect(toasts[0].textContent).toContain("First");
		expect(toasts[0].className).toContain("a-show");

		toast.success({ title: "Second" });
		await nextTick();
		await raf();
		toasts = document.querySelectorAll(".toast");
		expect(toasts).toHaveLength(1);
		expect(toasts[0].textContent).toContain("Second");
		expect(toasts[0].textContent).not.toContain("First");
		wrapper.unmount();
	});

	it("maps variants and icons, renders the progress bar when lifetime > 0", async () => {
		const wrapper = mountProvider({ lifetime: 4000 });

		toast.error({ title: "Boom" });
		await nextTick();
		await raf();

		const node = document.querySelector(".toast");
		expect(node.className).toContain("toast-danger");
		expect(node.className).not.toContain("toast-error");
		expect(node.querySelector(".toast-progress-bar")).not.toBeNull();
		wrapper.unmount();
	});

	it("omits the progress bar when lifetime is 0", async () => {
		const wrapper = mountProvider({ lifetime: 0 });

		toast.info({ title: "Sticky" });
		await nextTick();
		await raf();

		expect(document.querySelector(".toast")).not.toBeNull();
		expect(document.querySelector(".toast-progress")).toBeNull();
		wrapper.unmount();
	});

	it("close() removes the toast immediately", async () => {
		const wrapper = mountProvider({ lifetime: 4000 });

		toast.warning({ title: "Notice" });
		await nextTick();
		await raf();
		expect(document.querySelector(".toast")).not.toBeNull();

		toast.close();
		await nextTick();
		expect(document.querySelector(".toast")).toBeNull();
		wrapper.unmount();
	});

	it("renders text when only text is passed", async () => {
		const wrapper = mountProvider({ lifetime: 0 });

		toast.info({ text: "Plain body" });
		await nextTick();
		await raf();

		expect(document.querySelector(".toast-text")?.textContent).toBe("Plain body");
		wrapper.unmount();
	});
});

describe("useToast without a provider", () => {
	it("throws with a helpful message", () => {
		let lonelyToast;
		const Lonely = defineComponent({
			setup() {
				lonelyToast = useToast();
				return () => null;
			}
		});
		mount(Lonely);

		expect(() => lonelyToast.success({ title: "x" })).toThrow("<GnToastProvider>");
	});
});