UNPKG

@embeddable.com/sdk-core

Version:

Core Embeddable SDK module responsible for web-components bundling and publishing.

219 lines (198 loc) 6.7 kB
// buildGlobalHooks.int.test.ts import { describe, it, expect, beforeEach, vi } from "vitest"; import * as fs from "node:fs/promises"; import * as fsSync from "node:fs"; import * as vite from "vite"; import { getGlobalHooksMeta, getComponentLibraryConfig, getContentHash, } from "@embeddable.com/sdk-utils"; import buildGlobalHooks from "../src/buildGlobalHooks"; import type { ResolvedEmbeddableConfig } from "./defineConfig"; import path from "node:path"; const rootDir = path.resolve("fake", "root"); const buildDir = path.resolve("fake", "build"); const tmpDir = path.resolve("fake", "tmp"); const srcDir = path.resolve("fake", "src"); const lifecycleFile = path.resolve("fake", "root", "embeddable.lifecycle.ts"); const themFile = path.resolve("fake", "root", "embeddable.theme.ts"); // Potential partial mocks, or we can let some logic run real vi.mock("node:fs/promises"); vi.mock("node:fs"); vi.mock("vite"); vi.mock("@embeddable.com/sdk-utils", async () => { const actual = await vi.importActual< typeof import("@embeddable.com/sdk-utils") >("@embeddable.com/sdk-utils"); return { ...actual, getGlobalHooksMeta: vi.fn(), getComponentLibraryConfig: vi.fn(), getContentHash: vi.fn(), }; }); describe("buildGlobalHooks (Integration Tests)", () => { beforeEach(() => { vi.clearAllMocks(); }); it("builds aggregator and lifecycle for multiple libraries, then saves meta", async () => { // We pretend that the lifecycle file does exist vi.spyOn(fsSync, "existsSync").mockImplementation((p: any) => { // We'll say yes for lifecycle + local theme if (p === lifecycleFile) return true; if (p === themFile) return true; return false; }); // aggregator template or any read (fs.readFile as any).mockResolvedValueOnce( "{{LIBRARY_THEME_IMPORTS}}{{LOCAL_THEME_IMPORT}}", ); // Suppose subsequent reads for the entry files also return "some content" (fs.readFile as any).mockResolvedValue("some content"); // We hash them all (getContentHash as any).mockReturnValue("123abc"); // Suppose vite.build calls are successful (vite.build as any).mockResolvedValue(undefined); // For each library (getComponentLibraryConfig as any).mockImplementation((cfg: any) => ({ libraryName: cfg.name, })); (getGlobalHooksMeta as any) // aggregator calls for library #1 .mockResolvedValueOnce({ themeProvider: "libA-theme.js", lifecycleHooks: ["libA-lifecycle.js"], }) // aggregator calls for library #2 .mockResolvedValueOnce({ themeProvider: "libB-theme.js", lifecycleHooks: [], }) // lifecycle calls for library #1 .mockResolvedValueOnce({ themeProvider: "libA-theme.js", lifecycleHooks: ["libA-lifecycle.js"], }) // lifecycle calls for library #2 .mockResolvedValueOnce({ themeProvider: "libB-theme.js", lifecycleHooks: ["libB-lifecycle.js"], }); const ctx: ResolvedEmbeddableConfig = { client: { srcDir, buildDir, tmpDir, rootDir, lifecycleHooksFile: lifecycleFile, customizationFile: themFile, componentLibraries: [{ name: "libA" }, { name: "libB" }], }, core: { templatesDir: "/fake/templates", }, dev: { watch: false, // so we do hashing, no watchers }, } as any; await buildGlobalHooks(ctx); // aggregator => built with "embeddable-theme-123abc" expect(vite.build).toHaveBeenCalledWith( expect.objectContaining({ build: expect.objectContaining({ lib: expect.objectContaining({ entry: expect.stringContaining("embeddableThemeHook.js"), fileName: "embeddable-theme-123abc", }), }), }), ); // We also expect the lifecycle for the repo => "embeddable.lifecycle.ts" expect(vite.build).toHaveBeenCalledWith( expect.objectContaining({ build: expect.objectContaining({ lib: expect.objectContaining({ entry: lifecycleFile, fileName: "embeddable-lifecycle", // or with hash if code does that }), }), }), ); // library #1 => has "libA-lifecycle.js" // library #2 => has "libB-lifecycle.js" // so we expect them to build also expect(vite.build).toHaveBeenCalledWith( expect.objectContaining({ build: expect.objectContaining({ lib: expect.objectContaining({ entry: path.resolve( rootDir, "node_modules", "libA", "dist", "libA-lifecycle.js", ), }), }), }), ); expect(vite.build).toHaveBeenCalledWith( expect.objectContaining({ build: expect.objectContaining({ lib: expect.objectContaining({ entry: path.resolve( rootDir, "node_modules", "libB", "dist", "libB-lifecycle.js", ), }), }), }), ); // You might also check the final "saveGlobalHooksMeta" by reading the file or checking fsSync calls // ... }); it("skips aggregator if no library has themeProvider, no local theme", async () => { vi.spyOn(fsSync, "existsSync").mockImplementation((p: any) => false); (fs.readFile as any).mockResolvedValueOnce("{{LIBRARY_THEME_IMPORTS}}"); (getContentHash as any).mockReturnValue("someHash"); (vite.build as any).mockResolvedValue(undefined); (getGlobalHooksMeta as any) // aggregator calls: .mockResolvedValueOnce({ themeProvider: null, lifecycleHooks: [] }) // lifecycle calls: .mockResolvedValueOnce({ themeProvider: null, lifecycleHooks: [] }); (getComponentLibraryConfig as any).mockImplementation((cfg: any) => ({ libraryName: cfg.name, })); const ctx: ResolvedEmbeddableConfig = { client: { srcDir, buildDir, tmpDir, rootDir, lifecycleHooksFile: lifecycleFile, customizationFile: themFile, componentLibraries: [{ name: "libA" }], }, core: { templatesDir: "/fake/templates", }, dev: { watch: false }, } as any; await buildGlobalHooks(ctx); // aggregator not built expect(vite.build).not.toHaveBeenCalledWith( expect.objectContaining({ build: expect.objectContaining({ lib: expect.objectContaining({ entry: expect.stringContaining("embeddableThemeHook.js"), }), }), }), ); }); });