test: add coaster name matching test suite
Extract matching logic into lib/coaster-match.ts (isCoasterMatch + normalizeForMatch) so it can be imported by both the scraper and tests without duplication. Add tests/coaster-matching.test.ts covering all known match/false-positive cases: - Trademark symbols, leading THE, possessives, punctuation - Subtitle variants in both directions (Apocalypse, New Revolution - Classic) - Space-split brand words (BAT GIRL vs Batgirl) - 4D subtitle extension (THE JOKER™ 4D Free Fly Coaster vs Joker) - False positives: Joker y Harley Quinn, conjunction connectors Run with: npm test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
90
tests/coaster-matching.test.ts
Normal file
90
tests/coaster-matching.test.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Coaster name matching tests.
|
||||
*
|
||||
* Each case documents a real mismatch found between Queue-Times ride names
|
||||
* and RCDB coaster names, along with the park where it was observed.
|
||||
*
|
||||
* Run with: npm test
|
||||
*/
|
||||
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { isCoasterMatch, normalizeForMatch } from "../lib/coaster-match.ts";
|
||||
|
||||
// ── Helper ──────────────────────────────────────────────────────────────────
|
||||
|
||||
function makeSet(...rcdbNames: string[]): Set<string> {
|
||||
return new Set(rcdbNames.map(normalizeForMatch));
|
||||
}
|
||||
|
||||
// ── Should MATCH (Queue-Times name → RCDB name) ──────────────────────────────
|
||||
|
||||
test("exact match after lowercasing", () => {
|
||||
assert.ok(isCoasterMatch("Goliath", makeSet("Goliath")));
|
||||
});
|
||||
|
||||
test("trademark symbol stripped — BATMAN™ The Ride (Over Georgia, Magic Mountain)", () => {
|
||||
assert.ok(isCoasterMatch("BATMAN™ The Ride", makeSet("Batman The Ride")));
|
||||
});
|
||||
|
||||
test("leading THE stripped — THE RIDDLER Mindbender (Over Georgia)", () => {
|
||||
assert.ok(isCoasterMatch("THE RIDDLER Mindbender", makeSet("Riddler Mindbender")));
|
||||
});
|
||||
|
||||
test("trademark + leading THE — THE RIDDLER™'s Revenge (Magic Mountain)", () => {
|
||||
assert.ok(isCoasterMatch("THE RIDDLER™'s Revenge", makeSet("Riddler's Revenge")));
|
||||
});
|
||||
|
||||
test("curly apostrophe possessive stripped — CATWOMAN™ Whip (New England)", () => {
|
||||
assert.ok(isCoasterMatch("CATWOMAN™ Whip", makeSet("Catwoman's Whip")));
|
||||
});
|
||||
|
||||
test("straight apostrophe possessive stripped", () => {
|
||||
assert.ok(isCoasterMatch("Riddler's Revenge", makeSet("Riddler's Revenge")));
|
||||
});
|
||||
|
||||
test("trademark + colon punctuation — SUPERMAN™: Ultimate Flight (Over Georgia)", () => {
|
||||
assert.ok(isCoasterMatch("SUPERMAN™: Ultimate Flight", makeSet("Superman - Ultimate Flight")));
|
||||
});
|
||||
|
||||
test("QT drops subtitle — Apocalypse (Magic Mountain)", () => {
|
||||
assert.ok(isCoasterMatch("Apocalypse", makeSet("Apocalypse the Ride")));
|
||||
});
|
||||
|
||||
test("QT adds subtitle — The New Revolution - Classic (Magic Mountain)", () => {
|
||||
assert.ok(isCoasterMatch("The New Revolution - Classic", makeSet("New Revolution")));
|
||||
});
|
||||
|
||||
test("QT exclamation stripped — SCREAM (Magic Mountain)", () => {
|
||||
assert.ok(isCoasterMatch("SCREAM", makeSet("Scream!")));
|
||||
});
|
||||
|
||||
test("space-split word — BAT GIRL™: Coaster Chase (Fiesta Texas)", () => {
|
||||
assert.ok(isCoasterMatch("BAT GIRL™: Coaster Chase", makeSet("Batgirl Coaster Chase")));
|
||||
});
|
||||
|
||||
test("trademark + 4D subtitle — THE JOKER™ 4D Free Fly Coaster (New England)", () => {
|
||||
assert.ok(isCoasterMatch("THE JOKER™ 4D Free Fly Coaster", makeSet("Joker")));
|
||||
});
|
||||
|
||||
test("Great American Scream Machine — top-level QT rides array (Over Georgia)", () => {
|
||||
assert.ok(isCoasterMatch("The Great American Scream Machine", makeSet("Great American Scream Machine")));
|
||||
});
|
||||
|
||||
test("THE JOKER™ Funhouse Coaster — top-level QT rides array (Over Georgia)", () => {
|
||||
assert.ok(isCoasterMatch("THE JOKER™ Funhouse Coaster", makeSet("Joker Funhouse Coaster")));
|
||||
});
|
||||
|
||||
// ── Should NOT MATCH (false positives) ──────────────────────────────────────
|
||||
|
||||
test("false positive: Joker y Harley Quinn ≠ Joker (Six Flags Mexico)", () => {
|
||||
assert.ok(!isCoasterMatch("Joker y Harley Quinn", makeSet("Joker")));
|
||||
});
|
||||
|
||||
test("false positive: unrelated ride does not match", () => {
|
||||
assert.ok(!isCoasterMatch("SkyScreamer", makeSet("Goliath")));
|
||||
});
|
||||
|
||||
test("false positive: short prefix with conjunction — de connector", () => {
|
||||
assert.ok(!isCoasterMatch("Batman de Gotham", makeSet("Batman")));
|
||||
});
|
||||
Reference in New Issue
Block a user