fix: boolean props w/ bare attr as true
This commit is contained in:
parent
5635e6eb4a
commit
737ef54763
4 changed files with 57 additions and 5 deletions
|
|
@ -101,7 +101,7 @@
|
|||
"size-limit": [
|
||||
{
|
||||
"path": "./dist/WebComponent.js",
|
||||
"limit": "1.35 KB"
|
||||
"limit": "1.4 KB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/html.js",
|
||||
|
|
|
|||
|
|
@ -5,8 +5,11 @@
|
|||
*/
|
||||
export function deserialize(value, type) {
|
||||
switch (type) {
|
||||
case 'number':
|
||||
case 'boolean':
|
||||
// bare presence follows the HTML convention: `<el flag>` / `flag=""` is true.
|
||||
if (value === '') return true
|
||||
// falls through
|
||||
case 'number':
|
||||
case 'object':
|
||||
case 'undefined':
|
||||
return JSON.parse(value)
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ describe('WebComponent', () => {
|
|||
* and returns it. Remove it with `el.remove()` to trigger disconnect.
|
||||
*/
|
||||
let tagSeq = 0
|
||||
/**
|
||||
*
|
||||
* @param Class
|
||||
* @param attributes
|
||||
*/
|
||||
function mount(Class, attributes = {}) {
|
||||
const tag = `wc-test-${tagSeq++}`
|
||||
window.customElements.define(tag, Class)
|
||||
|
|
@ -265,6 +270,38 @@ describe('reactive props (documented contract)', () => {
|
|||
expect(el.props.count).toBe(5)
|
||||
})
|
||||
|
||||
it('turns a boolean prop on from a bare attribute (<el active>)', () => {
|
||||
const el = connected()
|
||||
// `<el active>` and `<el active="">` are the same to the DOM
|
||||
el.setAttribute('active', '')
|
||||
expect(el.props.active).toBe(true)
|
||||
})
|
||||
|
||||
it('honors an explicit "true"/"false" boolean attribute value', () => {
|
||||
const el = connected()
|
||||
el.setAttribute('active', 'true')
|
||||
expect(el.props.active).toBe(true)
|
||||
el.setAttribute('active', 'false')
|
||||
expect(el.props.active).toBe(false)
|
||||
})
|
||||
|
||||
it('resets a boolean prop to its default when the attribute is removed', () => {
|
||||
const el = connected()
|
||||
el.setAttribute('active', '')
|
||||
el.removeAttribute('active')
|
||||
expect(el.props.active).toBe(false)
|
||||
})
|
||||
|
||||
it('round-trips a boolean prop write through its reflected attribute', () => {
|
||||
const el = connected()
|
||||
el.props.active = true
|
||||
expect(el.getAttribute('active')).toBe('true')
|
||||
expect(el.props.active).toBe(true)
|
||||
el.props.active = false
|
||||
expect(el.getAttribute('active')).toBe('false')
|
||||
expect(el.props.active).toBe(false)
|
||||
})
|
||||
|
||||
it('fires onChanges with property/attribute/previousValue/currentValue', () => {
|
||||
const changes = []
|
||||
class WithChanges extends WebComponent {
|
||||
|
|
@ -475,7 +512,10 @@ describe('attribute value & removal handling', () => {
|
|||
expect(el.props.label).toBe('')
|
||||
// regression: must NOT echo back as "true"
|
||||
expect(el.getAttribute('label')).toBe('')
|
||||
expect(changes.at(-1)).toMatchObject({ property: 'label', currentValue: '' })
|
||||
expect(changes.at(-1)).toMatchObject({
|
||||
property: 'label',
|
||||
currentValue: '',
|
||||
})
|
||||
})
|
||||
|
||||
it('resets a prop to its static default when the attribute is removed', () => {
|
||||
|
|
@ -518,7 +558,10 @@ describe('attribute value & removal handling', () => {
|
|||
|
||||
// malformed value must not throw and must still fire onChanges/render
|
||||
expect(() => el.setAttribute('count', 'abc')).not.toThrow()
|
||||
expect(changes.at(-1)).toMatchObject({ property: 'count', currentValue: 'abc' })
|
||||
expect(changes.at(-1)).toMatchObject({
|
||||
property: 'count',
|
||||
currentValue: 'abc',
|
||||
})
|
||||
|
||||
error.mockRestore()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -13,8 +13,14 @@ describe('deserialize', () => {
|
|||
expect(deserialize('false', 'boolean')).toBe(false)
|
||||
})
|
||||
|
||||
test('treats a bare/empty boolean attribute as true', () => {
|
||||
expect(deserialize('', 'boolean')).toBe(true)
|
||||
})
|
||||
|
||||
test('parses object strings', () => {
|
||||
expect(deserialize('{"hello":"world"}', 'object')).toEqual({ hello: 'world' })
|
||||
expect(deserialize('{"hello":"world"}', 'object')).toEqual({
|
||||
hello: 'world',
|
||||
})
|
||||
expect(deserialize('[1,2,3]', 'object')).toEqual([1, 2, 3])
|
||||
expect(deserialize('null', 'object')).toBeNull()
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue