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 type { SQL } from "drizzle-orm";
|
||||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import type { HousekeepingCapabilityContext } from "../../../foundation/contracts";
|
import type { HousekeepingCapabilityContext } from "../../../foundation/contracts";
|
||||||
@@ -52,6 +53,24 @@ const context = {
|
|||||||
legacy: true,
|
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(() => {
|
beforeEach(() => {
|
||||||
state.rows = [];
|
state.rows = [];
|
||||||
state.writes = [];
|
state.writes = [];
|
||||||
@@ -69,6 +88,34 @@ describe("Hotel radio settings runtime", () => {
|
|||||||
expect(state.writes).toEqual([]);
|
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 () => {
|
it("rejects duplicate and invalid bulk entries atomically", async () => {
|
||||||
for (const entries of [
|
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 () => {
|
it("accepts the complete 102-entry curated form within the 500-entry bound", async () => {
|
||||||
const entries = Array.from({ length: 102 }, (_, index) => ({
|
const keys = readCuratedRadioSettingKeys();
|
||||||
key: `radio_curated_${index}`,
|
const entries = keys.map((key, index) => ({
|
||||||
|
key,
|
||||||
value: `value-${index}`,
|
value: `value-${index}`,
|
||||||
}));
|
}));
|
||||||
|
expect(keys).toHaveLength(102);
|
||||||
|
expect(new Set(keys).size).toBe(102);
|
||||||
|
|
||||||
await executeHotelMutationOperation(
|
await executeHotelMutationOperation(
|
||||||
"radio.settings.save-many",
|
"radio.settings.save-many",
|
||||||
@@ -103,7 +153,7 @@ describe("Hotel radio settings runtime", () => {
|
|||||||
context,
|
context,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(state.writes).toHaveLength(102);
|
expect(state.writes.map(({ key }) => key)).toEqual(keys);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects a bulk request above 500 entries", async () => {
|
it("rejects a bulk request above 500 entries", async () => {
|
||||||
|
|||||||
@@ -127,8 +127,8 @@ const roomRuntimeSchema = z
|
|||||||
})
|
})
|
||||||
.strict();
|
.strict();
|
||||||
|
|
||||||
const settingKey = requiredText(255).refine((key) =>
|
const settingKey = requiredText(255).refine(
|
||||||
/^(?:radio_|auto_dj_)[a-z0-9_]+$/i.test(key),
|
(key) => key.startsWith("radio_") || key.startsWith("auto_dj_"),
|
||||||
);
|
);
|
||||||
const settingSchema = z
|
const settingSchema = z
|
||||||
.object({
|
.object({
|
||||||
|
|||||||
Reference in new issue
Block a user