mirror of
https://github.com/jcwimer/wrestlingApp
synced 2026-04-13 08:32:47 +00:00
New stats page, scoreboard, and live scores pages.
This commit is contained in:
269
test/javascript/controllers/match_score_controller.test.js
Normal file
269
test/javascript/controllers/match_score_controller.test.js
Normal file
@@ -0,0 +1,269 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
import MatchScoreController from "../../../app/assets/javascripts/controllers/match_score_controller.js"
|
||||
|
||||
class FakeNode {
|
||||
constructor(tagName = "div") {
|
||||
this.tagName = tagName
|
||||
this.children = []
|
||||
this.value = ""
|
||||
this.innerHTML = ""
|
||||
this.innerText = ""
|
||||
this.id = ""
|
||||
this.placeholder = ""
|
||||
this.type = ""
|
||||
this.style = {}
|
||||
this.listeners = {}
|
||||
this.classList = {
|
||||
add: vi.fn(),
|
||||
remove: vi.fn()
|
||||
}
|
||||
}
|
||||
|
||||
appendChild(child) {
|
||||
this.children.push(child)
|
||||
return child
|
||||
}
|
||||
|
||||
setAttribute(name, value) {
|
||||
this[name] = value
|
||||
}
|
||||
|
||||
addEventListener(eventName, callback) {
|
||||
this.listeners[eventName] = callback
|
||||
}
|
||||
|
||||
querySelector(selector) {
|
||||
if (selector === "input") return this.allInputs()[0] || null
|
||||
if (!selector.startsWith("#")) return null
|
||||
return this.findById(selector.slice(1))
|
||||
}
|
||||
|
||||
querySelectorAll(selector) {
|
||||
if (selector !== "input") return []
|
||||
return this.allInputs()
|
||||
}
|
||||
|
||||
findById(id) {
|
||||
if (this.id === id) return this
|
||||
for (const child of this.children) {
|
||||
const match = child.findById?.(id)
|
||||
if (match) return match
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
allInputs() {
|
||||
const matches = this.tagName === "input" ? [this] : []
|
||||
for (const child of this.children) {
|
||||
matches.push(...(child.allInputs?.() || []))
|
||||
}
|
||||
return matches
|
||||
}
|
||||
}
|
||||
|
||||
function buildController() {
|
||||
const controller = new MatchScoreController()
|
||||
controller.element = {
|
||||
addEventListener: vi.fn(),
|
||||
removeEventListener: vi.fn()
|
||||
}
|
||||
controller.winTypeTarget = { value: "Decision" }
|
||||
controller.winnerSelectTarget = { value: "", options: [{ value: "" }, { value: "11" }], selectedIndex: 1 }
|
||||
controller.overtimeSelectTarget = { value: "", options: [{ value: "" }, { value: "SV-1" }] }
|
||||
controller.submitButtonTarget = { disabled: false }
|
||||
controller.dynamicScoreInputTarget = new FakeNode("div")
|
||||
controller.finalScoreFieldTarget = { value: "" }
|
||||
controller.validationAlertsTarget = {
|
||||
innerHTML: "",
|
||||
style: {},
|
||||
classList: { add: vi.fn(), remove: vi.fn() }
|
||||
}
|
||||
controller.pinTimeTipTarget = { style: {} }
|
||||
controller.manualOverrideValue = false
|
||||
controller.finishedValue = false
|
||||
controller.winnerScoreValue = "0"
|
||||
controller.loserScoreValue = "0"
|
||||
controller.pinMinutesValue = "0"
|
||||
controller.pinSecondsValue = "00"
|
||||
controller.hasWinnerSelectTarget = true
|
||||
controller.hasOvertimeSelectTarget = true
|
||||
return controller
|
||||
}
|
||||
|
||||
describe("match score controller", () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
global.document = {
|
||||
createElement: vi.fn((tagName) => new FakeNode(tagName))
|
||||
}
|
||||
})
|
||||
|
||||
it("connect binds manual-override listeners and initializes unfinished forms", () => {
|
||||
const controller = buildController()
|
||||
controller.updateScoreInput = vi.fn()
|
||||
controller.validateForm = vi.fn()
|
||||
vi.spyOn(globalThis, "setTimeout").mockImplementation((fn) => {
|
||||
fn()
|
||||
return 1
|
||||
})
|
||||
|
||||
controller.connect()
|
||||
|
||||
expect(controller.element.addEventListener).toHaveBeenCalledWith("input", controller.boundMarkManualOverride)
|
||||
expect(controller.element.addEventListener).toHaveBeenCalledWith("change", controller.boundMarkManualOverride)
|
||||
expect(controller.updateScoreInput).toHaveBeenCalledTimes(1)
|
||||
expect(controller.validateForm).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("connect skips score initialization for finished forms", () => {
|
||||
const controller = buildController()
|
||||
controller.finishedValue = true
|
||||
controller.updateScoreInput = vi.fn()
|
||||
controller.validateForm = vi.fn()
|
||||
|
||||
controller.connect()
|
||||
|
||||
expect(controller.updateScoreInput).not.toHaveBeenCalled()
|
||||
expect(controller.validateForm).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("applyDefaultResults fills derived defaults until the user overrides them", () => {
|
||||
const controller = buildController()
|
||||
controller.updateScoreInput = vi.fn()
|
||||
controller.validateForm = vi.fn()
|
||||
|
||||
controller.applyDefaultResults({
|
||||
winnerId: 11,
|
||||
overtimeType: "SV-1",
|
||||
winnerScore: 5,
|
||||
loserScore: 2,
|
||||
pinMinutes: 1,
|
||||
pinSeconds: 9
|
||||
})
|
||||
|
||||
expect(controller.winnerSelectTarget.value).toBe("11")
|
||||
expect(controller.overtimeSelectTarget.value).toBe("SV-1")
|
||||
expect(controller.winnerScoreValue).toBe("5")
|
||||
expect(controller.loserScoreValue).toBe("2")
|
||||
expect(controller.pinMinutesValue).toBe("1")
|
||||
expect(controller.pinSecondsValue).toBe("09")
|
||||
expect(controller.updateScoreInput).toHaveBeenCalledTimes(1)
|
||||
expect(controller.validateForm).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("applyDefaultResults does nothing after manual override", () => {
|
||||
const controller = buildController()
|
||||
controller.manualOverrideValue = true
|
||||
controller.updateScoreInput = vi.fn()
|
||||
|
||||
controller.applyDefaultResults({ winnerId: 11, winnerScore: 5 })
|
||||
|
||||
expect(controller.winnerSelectTarget.value).toBe("")
|
||||
expect(controller.updateScoreInput).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("markManualOverride only reacts to trusted events", () => {
|
||||
const controller = buildController()
|
||||
|
||||
controller.markManualOverride({ isTrusted: false })
|
||||
expect(controller.manualOverrideValue).toBe(false)
|
||||
|
||||
controller.markManualOverride({ isTrusted: true })
|
||||
expect(controller.manualOverrideValue).toBe(true)
|
||||
})
|
||||
|
||||
it("validateForm disables submit for invalid decision scores and enables it for valid ones", () => {
|
||||
const controller = buildController()
|
||||
controller.winTypeTarget.value = "Decision"
|
||||
controller.winnerSelectTarget.value = "11"
|
||||
controller.winnerScoreValue = "2"
|
||||
controller.loserScoreValue = "3"
|
||||
|
||||
expect(controller.validateForm()).toBe(false)
|
||||
expect(controller.submitButtonTarget.disabled).toBe(true)
|
||||
expect(controller.validationAlertsTarget.style.display).toBe("block")
|
||||
|
||||
controller.winnerScoreValue = "5"
|
||||
controller.loserScoreValue = "2"
|
||||
controller.validationAlertsTarget.style = {}
|
||||
|
||||
expect(controller.validateForm()).toBe(true)
|
||||
expect(controller.submitButtonTarget.disabled).toBe(false)
|
||||
})
|
||||
|
||||
it("winnerChanged and winTypeChanged revalidate the form", () => {
|
||||
const controller = buildController()
|
||||
controller.updateScoreInput = vi.fn()
|
||||
controller.validateForm = vi.fn()
|
||||
|
||||
controller.winTypeChanged()
|
||||
expect(controller.updateScoreInput).toHaveBeenCalledTimes(1)
|
||||
expect(controller.validateForm).toHaveBeenCalledTimes(1)
|
||||
|
||||
controller.winnerChanged()
|
||||
expect(controller.validateForm).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it("updateScoreInput builds pin inputs and writes pin time score", () => {
|
||||
const controller = buildController()
|
||||
controller.winTypeTarget.value = "Pin"
|
||||
controller.pinMinutesValue = "1"
|
||||
controller.pinSecondsValue = "09"
|
||||
controller.validateForm = vi.fn()
|
||||
|
||||
controller.updateScoreInput()
|
||||
|
||||
expect(controller.pinTimeTipTarget.style.display).toBe("block")
|
||||
expect(controller.dynamicScoreInputTarget.querySelector("#minutes").value).toBe("1")
|
||||
expect(controller.dynamicScoreInputTarget.querySelector("#seconds").value).toBe("09")
|
||||
expect(controller.finalScoreFieldTarget.value).toBe("01:09")
|
||||
})
|
||||
|
||||
it("updateScoreInput builds point inputs and writes point score", () => {
|
||||
const controller = buildController()
|
||||
controller.winTypeTarget.value = "Decision"
|
||||
controller.winnerScoreValue = "7"
|
||||
controller.loserScoreValue = "3"
|
||||
controller.validateForm = vi.fn()
|
||||
|
||||
controller.updateScoreInput()
|
||||
|
||||
expect(controller.pinTimeTipTarget.style.display).toBe("none")
|
||||
expect(controller.dynamicScoreInputTarget.querySelector("#winner-score").value).toBe("7")
|
||||
expect(controller.dynamicScoreInputTarget.querySelector("#loser-score").value).toBe("3")
|
||||
expect(controller.finalScoreFieldTarget.value).toBe("7-3")
|
||||
})
|
||||
|
||||
it("updateScoreInput clears score for non-score win types", () => {
|
||||
const controller = buildController()
|
||||
controller.winTypeTarget.value = "Forfeit"
|
||||
controller.finalScoreFieldTarget.value = "7-3"
|
||||
controller.validateForm = vi.fn()
|
||||
|
||||
controller.updateScoreInput()
|
||||
|
||||
expect(controller.pinTimeTipTarget.style.display).toBe("none")
|
||||
expect(controller.finalScoreFieldTarget.value).toBe("")
|
||||
expect(controller.dynamicScoreInputTarget.children.at(-1).innerText).toBe("No score required for Forfeit win type.")
|
||||
})
|
||||
|
||||
it("validateForm enforces major and tech fall score boundaries", () => {
|
||||
const controller = buildController()
|
||||
controller.winnerSelectTarget.value = "11"
|
||||
controller.winTypeTarget.value = "Decision"
|
||||
controller.winnerScoreValue = "10"
|
||||
controller.loserScoreValue = "2"
|
||||
|
||||
expect(controller.validateForm()).toBe(false)
|
||||
expect(controller.validationAlertsTarget.innerHTML).toContain("Major")
|
||||
|
||||
controller.winTypeTarget.value = "Tech Fall"
|
||||
controller.winnerScoreValue = "17"
|
||||
controller.loserScoreValue = "2"
|
||||
controller.validationAlertsTarget.innerHTML = ""
|
||||
controller.validationAlertsTarget.style = {}
|
||||
|
||||
expect(controller.validateForm()).toBe(true)
|
||||
expect(controller.submitButtonTarget.disabled).toBe(false)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user