fix(housekeeping): preserve radio key compatibility
This commit is contained in:
1 parent
9b83cdc3c3
commit
36ac116dc2
2 files changed
+55
-5
No files matched your search
@@ -1,3 +1,4 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import type { SQL } from "drizzle-orm";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { HousekeepingCapabilityContext } from "../../../foundation/contracts";
|
||||
@@ -52,6 +53,24 @@ const context = {
|
||||
legacy: true,
|
||||
};
|
||||
|
||||
function readCuratedRadioSettingKeys(): string[] {
|
||||
const pagePath = new URL(
|
||||
"../../../../../app/admin/radio/settings/page.tsx",
|
||||
import.meta.url,
|
||||
);
|
||||
const source = readFileSync(pagePath, "utf8");
|
||||
const groupsStart = source.indexOf("const GROUPS: Group[] = [");
|
||||
const groupsEnd = source.indexOf("const CURATED_KEYS", groupsStart);
|
||||
if (groupsStart < 0 || groupsEnd < 0) {
|
||||
throw new Error("Radio settings GROUPS source contract was not found");
|
||||
}
|
||||
|
||||
return Array.from(
|
||||
source.slice(groupsStart, groupsEnd).matchAll(/\bkey:\s*"([^"]+)"/g),
|
||||
(match) => match[1],
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
state.rows = [];
|
||||
state.writes = [];
|
||||
@@ -69,6 +88,34 @@ describe("Hotel radio settings runtime", () => {
|
||||
expect(state.writes).toEqual([]);
|
||||
});
|
||||
|
||||
it.each(["radio_custom-setting.v2", "auto_dj_vendor:key/variant"])(
|
||||
"accepts an existing custom prefixed setting key: %s",
|
||||
async (key) => {
|
||||
await executeHotelMutationOperation(
|
||||
"radio.settings.save-one",
|
||||
{ key, value: "configured" },
|
||||
context,
|
||||
);
|
||||
expect(state.writes).toEqual([
|
||||
expect.objectContaining({ key, value: "configured" }),
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(["Radio_name", "AUTO_DJ_mode"])(
|
||||
"rejects an uppercase setting prefix: %s",
|
||||
async (key) => {
|
||||
await expect(
|
||||
executeHotelMutationOperation(
|
||||
"radio.settings.save-one",
|
||||
{ key, value: "configured" },
|
||||
context,
|
||||
),
|
||||
).rejects.toBeInstanceOf(HotelMutationFailure);
|
||||
expect(state.writes).toEqual([]);
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects duplicate and invalid bulk entries atomically", async () => {
|
||||
for (const entries of [
|
||||
[
|
||||
@@ -92,10 +139,13 @@ describe("Hotel radio settings runtime", () => {
|
||||
});
|
||||
|
||||
it("accepts the complete 102-entry curated form within the 500-entry bound", async () => {
|
||||
const entries = Array.from({ length: 102 }, (_, index) => ({
|
||||
key: `radio_curated_${index}`,
|
||||
const keys = readCuratedRadioSettingKeys();
|
||||
const entries = keys.map((key, index) => ({
|
||||
key,
|
||||
value: `value-${index}`,
|
||||
}));
|
||||
expect(keys).toHaveLength(102);
|
||||
expect(new Set(keys).size).toBe(102);
|
||||
|
||||
await executeHotelMutationOperation(
|
||||
"radio.settings.save-many",
|
||||
@@ -103,7 +153,7 @@ describe("Hotel radio settings runtime", () => {
|
||||
context,
|
||||
);
|
||||
|
||||
expect(state.writes).toHaveLength(102);
|
||||
expect(state.writes.map(({ key }) => key)).toEqual(keys);
|
||||
});
|
||||
|
||||
it("rejects a bulk request above 500 entries", async () => {
|
||||
|
||||
@@ -127,8 +127,8 @@ const roomRuntimeSchema = z
|
||||
})
|
||||
.strict();
|
||||
|
||||
const settingKey = requiredText(255).refine((key) =>
|
||||
/^(?:radio_|auto_dj_)[a-z0-9_]+$/i.test(key),
|
||||
const settingKey = requiredText(255).refine(
|
||||
(key) => key.startsWith("radio_") || key.startsWith("auto_dj_"),
|
||||
);
|
||||
const settingSchema = z
|
||||
.object({
|
||||
|
||||
Reference in new issue
Block a user