import { beforeEach, expect, test } from 'vitest'
import { WebComponent, html } from '../../src/index.js'
/**
* Boolean props reflect as bare attributes (presence/absence), so the two
* things that silently broke under string reflection work here: the platform's
* own `toggleAttribute()` API, and `[attr]` presence selectors in CSS.
* These need a real browser — happy-dom does not evaluate `:host([flag])`.
*/
class FlagBox extends WebComponent {
static props = { flag: false }
static shadowRootInit = { mode: 'open' }
static styles = `
:host { color: rgb(0, 0, 0); }
:host([flag]) { color: rgb(255, 0, 0); }
`
get template() {
// an object template, so `static styles` actually gets adopted
return html`flag is ${this.props.flag}`
}
}
window.customElements.define('flag-box', FlagBox)
const color = (el) => window.getComputedStyle(el).color
beforeEach(() => {
document.body.innerHTML = ''
})
test('a false boolean prop leaves no attribute to mis-match [flag]', () => {
document.body.innerHTML = ''
const el = document.querySelector('flag-box')
expect(el.hasAttribute('flag')).toBe(false)
expect(el.props.flag).toBe(false)
// the REQ-07 bug: `flag="false"` used to match `:host([flag])` and paint the
// "on" style onto an element whose prop was false
expect(color(el)).toBe('rgb(0, 0, 0)')
})
test('toggleAttribute drives the prop, the render and the [flag] style', () => {
document.body.innerHTML = ''
const el = document.querySelector('flag-box')
// used to be a silent no-op: the attribute already existed as flag="false"
el.toggleAttribute('flag', true)
expect(el.props.flag).toBe(true)
expect(el.shadowRoot.querySelector('span').textContent).toBe('flag is true')
expect(color(el)).toBe('rgb(255, 0, 0)')
el.toggleAttribute('flag', false)
expect(el.props.flag).toBe(false)
expect(el.shadowRoot.querySelector('span').textContent).toBe('flag is false')
expect(color(el)).toBe('rgb(0, 0, 0)')
})
test('a prop write reflects as a bare attribute the CSS can match', () => {
document.body.innerHTML = ''
const el = document.querySelector('flag-box')
el.props.flag = true
expect(el.getAttribute('flag')).toBe('')
expect(color(el)).toBe('rgb(255, 0, 0)')
el.props.flag = false
expect(el.hasAttribute('flag')).toBe(false)
expect(color(el)).toBe('rgb(0, 0, 0)')
})
test('markup presence turns the prop on, whatever the value says', () => {
// strict HTML semantics: any present value is true, including "false"
document.body.innerHTML =
''
const [bare, stringly] = document.querySelectorAll('flag-box')
expect(bare.props.flag).toBe(true)
expect(stringly.props.flag).toBe(true)
expect(color(bare)).toBe('rgb(255, 0, 0)')
expect(color(stringly)).toBe('rgb(255, 0, 0)')
})