94 lines
2.6 KiB
TypeScript
94 lines
2.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { test } from "node:test";
|
|
import {
|
|
createRoomSchema,
|
|
joinRoomSchema,
|
|
roomGuessSchema,
|
|
chatMessageSchema,
|
|
} from "../shared/multiplayer";
|
|
|
|
const map = "00000000-0000-4000-8000-000000000000";
|
|
test("chat accepts plain multilingual text and rejects blank, oversized or hidden-control messages", () => {
|
|
assert.equal(
|
|
chatMessageSchema.parse({ clientId: map, text: " Привет (: " }).text,
|
|
"Привет (:",
|
|
);
|
|
assert.equal(
|
|
chatMessageSchema.safeParse({ clientId: map, text: "x".repeat(500) })
|
|
.success,
|
|
true,
|
|
);
|
|
for (const text of [
|
|
"",
|
|
" ",
|
|
"x".repeat(501),
|
|
"hidden\u202e",
|
|
"hidden\u0085",
|
|
"x\nname",
|
|
"x\u0000name",
|
|
])
|
|
assert.equal(
|
|
chatMessageSchema.safeParse({ clientId: map, text }).success,
|
|
false,
|
|
);
|
|
assert.equal(
|
|
chatMessageSchema.safeParse({ clientId: "wrong", text: "hi" }).success,
|
|
false,
|
|
);
|
|
assert.equal(
|
|
chatMessageSchema.parse({
|
|
clientId: map,
|
|
text: "<script>alert(1)</script>",
|
|
}).text,
|
|
"<script>alert(1)</script>",
|
|
);
|
|
});
|
|
test("room limits include the owner and stay between 2 and 16", () => {
|
|
for (const playerLimit of [2, 16])
|
|
assert.equal(
|
|
createRoomSchema.parse({
|
|
datasetId: map,
|
|
difficulty: "normal",
|
|
playerLimit,
|
|
}).playerLimit,
|
|
playerLimit,
|
|
);
|
|
for (const playerLimit of [1, 17, 2.5, "16", null])
|
|
assert.equal(
|
|
createRoomSchema.safeParse({
|
|
datasetId: map,
|
|
difficulty: "normal",
|
|
playerLimit,
|
|
}).success,
|
|
false,
|
|
);
|
|
});
|
|
test("party creation rejects a client-selected host identity", () => {
|
|
const room = { datasetId: map, difficulty: "normal", playerLimit: 4 };
|
|
assert.equal(createRoomSchema.safeParse(room).success, true);
|
|
for (const identity of [
|
|
{ displayName: "Impostor" },
|
|
{ accountId: map },
|
|
{ name: "Impostor" },
|
|
])
|
|
assert.equal(
|
|
createRoomSchema.safeParse({ ...room, ...identity }).success,
|
|
false,
|
|
);
|
|
});
|
|
test("multiplayer names and guesses reject hidden controls, invalid rounds, and non-finite positions", () => {
|
|
assert.equal(
|
|
joinRoomSchema.parse({ displayName: " Друг " }).displayName,
|
|
"Друг",
|
|
);
|
|
for (const displayName of ["a", "x\nname", "name\u202e", "a".repeat(33)])
|
|
assert.equal(joinRoomSchema.safeParse({ displayName }).success, false);
|
|
for (const payload of [
|
|
{ round: 5, x: 0, z: 0 },
|
|
{ round: 0, x: Infinity, z: 0 },
|
|
{ round: 0, x: NaN, z: 0 },
|
|
{ round: 0, x: 0 },
|
|
])
|
|
assert.equal(roomGuessSchema.safeParse(payload).success, false);
|
|
});
|