1
0
mirror of https://github.com/jcwimer/wrestlingApp synced 2026-04-11 16:01:56 +00:00
Files
wrestlingdev.com/test/javascript/controllers/match_score_controller.test.js

270 lines
8.9 KiB
JavaScript

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)
})
})