Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline (Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/* packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
111 lines
3.9 KiB
TypeScript
111 lines
3.9 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const application = vi.hoisted(() => ({
|
|
nativeApplicationVersion: null as string | null,
|
|
nativeBuildVersion: null as string | null,
|
|
}));
|
|
|
|
const updates = vi.hoisted(() => ({
|
|
isEnabled: false,
|
|
isEmbeddedLaunch: true,
|
|
updateId: null as string | null,
|
|
channel: null as string | null,
|
|
createdAt: null as Date | null,
|
|
}));
|
|
|
|
const constants = vi.hoisted(() => ({
|
|
expoConfig: { version: "1.0.3" } as { version?: string } | null,
|
|
platform: {
|
|
ios: { buildNumber: "1" },
|
|
android: { versionCode: 10 },
|
|
} as {
|
|
ios?: { buildNumber: string | null };
|
|
android?: { versionCode: number };
|
|
},
|
|
}));
|
|
|
|
vi.mock("expo-application", () => application);
|
|
vi.mock("expo-updates", () => updates);
|
|
vi.mock("expo-constants", () => ({ default: constants }));
|
|
vi.mock("react-native", () => ({
|
|
Platform: { OS: "ios" },
|
|
}));
|
|
|
|
afterEach(() => {
|
|
application.nativeApplicationVersion = null;
|
|
application.nativeBuildVersion = null;
|
|
updates.isEnabled = false;
|
|
updates.isEmbeddedLaunch = true;
|
|
updates.updateId = null;
|
|
updates.channel = null;
|
|
updates.createdAt = null;
|
|
constants.expoConfig = { version: "1.0.3" };
|
|
constants.platform = {
|
|
ios: { buildNumber: "1" },
|
|
android: { versionCode: 10 },
|
|
};
|
|
vi.resetModules();
|
|
});
|
|
|
|
describe("app version footer helpers", () => {
|
|
it("formats native version with and without build", async () => {
|
|
const { formatNativeVersionLabel, shortUpdateId } = await import("./app-version");
|
|
expect(formatNativeVersionLabel("1.0.3", "10")).toBe("1.0.3 (10)");
|
|
expect(formatNativeVersionLabel("1.0.3", null)).toBe("1.0.3");
|
|
expect(formatNativeVersionLabel(null, "10")).toBe("10");
|
|
expect(formatNativeVersionLabel(" ", " ")).toBeNull();
|
|
expect(shortUpdateId("A1B2C3D4-E5F6-7890-ABCD-EF1234567890")).toBe("a1b2c3d4");
|
|
});
|
|
|
|
it("prefers expo-application values and labels embedded updates", async () => {
|
|
application.nativeApplicationVersion = "1.0.3";
|
|
application.nativeBuildVersion = "12";
|
|
updates.isEnabled = true;
|
|
updates.isEmbeddedLaunch = true;
|
|
const { formatUpdateLabel, getAppVersionInfo } = await import("./app-version");
|
|
const info = getAppVersionInfo();
|
|
expect(info.nativeLabel).toBe("1.0.3 (12)");
|
|
expect(info.update).toEqual({ kind: "embedded" });
|
|
expect(formatUpdateLabel(info.update, (message) => message)).toBe("Embedded");
|
|
});
|
|
|
|
it("falls back to Constants when Application is empty", async () => {
|
|
const { getAppVersionInfo } = await import("./app-version");
|
|
expect(getAppVersionInfo().nativeLabel).toBe("1.0.3 (1)");
|
|
});
|
|
|
|
it("summarizes an OTA update with channel and date", async () => {
|
|
application.nativeApplicationVersion = "1.0.3";
|
|
application.nativeBuildVersion = "12";
|
|
updates.isEnabled = true;
|
|
updates.isEmbeddedLaunch = false;
|
|
updates.updateId = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
|
|
updates.channel = "production";
|
|
updates.createdAt = new Date("2026-09-10T12:00:00.000Z");
|
|
const { formatUpdateLabel, getAppVersionInfo } = await import("./app-version");
|
|
const info = getAppVersionInfo();
|
|
expect(info.update).toEqual({
|
|
kind: "ota",
|
|
id: "a1b2c3d4",
|
|
channel: "production",
|
|
createdAt: "2026-09-10",
|
|
});
|
|
expect(
|
|
formatUpdateLabel(info.update, (message, values) => {
|
|
if (!values) return message;
|
|
return message.replace(/\{([A-Za-z0-9_]+)\}/g, (match, key: string) =>
|
|
Object.hasOwn(values, key) ? String(values[key]) : match,
|
|
);
|
|
}),
|
|
).toBe("production · a1b2c3d4 · 2026-09-10");
|
|
});
|
|
|
|
it("treats disabled updates as embedded", async () => {
|
|
updates.isEnabled = false;
|
|
updates.isEmbeddedLaunch = false;
|
|
updates.updateId = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
|
|
const { getAppVersionInfo } = await import("./app-version");
|
|
expect(getAppVersionInfo().update).toEqual({ kind: "embedded" });
|
|
});
|
|
});
|