UNPKG

@embeddable.com/sdk-core

Version:

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

168 lines (136 loc) 5.28 kB
import path from "node:path"; import { describe, it, expect, vi, beforeEach } from "vitest"; import * as fs from "node:fs/promises"; import * as fsSync from "node:fs"; import process from "node:process"; import buildPackage from "./buildPackage"; import buildTypes from "./buildTypes"; import buildGlobalHooks from "./buildGlobalHooks"; import provideConfig from "./provideConfig"; import { checkNodeVersion, removeBuildSuccessFlag, storeBuildSuccessFlag, } from "./utils"; import { initLogger, logError } from "./logger"; import { ResolvedEmbeddableConfig } from "./defineConfig"; // ----------------- MOCKS ----------------- // vi.mock("node:fs/promises"); vi.mock("node:fs"); // Mock buildTypes vi.mock("./buildTypes", () => ({ default: vi.fn(), })); // Mock buildGlobalHooks vi.mock("./buildGlobalHooks", () => ({ default: vi.fn(), })); // Mock provideConfig vi.mock("./provideConfig", () => ({ default: vi.fn(), })); // Mock utils vi.mock("./utils", async () => { const actualUtils = await vi.importActual<typeof import("./utils")>("./utils"); return { ...actualUtils, checkNodeVersion: vi.fn(), removeBuildSuccessFlag: vi.fn(), storeBuildSuccessFlag: vi.fn(), }; }); // Mock logger vi.mock("./logger", () => ({ initLogger: vi.fn().mockResolvedValue(undefined), logError: vi.fn().mockResolvedValue(undefined), })); // ----------------- TESTS ----------------- // describe("buildPackage", () => { // We'll create a sample plugin for testing const mockPlugin = { pluginName: "testPlugin", validate: vi.fn(), buildPackage: vi.fn(), }; const rootDir = path.resolve("fake", "root"); const buildDir = path.resolve("fake", "build"); const distDir = path.resolve(rootDir, "dist"); // We'll also create a sample config const config = { client: { rootDir, buildDir, }, plugins: [() => mockPlugin], } as unknown as ResolvedEmbeddableConfig; beforeEach(() => { // Clear mocks before each test to avoid cross-test interference vi.clearAllMocks(); // By default, provideConfig will return our sample config vi.mocked(provideConfig).mockResolvedValue(config); // Let's ensure fsSync.existsSync returns false by default // (so that our prepare() logic tries to mkdir, etc.) vi.spyOn(fsSync, "existsSync").mockReturnValue(false); }); it("should call all main steps in a successful scenario", async () => { await buildPackage(); // 1. Logger expect(initLogger).toHaveBeenCalledWith("package"); // 2. checkNodeVersion and removeBuildSuccessFlag expect(checkNodeVersion).toHaveBeenCalled(); expect(removeBuildSuccessFlag).toHaveBeenCalled(); // 3. provideConfig -> must be called, returns our config expect(provideConfig).toHaveBeenCalled(); // 4. prepare() logic -> it checks if buildDir exists, removes if so, then mkdir // Because we do cross-platform checks, we confirm the path used is distDir expect(fsSync.existsSync).toHaveBeenCalledWith(distDir); // Because it returned false, we do not remove expect(fs.rm).toHaveBeenCalledTimes(0); // Instead we create it expect(fs.mkdir).toHaveBeenCalledWith(distDir); // 5. buildTypes & buildGlobalHooks expect(buildTypes).toHaveBeenCalledWith(config); expect(buildGlobalHooks).toHaveBeenCalledWith(config); // 6. Plugin calls expect(mockPlugin.validate).toHaveBeenCalledWith(config); expect(mockPlugin.buildPackage).toHaveBeenCalledWith(config); // 7. storeBuildSuccessFlag expect(storeBuildSuccessFlag).toHaveBeenCalled(); }); it("should remove and recreate buildDir if it already exists", async () => { // This time let's simulate that buildDir already exists vi.mocked(fsSync.existsSync).mockReturnValue(true); await buildPackage(); // Because buildDir exists, prepare() should remove it expect(fs.rm).toHaveBeenCalledWith(distDir, { recursive: true }); // Then re-create it expect(fs.mkdir).toHaveBeenCalledWith(distDir); }); it("should log an error, call logError, and exit(1) if an error occurs", async () => { // We'll simulate an error in removeBuildSuccessFlag const error = new Error("test error"); vi.mocked(removeBuildSuccessFlag).mockRejectedValueOnce(error); // We want to check process.exit(1) is called // but calling exit actually kills the process, so we mock it const originalConsoleLog = console.log; console.log = vi.fn(); const exitSpy = vi.spyOn(process, "exit").mockImplementation(() => { throw new Error("process.exit called"); }); // We expect buildPackage to throw because exit is called await expect(buildPackage()).rejects.toThrow("process.exit called"); // We also expect that logError has been called with the correct params expect(logError).toHaveBeenCalledWith({ command: "package", breadcrumbs: ["checkNodeVersion"], // because it fails after calling checkNodeVersion error, }); // And the error is printed expect(console.log).toHaveBeenCalledWith(error); // Finally, we confirm process.exit(1) was triggered expect(process.exit).toHaveBeenCalledWith(1); console.log = originalConsoleLog; exitSpy.mockRestore(); }); });