mirror of
https://github.com/jcwimer/wrestlingApp
synced 2026-04-11 16:01:56 +00:00
180 lines
5.9 KiB
JavaScript
180 lines
5.9 KiB
JavaScript
import { beforeEach, describe, expect, it, vi } from "vitest"
|
|
import MatchDataController from "../../../app/assets/javascripts/controllers/match_data_controller.js"
|
|
|
|
function makeTarget(value = "") {
|
|
return {
|
|
value,
|
|
innerText: "",
|
|
addEventListener: vi.fn(),
|
|
classList: {
|
|
add: vi.fn(),
|
|
remove: vi.fn()
|
|
}
|
|
}
|
|
}
|
|
|
|
function buildController() {
|
|
const controller = new MatchDataController()
|
|
controller.tournamentIdValue = 8
|
|
controller.boutNumberValue = 1001
|
|
controller.matchIdValue = 22
|
|
controller.w1StatTarget = makeTarget("Initial W1")
|
|
controller.w2StatTarget = makeTarget("Initial W2")
|
|
controller.statusIndicatorTarget = makeTarget()
|
|
return controller
|
|
}
|
|
|
|
describe("match data controller", () => {
|
|
beforeEach(() => {
|
|
vi.restoreAllMocks()
|
|
vi.spyOn(Date.prototype, "toISOString").mockReturnValue("2026-04-10T00:00:00.000Z")
|
|
global.localStorage = {
|
|
getItem: vi.fn(() => null),
|
|
setItem: vi.fn()
|
|
}
|
|
global.window = {
|
|
App: null
|
|
}
|
|
global.document = {
|
|
getElementById: vi.fn(() => null)
|
|
}
|
|
global.setTimeout = vi.fn((fn) => {
|
|
fn()
|
|
return 1
|
|
})
|
|
global.clearTimeout = vi.fn()
|
|
global.setInterval = vi.fn(() => 123)
|
|
global.clearInterval = vi.fn()
|
|
})
|
|
|
|
it("connect initializes wrestler state, localStorage, textarea handlers, and subscription", () => {
|
|
const controller = buildController()
|
|
controller.initializeFromLocalStorage = vi.fn()
|
|
controller.setupSubscription = vi.fn()
|
|
|
|
controller.connect()
|
|
|
|
expect(controller.w1.stats).toBe("Initial W1")
|
|
expect(controller.w2.stats).toBe("Initial W2")
|
|
expect(controller.w1StatTarget.addEventListener).toHaveBeenCalledWith("input", expect.any(Function))
|
|
expect(controller.w2StatTarget.addEventListener).toHaveBeenCalledWith("input", expect.any(Function))
|
|
expect(controller.initializeFromLocalStorage).toHaveBeenCalledTimes(1)
|
|
expect(controller.setupSubscription).toHaveBeenCalledWith(22)
|
|
})
|
|
|
|
it("generates tournament and bout scoped localStorage keys", () => {
|
|
const controller = buildController()
|
|
|
|
expect(controller.generateKey("w1")).toBe("w1-8-1001")
|
|
expect(controller.generateKey("w2")).toBe("w2-8-1001")
|
|
})
|
|
|
|
it("updateStats updates textareas, localStorage, and sends websocket stat payloads", () => {
|
|
const controller = buildController()
|
|
controller.connect()
|
|
controller.matchSubscription = { perform: vi.fn() }
|
|
|
|
controller.updateStats(controller.w1, "T3")
|
|
|
|
expect(controller.w1.stats).toBe("Initial W1T3 ")
|
|
expect(controller.w1StatTarget.value).toBe("Initial W1T3 ")
|
|
expect(localStorage.setItem).toHaveBeenCalledWith(
|
|
"w1-8-1001",
|
|
expect.stringContaining('"stats":"Initial W1T3 "')
|
|
)
|
|
expect(controller.matchSubscription.perform).toHaveBeenCalledWith("send_stat", {
|
|
new_w1_stat: "Initial W1T3 "
|
|
})
|
|
})
|
|
|
|
it("textarea input saves local state and marks pending sync when disconnected", () => {
|
|
const controller = buildController()
|
|
controller.connect()
|
|
controller.isConnected = false
|
|
controller.matchSubscription = { perform: vi.fn() }
|
|
|
|
controller.handleTextAreaInput({ value: "Manual stat" }, controller.w2)
|
|
|
|
expect(controller.w2.stats).toBe("Manual stat")
|
|
expect(controller.pendingLocalSync.w2).toBe(true)
|
|
expect(localStorage.setItem).toHaveBeenCalledWith(
|
|
"w2-8-1001",
|
|
expect.stringContaining('"stats":"Manual stat"')
|
|
)
|
|
expect(controller.matchSubscription.perform).toHaveBeenCalledWith("send_stat", {
|
|
new_w2_stat: "Manual stat"
|
|
})
|
|
})
|
|
|
|
it("loads persisted localStorage stats and timers into the textareas", () => {
|
|
const controller = buildController()
|
|
localStorage.getItem = vi.fn((key) => {
|
|
if (key === "w1-8-1001") {
|
|
return JSON.stringify({
|
|
stats: "Saved W1",
|
|
updated_at: "timestamp",
|
|
timers: {
|
|
injury: { time: 5, startTime: null, interval: null },
|
|
blood: { time: 0, startTime: null, interval: null }
|
|
}
|
|
})
|
|
}
|
|
return null
|
|
})
|
|
|
|
controller.connect()
|
|
|
|
expect(controller.w1.stats).toBe("Saved W1")
|
|
expect(controller.w1StatTarget.value).toBe("Saved W1")
|
|
expect(controller.w1.timers.injury.time).toBe(5)
|
|
})
|
|
|
|
it("subscription callbacks update status, request sync, and apply received stats", () => {
|
|
const controller = buildController()
|
|
const subscription = { perform: vi.fn(), unsubscribe: vi.fn() }
|
|
let callbacks
|
|
global.App = {
|
|
cable: {
|
|
subscriptions: {
|
|
create: vi.fn((_identifier, receivedCallbacks) => {
|
|
callbacks = receivedCallbacks
|
|
return subscription
|
|
})
|
|
}
|
|
}
|
|
}
|
|
window.App = global.App
|
|
|
|
controller.connect()
|
|
controller.w1.stats = "Local W1"
|
|
controller.w2.stats = "Local W2"
|
|
callbacks.connected()
|
|
|
|
expect(controller.isConnected).toBe(true)
|
|
expect(controller.statusIndicatorTarget.innerText).toBe("Connected: Stats will update in real-time.")
|
|
expect(subscription.perform).toHaveBeenCalledWith("send_stat", {
|
|
new_w1_stat: "Local W1",
|
|
new_w2_stat: "Local W2"
|
|
})
|
|
|
|
controller.pendingLocalSync.w1 = false
|
|
controller.pendingLocalSync.w2 = false
|
|
callbacks.received({ w1_stat: "Remote W1", w2_stat: "Remote W2" })
|
|
|
|
expect(controller.w1StatTarget.value).toBe("Remote W1")
|
|
expect(controller.w2StatTarget.value).toBe("Remote W2")
|
|
|
|
callbacks.disconnected()
|
|
expect(controller.isConnected).toBe(false)
|
|
expect(controller.statusIndicatorTarget.innerText).toBe("Disconnected: Stats updates paused.")
|
|
})
|
|
|
|
it("setupSubscription reports websocket unavailable when ActionCable is missing", () => {
|
|
const controller = buildController()
|
|
controller.connect()
|
|
|
|
expect(controller.statusIndicatorTarget.innerText).toBe("Error: WebSockets unavailable. Stats won't update in real-time.")
|
|
expect(controller.statusIndicatorTarget.classList.add).toHaveBeenCalledWith("alert-danger")
|
|
})
|
|
})
|