167 lines
5.1 KiB
JavaScript
167 lines
5.1 KiB
JavaScript
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { __featureFlagTesting } from "./splitio-react-replacement";
|
|
|
|
const {
|
|
createFeatureFlagClient,
|
|
getNextScheduleRefreshDelay,
|
|
getLocalStorageKey,
|
|
isFeatureFlagChangeRelevant,
|
|
normalizeFlagValue,
|
|
readCachedFeatureFlags,
|
|
writeCachedFeatureFlags
|
|
} = __featureFlagTesting;
|
|
|
|
beforeEach(() => {
|
|
window.localStorage.clear();
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
describe("splitio-react-replacement feature flag normalization", () => {
|
|
it("returns off for unknown or null values", () => {
|
|
expect(normalizeFlagValue(null)).toEqual({ treatment: "off", config: null });
|
|
expect(normalizeFlagValue(undefined)).toEqual({ treatment: "off", config: null });
|
|
});
|
|
|
|
it("normalizes primitive values into Split-like treatments", () => {
|
|
expect(normalizeFlagValue(true)).toEqual({ treatment: "on", config: null });
|
|
expect(normalizeFlagValue(false)).toEqual({ treatment: "off", config: null });
|
|
expect(normalizeFlagValue(1)).toEqual({ treatment: "on", config: null });
|
|
expect(normalizeFlagValue(0)).toEqual({ treatment: "off", config: null });
|
|
expect(normalizeFlagValue("true")).toEqual({ treatment: "on", config: null });
|
|
expect(normalizeFlagValue("false")).toEqual({ treatment: "off", config: null });
|
|
expect(normalizeFlagValue("variant-a")).toEqual({ treatment: "variant-a", config: null });
|
|
});
|
|
|
|
it("preserves custom treatments and parses JSON config strings", () => {
|
|
expect(
|
|
normalizeFlagValue({
|
|
treatment: "demo",
|
|
config: "{\"limit\":25}"
|
|
})
|
|
).toEqual({
|
|
treatment: "demo",
|
|
config: { limit: 25 }
|
|
});
|
|
});
|
|
|
|
it("respects activeDate and deactiveDate windows", () => {
|
|
vi.useFakeTimers();
|
|
vi.setSystemTime(new Date("2026-05-19T15:00:00.000Z"));
|
|
|
|
expect(
|
|
normalizeFlagValue({
|
|
treatment: "on",
|
|
activeDate: "2026-05-19T14:59:00.000Z",
|
|
deactiveDate: "2026-05-19T15:01:00.000Z"
|
|
})
|
|
).toEqual({ treatment: "on", config: null });
|
|
|
|
expect(
|
|
normalizeFlagValue({
|
|
treatment: "on",
|
|
activeDate: "2026-05-19T15:01:00.000Z"
|
|
})
|
|
).toEqual({ treatment: "off", config: null });
|
|
|
|
expect(
|
|
normalizeFlagValue({
|
|
treatment: "on",
|
|
deactiveDate: "2026-05-19T15:00:00.000Z"
|
|
})
|
|
).toEqual({ treatment: "off", config: null });
|
|
|
|
vi.useRealTimers();
|
|
});
|
|
});
|
|
|
|
describe("splitio-react-replacement feature flag client", () => {
|
|
it("uses backend flags", () => {
|
|
const client = createFeatureFlagClient({
|
|
bodyshop: {
|
|
imexshopid: "APPLE"
|
|
},
|
|
backendFlags: {
|
|
Enhanced_Payroll: { treatment: "on" }
|
|
}
|
|
});
|
|
|
|
expect(client.getTreatment("Enhanced_Payroll")).toBe("on");
|
|
});
|
|
|
|
it("ignores old bodyshop feature JSON fallback values", () => {
|
|
const client = createFeatureFlagClient({
|
|
bodyshop: {
|
|
imexshopid: "APPLE",
|
|
features: {
|
|
featureFlags: {
|
|
Enhanced_Payroll: { treatment: "on" }
|
|
}
|
|
}
|
|
},
|
|
backendFlags: {}
|
|
});
|
|
|
|
expect(client.getTreatment("Enhanced_Payroll")).toBe("off");
|
|
});
|
|
|
|
it("returns off for flags that are not present in any source", () => {
|
|
const client = createFeatureFlagClient({
|
|
bodyshop: { imexshopid: "APPLE", features: {} },
|
|
backendFlags: {}
|
|
});
|
|
|
|
expect(client.getTreatment("Missing_Flag")).toBe("off");
|
|
});
|
|
|
|
it("uses a bodyshop-scoped browser cache key", () => {
|
|
expect(getLocalStorageKey("shop-1")).toBe("bodyshop-feature-flags:shop-1");
|
|
});
|
|
|
|
it("stores and reads last-known backend flags from browser storage", () => {
|
|
vi.useFakeTimers();
|
|
vi.setSystemTime(new Date("2026-05-19T15:00:00.000Z"));
|
|
|
|
writeCachedFeatureFlags("shop-1", {
|
|
Enhanced_Payroll: { treatment: "on", config: null }
|
|
});
|
|
|
|
expect(readCachedFeatureFlags("shop-1")).toEqual({
|
|
Enhanced_Payroll: { treatment: "on", config: null }
|
|
});
|
|
});
|
|
|
|
it("ignores expired browser cached flags", () => {
|
|
vi.useFakeTimers();
|
|
vi.setSystemTime(new Date("2026-05-19T15:00:00.000Z"));
|
|
|
|
writeCachedFeatureFlags("shop-1", {
|
|
Enhanced_Payroll: { treatment: "on", config: null }
|
|
});
|
|
|
|
expect(readCachedFeatureFlags("shop-1", Date.parse("2026-05-20T15:00:01.000Z"))).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("splitio-react-replacement live refresh helpers", () => {
|
|
it("matches global and bodyshop-scoped socket changes", () => {
|
|
expect(isFeatureFlagChangeRelevant({ scope: "global" }, "shop-1")).toBe(true);
|
|
expect(isFeatureFlagChangeRelevant({ bodyshopId: "shop-1", scope: "bodyshop" }, "shop-1")).toBe(true);
|
|
expect(isFeatureFlagChangeRelevant({ bodyshopId: "shop-2", scope: "bodyshop" }, "shop-1")).toBe(false);
|
|
});
|
|
|
|
it("finds the next active/deactive date boundary that needs a refresh", () => {
|
|
const now = Date.parse("2026-05-19T15:00:00.000Z");
|
|
|
|
expect(
|
|
getNextScheduleRefreshDelay(
|
|
{
|
|
Demo: { treatment: "on", activeDate: "2026-05-19T15:05:00.000Z" },
|
|
Expiring: { treatment: "on", deactiveDate: "2026-05-19T15:02:00.000Z" },
|
|
Expired: { treatment: "on", deactiveDate: "2026-05-19T14:59:00.000Z" }
|
|
},
|
|
now
|
|
)
|
|
).toBe(120050);
|
|
});
|
|
});
|