Files
hyperframes/packages/cli/src/utils/submitFeedback.test.ts
T
Miguel Ángel 08934bfd55 revert(cli): keep HeyGen API traffic on stable prod (#3202)
* Revert "fix(cli): route HeyGen API calls through canary (#3201)"

This reverts commit 5545521556.

* fix(cli): remove remaining EF canary routes
2026-08-10 21:41:21 -04:00

101 lines
3.3 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const getPublishApiBaseUrlMock = vi.hoisted(() => vi.fn(() => "https://api.example.com"));
vi.mock("./publishProject.js", () => ({
getPublishApiBaseUrl: getPublishApiBaseUrlMock,
}));
import { submitFeedback } from "./submitFeedback.js";
describe("submitFeedback", () => {
beforeEach(() => {
getPublishApiBaseUrlMock.mockReturnValue("https://api.example.com");
});
afterEach(() => {
vi.clearAllMocks();
vi.unstubAllGlobals();
});
it("posts feedback to the backend endpoint", async () => {
const fetchMock = vi.fn<typeof fetch>(async () => new Response(null, { status: 202 }));
vi.stubGlobal("fetch", fetchMock);
await submitFeedback({
rating: 4,
comment: "fast but font missing",
cliVersion: "1.2.3",
env: "os=darwin/arm64 node=v22.11.0",
});
expect(fetchMock).toHaveBeenCalledOnce();
expect(getPublishApiBaseUrlMock).toHaveBeenCalledOnce();
expect(fetchMock).toHaveBeenCalledWith(
"https://api.example.com/v1/hyperframes/feedback",
expect.objectContaining({
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
rating: 4,
rating_scale: 10,
comment: "fast but font missing",
cli_version: "1.2.3",
env: "os=darwin/arm64 node=v22.11.0",
}),
signal: expect.any(AbortSignal),
}),
);
});
it.each([0, 10])("serializes the NPS boundary %i without changing it", async (rating) => {
const fetchMock = vi.fn<typeof fetch>(async () => new Response(null, { status: 202 }));
vi.stubGlobal("fetch", fetchMock);
await submitFeedback({ rating, cliVersion: "1.2.3" });
const requestInit = fetchMock.mock.calls[0]?.[1];
const body = JSON.parse(requestInit?.body as string);
expect(body).toMatchObject({ rating, rating_scale: 10 });
});
it("truncates over-long fields to the backend caps", async () => {
const fetchMock = vi.fn<typeof fetch>(async () => new Response(null, { status: 202 }));
vi.stubGlobal("fetch", fetchMock);
await submitFeedback({
rating: 3,
comment: "x".repeat(2500),
cliVersion: "v".repeat(200),
env: "e".repeat(600),
});
const requestInit = fetchMock.mock.calls[0]?.[1];
expect(requestInit).toBeDefined();
const body = JSON.parse(requestInit?.body as string);
expect(body.comment).toHaveLength(2000);
expect(body.cli_version).toHaveLength(100);
expect(body.env).toHaveLength(500);
});
it("does not reject when fetch rejects", async () => {
const fetchMock = vi.fn().mockRejectedValueOnce(new TypeError("fetch failed"));
vi.stubGlobal("fetch", fetchMock);
await expect(
submitFeedback({ rating: 1, cliVersion: "1.2.3", env: "os=linux" }),
).resolves.toBeUndefined();
});
it("always resolves regardless of fetch outcome", async () => {
const fetchMock = vi
.fn()
.mockResolvedValueOnce(new Response(null, { status: 500 }))
.mockRejectedValueOnce(new Error("offline"));
vi.stubGlobal("fetch", fetchMock);
await expect(submitFeedback({ rating: 2, cliVersion: "1.2.3" })).resolves.toBeUndefined();
await expect(submitFeedback({ rating: 3, cliVersion: "1.2.3" })).resolves.toBeUndefined();
});
});