Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/scripts/deck.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,19 @@ export const createDeck = (deckList, id, x, y) => {
if (failed.length > 0) {
const errorElement = document.createElement("div")
errorElement.classList.add("deck-parse-errors")
errorElement.innerHTML = `<strong>Unrecognized cards (not loaded):</strong><ul>${failed.map(n => `<li>${n}</li>`).join("")}</ul>`

const heading = document.createElement("strong")
heading.textContent = "Unrecognized cards (not loaded):"
errorElement.appendChild(heading)

const list = document.createElement("ul")
for (const name of failed) {
const item = document.createElement("li")
item.textContent = name
list.appendChild(item)
}
errorElement.appendChild(list)

document.querySelector("#card-layer").appendChild(errorElement)
}

Expand Down
19 changes: 19 additions & 0 deletions src/scripts/deck.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,25 @@ describe('createDeck', () => {
expect(document.querySelector('.deck-parse-errors')).not.toBeNull()
})

it('renders HTML characters in failed card names as escaped text, not live markup', () => {
createDeck('1x <img src=x onerror="xss()">', 'test-deck', '0px', '0px')
const errors = document.querySelector('.deck-parse-errors')
expect(errors).not.toBeNull()
expect(errors.querySelector('img')).toBeNull()
expect(errors.textContent).toContain('<img src=x onerror="xss()">')
})

it('renders one <li> per distinct unrecognized card name', () => {
createDeck('1x Ghost Runner\n1x Sneakdoor Beta', 'test-deck', '0px', '0px')
const errors = document.querySelector('.deck-parse-errors')
expect(errors).not.toBeNull()
const items = errors.querySelectorAll('li')
expect(items).toHaveLength(2)
const texts = Array.from(items).map(li => li.textContent)
expect(texts).toContain('Ghost Runner')
expect(texts).toContain('Sneakdoor Beta')
})

it('adds red-tint class and sets title to "no cards left" when all cards are drawn', () => {
const el = createDeck('2x Hedge Fund', 'test-deck', '0px', '0px')
el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }))
Expand Down
Loading