Something went wrong. Try again.
Web frontend and supporting services for lance.blue
Something went wrong. Try again.
3.3 kB · 107 lines
JavaScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108/** * A phone is turned away from a match, and nothing else is. * * The gate is a hard stop with no "play anyway" behind it, so the cost of it * answering yes to a machine that can play is a player who cannot play at * all. That is what these cases are: the two shapes a phone takes, and the * three things next to it that have to stay out — a desktop window dragged * narrow, a tablet in landscape, and a browser with no matchMedia at all. * * Run with `npm test`. */import { test } from "node:test";import assert from "node:assert/strict";import { mkdtemp, rm } from "node:fs/promises";import { tmpdir } from "node:os";import { join } from "node:path";import { execFile } from "node:child_process";import { promisify } from "node:util";
const run = promisify(execFile);const web = join(new URL(".", import.meta.url).pathname, "..");
const dir = await mkdtemp(join(tmpdir(), "phone-gate-"));const bundle = join(dir, "fixture.mjs");await run( join(web, "node_modules/.bin/rolldown"), [ join(web, "scripts/phone-gate.fixture.ts"), "--format", "esm", "--platform", "node", "--file", bundle, ], { cwd: web },);
const { isPhone } = await import(bundle);
const ROOT_PX = 16;
/** * A browser of the given size and pointer, answering the three queries the * predicate asks the way a real one would. * * Only the four features it uses are parsed. A query it does not know is a * mistake in the module rather than something to answer with false, so this * throws on one. */function browser({ width, height, pointer }) { globalThis.window = { matchMedia(query) { const [, feature, value] = /\((.+):\s*(.+)\)/.exec(query) ?? []; const px = Number.parseFloat(value) * (value.endsWith("rem") ? ROOT_PX : 1); switch (feature) { case "pointer": return { matches: pointer === value }; case "max-width": return { matches: width <= px }; case "max-height": return { matches: height <= px }; default: throw new Error(`the gate asked an unhandled query: ${query}`); } }, };}
test("a phone held either way is a phone", () => { browser({ width: 390, height: 844, pointer: "coarse" }); assert.equal(isPhone(), true, "a phone upright was let through to a match");
browser({ width: 844, height: 390, pointer: "coarse" }); assert.equal( isPhone(), true, "a phone on its side is wide enough to pass the width check, and the " + "height check is the only thing that catches it", );});
test("a narrow desktop window is not a phone", () => { browser({ width: 500, height: 900, pointer: "fine" }); assert.equal( isPhone(), false, "a mouse in front of a small viewport was locked out of a match it can play", );});
test("a tablet in landscape is not a phone", () => { browser({ width: 1024, height: 768, pointer: "coarse" }); assert.equal(isPhone(), false);});
test("a browser without matchMedia is not a phone", () => { globalThis.window = {}; assert.equal( isPhone(), false, "an unanswerable question turned a player away; the gate must fail open", );});
test.after(() => rm(dir, { recursive: true, force: true }));