mirror of
https://github.com/ecomfe/vue-echarts.git
synced 2025-10-27 10:55:07 +08:00
test: increase coverage and add codecov integration
This commit is contained in:
166
tests/wc.test.ts
Normal file
166
tests/wc.test.ts
Normal file
@ -0,0 +1,166 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
|
||||
declare global {
|
||||
interface HTMLElement {
|
||||
__dispose?: (() => void) | null;
|
||||
}
|
||||
}
|
||||
|
||||
type LoadOptions = { suffix?: string };
|
||||
|
||||
const loadModule = (() => {
|
||||
let counter = 0;
|
||||
return async (mode: "stub" | "native", options?: LoadOptions) => {
|
||||
const suffix = options?.suffix ?? `${mode}-${++counter}`;
|
||||
return import(/* @vite-ignore */ `../src/wc?${suffix}`);
|
||||
};
|
||||
})();
|
||||
|
||||
describe("register", () => {
|
||||
describe("with stubbed customElements", () => {
|
||||
class CustomElementRegistryStub {
|
||||
private readonly registry = new Map<string, CustomElementConstructor>();
|
||||
|
||||
define(name: string, ctor: CustomElementConstructor): void {
|
||||
if (this.registry.has(name)) {
|
||||
throw new DOMException("already defined", "NotSupportedError");
|
||||
}
|
||||
this.registry.set(name, ctor);
|
||||
}
|
||||
|
||||
get(name: string): CustomElementConstructor | undefined {
|
||||
return this.registry.get(name);
|
||||
}
|
||||
}
|
||||
|
||||
let registry: CustomElementRegistryStub;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetModules();
|
||||
vi.unstubAllGlobals();
|
||||
|
||||
registry = new CustomElementRegistryStub();
|
||||
vi.stubGlobal(
|
||||
"customElements",
|
||||
registry as unknown as CustomElementRegistry,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("returns false when custom elements are unavailable", async () => {
|
||||
vi.unstubAllGlobals();
|
||||
vi.stubGlobal(
|
||||
"customElements",
|
||||
undefined as unknown as CustomElementRegistry,
|
||||
);
|
||||
|
||||
const { register } = await loadModule("stub");
|
||||
|
||||
expect(register()).toBe(false);
|
||||
expect(register()).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false when browser APIs are disabled", async () => {
|
||||
vi.resetModules();
|
||||
// Simulate missing browser API by providing a registry without `get`
|
||||
vi.stubGlobal("customElements", {
|
||||
define() {},
|
||||
} as unknown as CustomElementRegistry);
|
||||
|
||||
const { register } = await loadModule("stub", { suffix: "no-get" });
|
||||
expect(register()).toBe(false);
|
||||
expect(register()).toBe(false);
|
||||
});
|
||||
|
||||
it("registers the custom element once", async () => {
|
||||
const defineSpy = vi.spyOn(registry, "define");
|
||||
|
||||
const { register, TAG_NAME } = await loadModule("stub");
|
||||
|
||||
expect(register()).toBe(true);
|
||||
expect(defineSpy).toHaveBeenCalledTimes(1);
|
||||
expect(registry.get(TAG_NAME)).toBeTypeOf("function");
|
||||
|
||||
defineSpy.mockClear();
|
||||
expect(register()).toBe(true);
|
||||
expect(defineSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("handles definition failures gracefully", async () => {
|
||||
const defineSpy = vi.spyOn(registry, "define").mockImplementation(() => {
|
||||
throw new Error("boom");
|
||||
});
|
||||
|
||||
const { register, TAG_NAME } = await loadModule("stub");
|
||||
|
||||
expect(register()).toBe(false);
|
||||
expect(register()).toBe(false);
|
||||
expect(defineSpy).toHaveBeenCalledTimes(1);
|
||||
expect(registry.get(TAG_NAME)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("skips redefinition when element already registered", async () => {
|
||||
const existing = class extends HTMLElement {};
|
||||
const { register, TAG_NAME } = await loadModule("stub");
|
||||
registry.define(TAG_NAME, existing);
|
||||
|
||||
const defineSpy = vi.spyOn(registry, "define");
|
||||
|
||||
expect(register()).toBe(true);
|
||||
expect(defineSpy).not.toHaveBeenCalled();
|
||||
expect(registry.get(TAG_NAME)).toBe(existing);
|
||||
});
|
||||
|
||||
it("exposes a constructor with disconnect hook", async () => {
|
||||
const { register, TAG_NAME } = await loadModule("stub");
|
||||
|
||||
expect(register()).toBe(true);
|
||||
|
||||
const ctor = registry.get(TAG_NAME);
|
||||
expect(typeof ctor).toBe("function");
|
||||
expect("disconnectedCallback" in (ctor?.prototype ?? {})).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with native customElements", () => {
|
||||
let original: CustomElementConstructor | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllGlobals();
|
||||
original = customElements.get("x-vue-echarts");
|
||||
document.body.innerHTML = "";
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = "";
|
||||
if (original) {
|
||||
customElements.define("x-vue-echarts", original);
|
||||
}
|
||||
});
|
||||
|
||||
it("disposes chart when element is removed from DOM", async () => {
|
||||
const { register, TAG_NAME } = await loadModule("native");
|
||||
|
||||
expect(register()).toBe(true);
|
||||
|
||||
const element = document.createElement(TAG_NAME) as HTMLElement & {
|
||||
__dispose: (() => void) | null;
|
||||
};
|
||||
const dispose = vi.fn();
|
||||
element.__dispose = dispose;
|
||||
|
||||
document.body.appendChild(element);
|
||||
document.body.removeChild(element);
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
expect(dispose).toHaveBeenCalledTimes(1);
|
||||
expect(element.__dispose).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user