@embeddable.com/sdk-core
Version:
Core Embeddable SDK module responsible for web-components bundling and publishing.
127 lines (98 loc) • 3.35 kB
text/typescript
import {
createWatcherLock,
preventContentLength,
waitUntilFileStable,
} from "./dev.utils";
import { ServerResponse } from "http";
import * as fs from "node:fs/promises";
import {createReadStream} from "node:fs";
import { Readable } from "node:stream";
vi.mock("node:fs/promises", async () => {
let size = 100;
return {
stat: vi.fn().mockImplementation(() => ({ size })),
};
});
vi.mock("node:fs", async () => ({
createReadStream: vi.fn()
}));
describe("preventContentLength", () => {
it("should not allow setting 'content-length' header", () => {
const headers: Record<string, string> = {};
const res = {
setHeader: (key: string, value: any) => {
headers[key.toLowerCase()] = value;
},
} as unknown as ServerResponse;
preventContentLength(res);
res.setHeader("content-length", "1234");
res.setHeader("x-custom-header", "abc");
expect(headers["content-length"]).toBeUndefined();
expect(headers["x-custom-header"]).toBe("abc");
});
});
describe("createWatcherLock", () => {
it("should block and unblock correctly", async () => {
const lock = createWatcherLock();
lock.lock();
let unlocked = false;
const waiter = lock.waitUntilFree().then(() => {
unlocked = true;
});
// Still locked
expect(unlocked).toBe(false);
lock.unlock();
// Wait for Promise resolution
await waiter;
expect(unlocked).toBe(true);
});
it("should resolve immediately if not locked", async () => {
const lock = createWatcherLock();
await expect(lock.waitUntilFree()).resolves.toBeUndefined();
});
it("should not resolve until unlock is called", async () => {
const lock = createWatcherLock();
lock.lock();
let resolved = false;
lock.waitUntilFree().then(() => {
resolved = true;
});
await new Promise((r) => setTimeout(r, 20));
expect(resolved).toBe(false);
lock.unlock();
await new Promise((r) => setTimeout(r, 0)); // allow promise to resolve
expect(resolved).toBe(true);
});
});
describe("waitUntilFileStable", () => {
it("should resolve when file becomes stable and has the expected tail", async () => {
const filePath = "mock/path.js";
const expectedTail = "sourceMappingURL";
let size = 10;
const mockStat = vi.fn().mockImplementation(() => {
return Promise.resolve({ size });
});
vi.mocked(fs.stat).mockImplementation(mockStat);
const streamData = "some data\n// sourceMappingURL=something.js";
vi.mocked(createReadStream).mockImplementation(() => {
return Readable.from([streamData]) as any;
});
await expect(waitUntilFileStable(filePath, expectedTail, {
maxAttempts: 5,
})).resolves.toBeUndefined();
expect(fs.stat).toHaveBeenCalled();
expect(createReadStream).toHaveBeenCalled();
});
it("should throw if file never stabilizes", async () => {
const filePath = "mock/path.js";
const expectedTail = "sourceMappingURL";
vi.mocked(fs.stat).mockResolvedValue({ size: 0 } as any);
vi.mocked(createReadStream).mockImplementation(() => {
return Readable.from([""]) as any;
});
await expect(waitUntilFileStable(filePath, expectedTail, {
maxAttempts: 3,
})).rejects.toThrow("File did not stabilize");
expect(fs.stat).toHaveBeenCalled();
});
});