bfe099322f
Build and Deploy / Build & Push (push) Successful in 1m3s
Join Fast Lane waits from the Six Flags /wait-times endpoint onto Queue-Times rides by name. A new toggle on the live ride panel swaps the shown wait to the Fast Lane number; regular waits and open status still come from Queue-Times. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
/**
|
|
* Fast Lane name-join tests.
|
|
*
|
|
* The Six Flags /wait-times endpoint and Queue-Times use slightly different
|
|
* ride name conventions, so Fast Lane waits are joined onto Queue-Times rides
|
|
* by normalized name. These cases lock that join behaviour.
|
|
*
|
|
* Run with: npm test
|
|
*/
|
|
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { parseWaitTimes, lookupFastLane } from "../lib/scrapers/sixflags-waittimes";
|
|
import type { WTResponse } from "../lib/scrapers/sixflags-waittimes";
|
|
|
|
function ride(
|
|
name: string,
|
|
isFastLane: boolean,
|
|
fastLaneMinutes: number | null,
|
|
): Record<string, unknown> {
|
|
return {
|
|
id: 1,
|
|
name,
|
|
isFastLane,
|
|
regularWaittime: { createdDateTime: "May 29, 2026 19:00:00", waitTime: 20 },
|
|
fastlaneWaittime:
|
|
fastLaneMinutes === null
|
|
? { createdDateTime: "", waitTime: 0 }
|
|
: { createdDateTime: "May 29, 2026 19:00:00", waitTime: fastLaneMinutes },
|
|
fimsId: "RIDE-906-00001",
|
|
};
|
|
}
|
|
|
|
function result(...rides: Record<string, unknown>[]) {
|
|
const json: WTResponse = {
|
|
parkId: 906,
|
|
venues: [{ venueId: 1, venueName: "Rides", details: rides as never }],
|
|
};
|
|
const r = parseWaitTimes(json);
|
|
assert.ok(r, "expected parseWaitTimes to return a result");
|
|
return r;
|
|
}
|
|
|
|
// ── Name joins across QT ↔ SF naming quirks ──────────────────────────────────
|
|
|
|
test("matches across trademark symbols, THE prefix, possessives", () => {
|
|
const r = result(
|
|
ride("Batman: The Ride", true, 5),
|
|
ride("Riddler's Revenge", true, 10),
|
|
ride("Apocalypse the Ride", true, 15),
|
|
);
|
|
|
|
// Queue-Times-style names on the left should resolve to the SF entries.
|
|
assert.deepEqual(lookupFastLane("BATMAN™ The Ride", r), {
|
|
hasFastLane: true,
|
|
fastLaneMinutes: 5,
|
|
});
|
|
assert.deepEqual(lookupFastLane("THE RIDDLER™'s Revenge", r), {
|
|
hasFastLane: true,
|
|
fastLaneMinutes: 10,
|
|
});
|
|
// Prefix match: "Apocalypse" is a prefix of "Apocalypse the Ride".
|
|
assert.deepEqual(lookupFastLane("Apocalypse", r), {
|
|
hasFastLane: true,
|
|
fastLaneMinutes: 15,
|
|
});
|
|
});
|
|
|
|
test("a non-Fast-Lane ride resolves to hasFastLane: false", () => {
|
|
const r = result(ride("Bucaneer", false, null));
|
|
assert.deepEqual(lookupFastLane("Bucaneer", r), {
|
|
hasFastLane: false,
|
|
fastLaneMinutes: null,
|
|
});
|
|
});
|
|
|
|
test("empty fastlane createdDateTime yields fastLaneMinutes: null", () => {
|
|
const r = result(ride("Batman: The Ride", true, null));
|
|
assert.deepEqual(lookupFastLane("Batman: The Ride", r), {
|
|
hasFastLane: true,
|
|
fastLaneMinutes: null,
|
|
});
|
|
});
|
|
|
|
test("a ride absent from SF data returns null", () => {
|
|
const r = result(ride("Apocalypse the Ride", true, 15));
|
|
assert.equal(lookupFastLane("Some Other Coaster", r), null);
|
|
});
|
|
|
|
test("conjunction guard: compound name does not match a single ride", () => {
|
|
const r = result(ride("Joker", true, 25));
|
|
// "Joker y Harley Quinn" is a different (compound) ride, not a Joker subtitle.
|
|
assert.equal(lookupFastLane("Joker y Harley Quinn", r), null);
|
|
});
|
|
|
|
test("parseWaitTimes returns null when no ride rows present", () => {
|
|
assert.equal(parseWaitTimes({ parkId: 1, venues: [] }), null);
|
|
assert.equal(
|
|
parseWaitTimes({ parkId: 1, venues: [{ venueId: 9, venueName: "Restaurants", details: [] }] }),
|
|
null,
|
|
);
|
|
});
|