зеркало из https://github.com/github/catalyst.git
Merge pull request #232 from github/fix-up-types-in-tests
Fix up types in tests
This commit is contained in:
Коммит
c7b92eacb1
|
@ -4,3 +4,4 @@ _site
|
|||
lib/
|
||||
.jekyll-cache
|
||||
.lighthouseci
|
||||
coverage
|
||||
|
|
|
@ -23,10 +23,11 @@
|
|||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc --build",
|
||||
"build": "tsc --build tsconfig.build.json",
|
||||
"build:docs": "cd docs && JEKYLL_ENV=production bundle exec jekyll build",
|
||||
"clean": "tsc --build --clean",
|
||||
"clean": "tsc --build --clean tsconfig.build.json",
|
||||
"lint": "eslint . --ignore-path .gitignore",
|
||||
"postlint": "tsc",
|
||||
"prepack": "npm run build",
|
||||
"presize": "npm run build",
|
||||
"size": "size-limit",
|
||||
|
|
14
src/mark.ts
14
src/mark.ts
|
@ -1,9 +1,11 @@
|
|||
type PropertyType = 'field' | 'getter' | 'setter' | 'method'
|
||||
type PropertyDecorator = (proto: object, key: PropertyKey) => void
|
||||
interface PropertyDecorator {
|
||||
(proto: object, key: PropertyKey, descriptor?: PropertyDescriptor): void
|
||||
readonly static: unique symbol
|
||||
}
|
||||
type GetMarks = (instance: object) => Set<PropertyKey>
|
||||
export function createMark(validate: (key: PropertyKey, type: PropertyType) => void): [PropertyDecorator, GetMarks] {
|
||||
const marks = new WeakMap<object, Set<PropertyKey>>()
|
||||
const sym = Symbol()
|
||||
function get(proto: object): Set<PropertyKey> {
|
||||
if (!marks.has(proto)) {
|
||||
const parent = Object.getPrototypeOf(proto)
|
||||
|
@ -22,13 +24,15 @@ export function createMark(validate: (key: PropertyKey, type: PropertyType) => v
|
|||
validate(key, type)
|
||||
get(proto).add(key)
|
||||
}
|
||||
marker.static = sym
|
||||
marker.static = Symbol()
|
||||
|
||||
return [
|
||||
marker,
|
||||
marker as PropertyDecorator,
|
||||
(instance: object): Set<PropertyKey> => {
|
||||
const proto = Object.getPrototypeOf(instance)
|
||||
for (const key of proto.constructor[sym] || []) marker(proto, key, Object.getOwnPropertyDescriptor(proto, key))
|
||||
for (const key of proto.constructor[marker.static] || []) {
|
||||
marker(proto, key, Object.getOwnPropertyDescriptor(proto, key))
|
||||
}
|
||||
return new Set(get(proto))
|
||||
}
|
||||
]
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import {expect, fixture, html} from '@open-wc/testing'
|
||||
import {restore, fake} from 'sinon'
|
||||
import type {CustomElement} from '../src/custom-element.js'
|
||||
import {createAbility, attachShadowCallback, attachInternalsCallback} from '../src/ability.js'
|
||||
|
||||
describe('ability', () => {
|
||||
let calls = []
|
||||
let calls: string[] = []
|
||||
const fakeable = createAbility(
|
||||
Class =>
|
||||
class extends Class {
|
||||
|
@ -22,9 +23,9 @@ describe('ability', () => {
|
|||
calls.push('fakeable adoptedCallback')
|
||||
super.adoptedCallback?.()
|
||||
}
|
||||
attributeChangedCallback(...args) {
|
||||
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
|
||||
calls.push('fakeable attributeChangedCallback')
|
||||
super.attributeChangedCallback?.(...args)
|
||||
super.attributeChangedCallback?.(name, oldValue, newValue)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -46,9 +47,9 @@ describe('ability', () => {
|
|||
calls.push('otherfakeable adoptedCallback')
|
||||
super.adoptedCallback?.()
|
||||
}
|
||||
attributeChangedCallback(...args) {
|
||||
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
|
||||
calls.push('otherfakeable attributeChangedCallback')
|
||||
super.attributeChangedCallback?.(...args)
|
||||
super.attributeChangedCallback?.(name, oldValue, newValue)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -85,9 +86,9 @@ describe('ability', () => {
|
|||
it('can be called multiple times, but only applies once', async () => {
|
||||
const MultipleFakeable = fakeable(fakeable(fakeable(fakeable(fakeable(Element)))))
|
||||
customElements.define('multiple-fakeable', MultipleFakeable)
|
||||
const instance = await fixture(html`<multiple-fakeable />`)
|
||||
const instance: CustomElement = await fixture(html`<multiple-fakeable />`)
|
||||
expect(calls).to.eql(['fakeable connectedCallback'])
|
||||
instance.connectedCallback()
|
||||
instance.connectedCallback!()
|
||||
expect(calls).to.eql(['fakeable connectedCallback', 'fakeable connectedCallback'])
|
||||
})
|
||||
|
||||
|
@ -95,22 +96,22 @@ describe('ability', () => {
|
|||
const CoreTest = otherfakeable(fakeable(Element))
|
||||
customElements.define('core-test', CoreTest)
|
||||
|
||||
let instance
|
||||
let instance: CustomElement & typeof CoreTest
|
||||
beforeEach(async () => {
|
||||
instance = await fixture(html`<core-test />`)
|
||||
})
|
||||
|
||||
it('applies keys from delegate onto subclass upon instantiation', () => {
|
||||
expect(instance).to.have.property('foo')
|
||||
expect(instance.foo()).to.equal('foo!')
|
||||
expect((instance as unknown as Record<string, () => void>).foo()).to.equal('foo!')
|
||||
expect(instance).to.have.property('bar')
|
||||
expect(instance.bar()).to.equal('bar!')
|
||||
expect((instance as unknown as Record<string, () => void>).bar()).to.equal('bar!')
|
||||
})
|
||||
|
||||
for (const method of ['connectedCallback', 'disconnectedCallback', 'adoptedCallback', 'attributeChangedCallback']) {
|
||||
it(`delegates to other ${method}s before class ${method}`, () => {
|
||||
calls = []
|
||||
instance[method]()
|
||||
;(instance as unknown as Record<string, () => void>)[method]()
|
||||
expect(calls).to.eql([`otherfakeable ${method}`, `fakeable ${method}`])
|
||||
})
|
||||
}
|
||||
|
@ -118,8 +119,8 @@ describe('ability', () => {
|
|||
|
||||
describe('ability extension behaviour', () => {
|
||||
describe('attachShadowCallback', () => {
|
||||
let attachShadowFake
|
||||
let shadow
|
||||
let attachShadowFake: (shadow: ShadowRoot) => void
|
||||
let shadow: ShadowRoot | null
|
||||
beforeEach(() => {
|
||||
shadow = null
|
||||
attachShadowFake = fake()
|
||||
|
@ -128,8 +129,8 @@ describe('ability', () => {
|
|||
const declarable = createAbility(
|
||||
Class =>
|
||||
class extends Class {
|
||||
[attachShadowCallback](...args) {
|
||||
super[attachShadowCallback](...args)
|
||||
[attachShadowCallback](...args: [ShadowRoot]) {
|
||||
super[attachShadowCallback]!(...args)
|
||||
return attachShadowFake.apply(this, args)
|
||||
}
|
||||
}
|
||||
|
@ -211,8 +212,8 @@ describe('ability', () => {
|
|||
})
|
||||
|
||||
describe('attachInternalsCallback', () => {
|
||||
let attachInternalsFake
|
||||
let internals
|
||||
let attachInternalsFake: (internals: ElementInternals) => void
|
||||
let internals: ElementInternals | null
|
||||
beforeEach(() => {
|
||||
internals = null
|
||||
attachInternalsFake = fake()
|
||||
|
@ -221,8 +222,8 @@ describe('ability', () => {
|
|||
const internable = createAbility(
|
||||
Class =>
|
||||
class extends Class {
|
||||
[attachInternalsCallback](...args) {
|
||||
super[attachInternalsCallback](...args)
|
||||
[attachInternalsCallback](...args: [ElementInternals]) {
|
||||
super[attachInternalsCallback]!(...args)
|
||||
return attachInternalsFake.apply(this, args)
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +262,7 @@ describe('ability', () => {
|
|||
})
|
||||
|
||||
it('errors if userland calls attachInternals more than once', async () => {
|
||||
const instance = await fixture(html`<manual-internals-ability></manual-internals-ability>`)
|
||||
const instance = await fixture<CustomElement>(html`<manual-internals-ability></manual-internals-ability>`)
|
||||
internals = instance.attachInternals()
|
||||
expect(internals).to.exist.and.be.instanceof(ElementInternals)
|
||||
expect(attachInternalsFake).to.be.calledOnce.calledOn(instance).and.calledWithExactly(internals)
|
||||
|
|
130
test/attr.ts
130
test/attr.ts
|
@ -3,79 +3,79 @@ import {controller} from '../src/controller.js'
|
|||
import {attr} from '../src/attr.js'
|
||||
|
||||
describe('Attr', () => {
|
||||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class InitializeAttrTest extends HTMLElement {
|
||||
@attr fooBar = 'hello'
|
||||
fooBaz = 1
|
||||
{
|
||||
@controller
|
||||
class InitializeAttrTest extends HTMLElement {
|
||||
@attr fooBar = 'hello'
|
||||
fooBaz = 1
|
||||
|
||||
getCount = 0
|
||||
setCount = 0
|
||||
#bing = 'world'
|
||||
get bingBaz() {
|
||||
this.getCount += 1
|
||||
return this.#bing
|
||||
}
|
||||
@attr set bingBaz(value: string) {
|
||||
this.setCount += 1
|
||||
this.#bing = value
|
||||
getCount = 0
|
||||
setCount = 0
|
||||
#bing = 'world'
|
||||
get bingBaz() {
|
||||
this.getCount += 1
|
||||
return this.#bing
|
||||
}
|
||||
@attr set bingBaz(value: string) {
|
||||
this.setCount += 1
|
||||
this.#bing = value
|
||||
}
|
||||
}
|
||||
|
||||
let instance: InitializeAttrTest
|
||||
beforeEach(async () => {
|
||||
instance = await fixture(html`<initialize-attr-test />`)
|
||||
})
|
||||
|
||||
it('does not error during creation', () => {
|
||||
document.createElement('initialize-attr-test')
|
||||
})
|
||||
|
||||
it('does not alter field values from their initial value', () => {
|
||||
expect(instance).to.have.property('fooBar', 'hello')
|
||||
expect(instance).to.have.property('fooBaz', 1)
|
||||
expect(instance).to.have.property('bingBaz', 'world')
|
||||
})
|
||||
|
||||
it('reflects the initial value as an attribute, if not present', () => {
|
||||
expect(instance).to.have.attribute('data-foo-bar', 'hello')
|
||||
expect(instance).to.not.have.attribute('data-foo-baz')
|
||||
expect(instance).to.have.attribute('data-bing-baz', 'world')
|
||||
})
|
||||
|
||||
it('prioritises the value in the attribute over the property', async () => {
|
||||
instance = await fixture(html`<initialize-attr-test data-foo-bar="goodbye" data-bing-baz="universe" />`)
|
||||
expect(instance).to.have.property('fooBar', 'goodbye')
|
||||
expect(instance).to.have.attribute('data-foo-bar', 'goodbye')
|
||||
expect(instance).to.have.property('bingBaz', 'universe')
|
||||
expect(instance).to.have.attribute('data-bing-baz', 'universe')
|
||||
})
|
||||
|
||||
it('changes the property when the attribute changes', async () => {
|
||||
instance.setAttribute('data-foo-bar', 'goodbye')
|
||||
await Promise.resolve()
|
||||
expect(instance).to.have.property('fooBar', 'goodbye')
|
||||
instance.setAttribute('data-bing-baz', 'universe')
|
||||
await Promise.resolve()
|
||||
expect(instance).to.have.property('bingBaz', 'universe')
|
||||
})
|
||||
|
||||
it('changes the attribute when the property changes', () => {
|
||||
instance.fooBar = 'goodbye'
|
||||
expect(instance).to.have.attribute('data-foo-bar', 'goodbye')
|
||||
instance.bingBaz = 'universe'
|
||||
expect(instance).to.have.attribute('data-bing-baz', 'universe')
|
||||
})
|
||||
}
|
||||
|
||||
let instance
|
||||
beforeEach(async () => {
|
||||
instance = await fixture(html`<initialize-attr-test />`)
|
||||
})
|
||||
|
||||
it('does not error during creation', () => {
|
||||
document.createElement('initialize-attr-test')
|
||||
})
|
||||
|
||||
it('does not alter field values from their initial value', () => {
|
||||
expect(instance).to.have.property('fooBar', 'hello')
|
||||
expect(instance).to.have.property('fooBaz', 1)
|
||||
expect(instance).to.have.property('bingBaz', 'world')
|
||||
})
|
||||
|
||||
it('reflects the initial value as an attribute, if not present', () => {
|
||||
expect(instance).to.have.attribute('data-foo-bar', 'hello')
|
||||
expect(instance).to.not.have.attribute('data-foo-baz')
|
||||
expect(instance).to.have.attribute('data-bing-baz', 'world')
|
||||
})
|
||||
|
||||
it('prioritises the value in the attribute over the property', async () => {
|
||||
instance = await fixture(html`<initialize-attr-test data-foo-bar="goodbye" data-bing-baz="universe" />`)
|
||||
expect(instance).to.have.property('fooBar', 'goodbye')
|
||||
expect(instance).to.have.attribute('data-foo-bar', 'goodbye')
|
||||
expect(instance).to.have.property('bingBaz', 'universe')
|
||||
expect(instance).to.have.attribute('data-bing-baz', 'universe')
|
||||
})
|
||||
|
||||
it('changes the property when the attribute changes', async () => {
|
||||
instance.setAttribute('data-foo-bar', 'goodbye')
|
||||
await Promise.resolve()
|
||||
expect(instance).to.have.property('fooBar', 'goodbye')
|
||||
instance.setAttribute('data-bing-baz', 'universe')
|
||||
await Promise.resolve()
|
||||
expect(instance).to.have.property('bingBaz', 'universe')
|
||||
})
|
||||
|
||||
it('changes the attribute when the property changes', () => {
|
||||
instance.fooBar = 'goodbye'
|
||||
expect(instance).to.have.attribute('data-foo-bar', 'goodbye')
|
||||
instance.bingBaz = 'universe'
|
||||
expect(instance).to.have.attribute('data-bing-baz', 'universe')
|
||||
})
|
||||
|
||||
describe('types', () => {
|
||||
it('infers boolean types from property and uses has/toggleAttribute', async () => {
|
||||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class BooleanAttrTest extends HTMLElement {
|
||||
@attr fooBar = false
|
||||
}
|
||||
|
||||
instance = await fixture(html`<boolean-attr-test />`)
|
||||
const instance = await fixture<BooleanAttrTest>(html`<boolean-attr-test />`)
|
||||
|
||||
expect(instance).to.have.property('fooBar', false)
|
||||
expect(instance).to.not.have.attribute('data-foo-bar')
|
||||
|
@ -104,7 +104,6 @@ describe('Attr', () => {
|
|||
|
||||
it('avoids infinite loops', async () => {
|
||||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class LoopAttrTest extends HTMLElement {
|
||||
count = 0
|
||||
@attr
|
||||
|
@ -115,7 +114,8 @@ describe('Attr', () => {
|
|||
this.count += 1
|
||||
}
|
||||
}
|
||||
instance = await fixture(html`<loop-attr-test />`)
|
||||
|
||||
const instance = await fixture<LoopAttrTest>(html`<loop-attr-test />`)
|
||||
|
||||
expect(instance).to.have.property('fooBar')
|
||||
instance.fooBar = 1
|
||||
|
@ -127,13 +127,13 @@ describe('Attr', () => {
|
|||
|
||||
describe('naming', () => {
|
||||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class NamingAttrTest extends HTMLElement {
|
||||
@attr fooBarBazBing = 'a'
|
||||
@attr URLBar = 'b'
|
||||
@attr ClipX = 'c'
|
||||
}
|
||||
|
||||
let instance: NamingAttrTest
|
||||
beforeEach(async () => {
|
||||
instance = await fixture(html`<naming-attr-test />`)
|
||||
})
|
||||
|
|
|
@ -3,9 +3,12 @@ import {replace, fake} from 'sinon'
|
|||
import {autoShadowRoot} from '../src/auto-shadow-root.js'
|
||||
|
||||
describe('autoShadowRoot', () => {
|
||||
window.customElements.define('shadowroot-test-element', class extends HTMLElement {})
|
||||
class ShadowRootTestElement extends HTMLElement {
|
||||
declare shadowRoot: ShadowRoot
|
||||
}
|
||||
window.customElements.define('shadowroot-test-element', ShadowRootTestElement)
|
||||
|
||||
let instance
|
||||
let instance: ShadowRootTestElement
|
||||
beforeEach(async () => {
|
||||
instance = await fixture(html`<shadowroot-test-element />`)
|
||||
})
|
||||
|
@ -58,7 +61,7 @@ describe('autoShadowRoot', () => {
|
|||
instance = await fixture(html`<shadowroot-test-element>
|
||||
<template data-shadowroot="closed">Hello World</template>
|
||||
</shadowroot-test-element>`)
|
||||
let shadowRoot = null
|
||||
let shadowRoot: ShadowRoot | null = null
|
||||
replace(
|
||||
instance,
|
||||
'attachShadow',
|
||||
|
|
32
test/bind.ts
32
test/bind.ts
|
@ -3,18 +3,16 @@ import {replace, fake} from 'sinon'
|
|||
import {bind, listenForBind} from '../src/bind.js'
|
||||
|
||||
describe('bind', () => {
|
||||
window.customElements.define(
|
||||
'bind-test-element',
|
||||
class extends HTMLElement {
|
||||
foo = fake()
|
||||
bar = fake()
|
||||
handleEvent = fake()
|
||||
}
|
||||
)
|
||||
class BindTestElement extends HTMLElement {
|
||||
foo = fake()
|
||||
bar = fake()
|
||||
handleEvent = fake()
|
||||
}
|
||||
window.customElements.define('bind-test-element', BindTestElement)
|
||||
|
||||
let instance
|
||||
let instance: BindTestElement
|
||||
beforeEach(async () => {
|
||||
instance = await fixture(html`<bind-test-element />`)
|
||||
instance = await fixture<BindTestElement>(html`<bind-test-element />`)
|
||||
})
|
||||
|
||||
it('binds events on elements based on their data-action attribute', () => {
|
||||
|
@ -47,7 +45,7 @@ describe('bind', () => {
|
|||
|
||||
it('does not bind elements whose closest selector is not this controller', () => {
|
||||
const el = document.createElement('div')
|
||||
el.getAttribute('data-action', 'click:bind-test-element#foo')
|
||||
el.setAttribute('data-action', 'click:bind-test-element#foo')
|
||||
const container = document.createElement('div')
|
||||
container.append(instance, el)
|
||||
bind(instance)
|
||||
|
@ -157,7 +155,7 @@ describe('bind', () => {
|
|||
const el2 = document.createElement('div')
|
||||
el1.setAttribute('data-action', 'click:bind-test-element#foo')
|
||||
el2.setAttribute('data-action', 'submit:bind-test-element#foo')
|
||||
instance.shadowRoot.append(el1, el2)
|
||||
instance.shadowRoot!.append(el1, el2)
|
||||
bind(instance)
|
||||
expect(instance.foo).to.have.callCount(0)
|
||||
el1.click()
|
||||
|
@ -173,8 +171,8 @@ describe('bind', () => {
|
|||
el1.setAttribute('data-action', 'click:bind-test-element#foo')
|
||||
el2.setAttribute('data-action', 'submit:bind-test-element#foo')
|
||||
bind(instance)
|
||||
instance.shadowRoot.append(el1)
|
||||
instance.shadowRoot.append(el2)
|
||||
instance.shadowRoot!.append(el1)
|
||||
instance.shadowRoot!.append(el2)
|
||||
// We need to wait for one microtask after injecting the HTML into to
|
||||
// controller so that the actions have been bound to the controller.
|
||||
await Promise.resolve()
|
||||
|
@ -267,7 +265,7 @@ describe('bind', () => {
|
|||
// We need to wait for one microtask after injecting the HTML into to
|
||||
// controller so that the actions have been bound to the controller.
|
||||
await Promise.resolve()
|
||||
instance.querySelector('button').click()
|
||||
instance.querySelector('button')!.click()
|
||||
expect(instance.foo).to.have.callCount(1)
|
||||
})
|
||||
|
||||
|
@ -277,7 +275,7 @@ describe('bind', () => {
|
|||
</bind-test-element>`)
|
||||
bind(instance)
|
||||
expect(instance.foo).to.have.callCount(0)
|
||||
const el = instance.querySelector('div')
|
||||
const el = instance.querySelector('div')!
|
||||
el.click()
|
||||
expect(instance.foo).to.have.callCount(1)
|
||||
el.setAttribute('data-action', 'click:other-element#foo')
|
||||
|
@ -292,7 +290,7 @@ describe('bind', () => {
|
|||
bind(instance)
|
||||
listenForBind(instance.ownerDocument)
|
||||
await Promise.resolve()
|
||||
const button = instance.querySelector('button')
|
||||
const button = instance.querySelector('button')!
|
||||
button.click()
|
||||
expect(instance.foo).to.have.callCount(0)
|
||||
button.setAttribute('data-action', 'click:bind-test-element#foo')
|
||||
|
|
|
@ -25,7 +25,6 @@ describe('controller', () => {
|
|||
|
||||
it('binds controllers before custom connectedCallback behaviour', async () => {
|
||||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class ControllerBindOrderElement extends HTMLElement {
|
||||
foo = fake()
|
||||
}
|
||||
|
@ -36,7 +35,7 @@ describe('controller', () => {
|
|||
this.dispatchEvent(new CustomEvent('loaded'))
|
||||
}
|
||||
}
|
||||
instance = await fixture(html`
|
||||
instance = await fixture<ControllerBindOrderElement>(html`
|
||||
<controller-bind-order>
|
||||
<controller-bind-order-sub data-action="loaded:controller-bind-order#foo" />
|
||||
</controller-bind-order>
|
||||
|
@ -46,36 +45,34 @@ describe('controller', () => {
|
|||
|
||||
it('binds shadowRoots after connectedCallback behaviour', async () => {
|
||||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class ControllerBindShadowElement extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.attachShadow({mode: 'open'})
|
||||
const button = document.createElement('button')
|
||||
button.setAttribute('data-action', 'click:controller-bind-shadow#foo')
|
||||
this.shadowRoot.appendChild(button)
|
||||
this.shadowRoot!.appendChild(button)
|
||||
}
|
||||
|
||||
foo() {
|
||||
return 'foo'
|
||||
}
|
||||
}
|
||||
instance = await fixture(html`<controller-bind-shadow />`)
|
||||
instance = await fixture<ControllerBindShadowElement>(html`<controller-bind-shadow />`)
|
||||
replace(instance, 'foo', fake(instance.foo))
|
||||
|
||||
instance.shadowRoot.querySelector('button').click()
|
||||
instance.shadowRoot!.querySelector('button')!.click()
|
||||
|
||||
expect(instance.foo).to.have.callCount(1)
|
||||
})
|
||||
|
||||
it('binds auto shadowRoots', async () => {
|
||||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class ControllerBindAutoShadowElement extends HTMLElement {
|
||||
foo() {
|
||||
return 'foo'
|
||||
}
|
||||
}
|
||||
instance = await fixture(html`
|
||||
instance = await fixture<ControllerBindAutoShadowElement>(html`
|
||||
<controller-bind-auto-shadow>
|
||||
<template data-shadowroot="open">
|
||||
<button data-action="click:controller-bind-auto-shadow#foo" />
|
||||
|
@ -86,8 +83,8 @@ describe('controller', () => {
|
|||
|
||||
expect(instance.shadowRoot).to.exist
|
||||
expect(instance).to.have.property('shadowRoot').not.equal(null)
|
||||
expect(instance.shadowRoot.children).to.have.lengthOf(1)
|
||||
instance.shadowRoot.querySelector('button').click()
|
||||
expect(instance.shadowRoot!.children).to.have.lengthOf(1)
|
||||
instance.shadowRoot!.querySelector('button')!.click()
|
||||
|
||||
expect(instance.foo).to.have.callCount(1)
|
||||
})
|
||||
|
@ -97,15 +94,14 @@ describe('controller', () => {
|
|||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class ChildElementElement extends HTMLElement {}
|
||||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class ParentElementElement extends HTMLElement {
|
||||
connectedCallback() {
|
||||
const child = this.querySelector('child-element')
|
||||
const child = this.querySelector('child-element')!
|
||||
expect(child.matches(':defined')).to.equal(true)
|
||||
}
|
||||
}
|
||||
|
||||
instance = await fixture(html`
|
||||
instance = await fixture<ParentElementElement>(html`
|
||||
<parent-element>
|
||||
<child-element />
|
||||
</parent-element>
|
||||
|
@ -113,12 +109,12 @@ describe('controller', () => {
|
|||
})
|
||||
|
||||
describe('attrs', () => {
|
||||
let attrValues = []
|
||||
let attrValues: string[] = []
|
||||
@controller
|
||||
class AttributeTestElement extends HTMLElement {
|
||||
foo = 'baz'
|
||||
attributeChangedCallback() {
|
||||
attrValues.push(this.getAttribute('data-foo'))
|
||||
attrValues.push(this.getAttribute('data-foo')!)
|
||||
attrValues.push(this.foo)
|
||||
}
|
||||
}
|
||||
|
@ -129,14 +125,14 @@ describe('controller', () => {
|
|||
})
|
||||
|
||||
it('initializes attrs as attributes in attributeChangedCallback', async () => {
|
||||
instance = await fixture(html`<attribute-test></attribute-test>`)
|
||||
instance = await fixture<AttributeTestElement>(html`<attribute-test></attribute-test>`)
|
||||
instance.foo = 'bar'
|
||||
instance.attributeChangedCallback()
|
||||
expect(attrValues).to.eql(['bar', 'bar'])
|
||||
})
|
||||
|
||||
it('initializes attributes as attrs in attributeChangedCallback', async () => {
|
||||
instance = await fixture(html`<attribute-test />`)
|
||||
instance = await fixture<AttributeTestElement>(html`<attribute-test />`)
|
||||
instance.setAttribute('data-foo', 'bar')
|
||||
instance.attributeChangedCallback()
|
||||
expect(attrValues).to.eql(['bar', 'bar'])
|
||||
|
|
|
@ -2,7 +2,7 @@ import {expect} from '@open-wc/testing'
|
|||
import {dasherize} from '../src/dasherize.js'
|
||||
|
||||
describe('dasherize', () => {
|
||||
const tests = [
|
||||
const tests: Array<[PropertyKey, string]> = [
|
||||
['json', 'json'],
|
||||
['fooBar', 'foo-bar'],
|
||||
['FooBar', 'foo-bar'],
|
||||
|
|
88
test/mark.ts
88
test/mark.ts
|
@ -6,8 +6,8 @@ describe('createMark', () => {
|
|||
it('returns a tuple of functions: a mark and getMarks', () => {
|
||||
const mark = createMark(() => {})
|
||||
expect(mark).to.be.an('array').with.lengthOf(2)
|
||||
expect(mark).to.have.property(0).a('function')
|
||||
expect(mark).to.have.property(1).a('function')
|
||||
expect(mark).to.have.property('0').a('function')
|
||||
expect(mark).to.have.property('1').a('function')
|
||||
})
|
||||
|
||||
it('attaches a `static` unique symbol to the first function', () => {
|
||||
|
@ -20,7 +20,7 @@ describe('createMark', () => {
|
|||
it('can be added to class fields without errors', () => {
|
||||
const [mark] = createMark(() => {})
|
||||
class FooBar {
|
||||
@mark foo
|
||||
@mark foo: unknown
|
||||
@mark bar = 1
|
||||
@mark baz = 'hi'
|
||||
}
|
||||
|
@ -30,11 +30,15 @@ describe('createMark', () => {
|
|||
it('can be added to getters or setters without errors', () => {
|
||||
const [mark] = createMark(() => {})
|
||||
class FooBar {
|
||||
@mark get foo() {}
|
||||
set foo(v) {}
|
||||
@mark get foo() {
|
||||
return 1
|
||||
}
|
||||
set foo(v: number) {}
|
||||
|
||||
@mark get bar() {}
|
||||
@mark set baz(v) {}
|
||||
@mark get bar() {
|
||||
return 1
|
||||
}
|
||||
@mark set baz(v: number) {}
|
||||
}
|
||||
new FooBar()
|
||||
})
|
||||
|
@ -50,13 +54,17 @@ describe('createMark', () => {
|
|||
it('retrieves all marked fields with the get mark function', () => {
|
||||
const [mark, getMark] = createMark(() => {})
|
||||
class FooBar {
|
||||
@mark foo
|
||||
@mark foo: unknown
|
||||
@mark bar = 1
|
||||
@mark baz = 'hi'
|
||||
@mark get bing() {}
|
||||
@mark get qux() {}
|
||||
@mark set quuz(v) {}
|
||||
@mark set corge(v) {}
|
||||
@mark get bing() {
|
||||
return 1
|
||||
}
|
||||
@mark get qux() {
|
||||
return 1
|
||||
}
|
||||
@mark set quuz(v: number) {}
|
||||
@mark set corge(v: number) {}
|
||||
@mark grault() {}
|
||||
}
|
||||
expect(getMark(new FooBar())).to.eql(new Set(['foo', 'bar', 'baz', 'bing', 'qux', 'quuz', 'corge', 'grault']))
|
||||
|
@ -75,13 +83,17 @@ describe('createMark', () => {
|
|||
const [mark, getMark] = createMark(() => {})
|
||||
class FooBar {
|
||||
static [mark.static] = ['bar', 'bing', 'quuz', 'grault']
|
||||
@mark foo
|
||||
@mark foo: unknown
|
||||
bar = 1
|
||||
@mark baz = 'hi'
|
||||
get bing() {}
|
||||
@mark get qux() {}
|
||||
set quuz(v) {}
|
||||
@mark set corge(v) {}
|
||||
get bing() {
|
||||
return 1
|
||||
}
|
||||
@mark get qux() {
|
||||
return 1
|
||||
}
|
||||
set quuz(v: number) {}
|
||||
@mark set corge(v: number) {}
|
||||
grault() {}
|
||||
}
|
||||
const instance = new FooBar()
|
||||
|
@ -92,13 +104,17 @@ describe('createMark', () => {
|
|||
const [mark, getMark] = createMark(() => {})
|
||||
class FooBar {
|
||||
static [mark.static] = ['bar', 'bing', 'quuz', 'grault']
|
||||
@mark foo
|
||||
@mark foo: unknown
|
||||
@mark bar = 1
|
||||
@mark baz = 'hi'
|
||||
@mark get bing() {}
|
||||
@mark get qux() {}
|
||||
@mark set quuz(v) {}
|
||||
@mark set corge(v) {}
|
||||
@mark get bing() {
|
||||
return 1
|
||||
}
|
||||
@mark get qux() {
|
||||
return 1
|
||||
}
|
||||
@mark set quuz(v: number) {}
|
||||
@mark set corge(v: number) {}
|
||||
@mark grault() {}
|
||||
}
|
||||
expect(getMark(new FooBar())).to.eql(new Set(['foo', 'bar', 'baz', 'bing', 'qux', 'quuz', 'corge', 'grault']))
|
||||
|
@ -109,13 +125,17 @@ describe('createMark', () => {
|
|||
const [mark] = createMark(validate)
|
||||
const sym = Symbol('garply')
|
||||
class FooBar {
|
||||
@mark foo
|
||||
@mark foo: unknown
|
||||
@mark bar = 1
|
||||
@mark baz = 'hi'
|
||||
@mark get bing() {}
|
||||
@mark get qux() {}
|
||||
@mark set quuz(v) {}
|
||||
@mark set corge(v) {}
|
||||
@mark get bing() {
|
||||
return 1
|
||||
}
|
||||
@mark get qux() {
|
||||
return 1
|
||||
}
|
||||
@mark set quuz(v: number) {}
|
||||
@mark set corge(v: number) {}
|
||||
@mark grault() {}
|
||||
@mark [sym]() {}
|
||||
}
|
||||
|
@ -136,13 +156,17 @@ describe('createMark', () => {
|
|||
const [mark, getMark] = createMark(validate)
|
||||
class FooBar {
|
||||
static [mark.static] = ['foo', 'bar', 'baz', 'bing', 'qux', 'quuz', 'corge', 'grault']
|
||||
foo
|
||||
foo: unknown
|
||||
bar = 1
|
||||
baz = 'hi'
|
||||
get bing() {}
|
||||
get qux() {}
|
||||
set quuz(v) {}
|
||||
set corge(v) {}
|
||||
get bing() {
|
||||
return 1
|
||||
}
|
||||
get qux() {
|
||||
return 1
|
||||
}
|
||||
set quuz(v: number) {}
|
||||
set corge(v: number) {}
|
||||
grault() {}
|
||||
}
|
||||
getMark(new FooBar())
|
||||
|
|
|
@ -9,19 +9,19 @@ describe('register', () => {
|
|||
|
||||
it('registers the class as a custom element, normalising the class name', () => {
|
||||
@register
|
||||
class MyFirstClass {}
|
||||
class MyFirstClass extends HTMLElement {}
|
||||
expect(window.customElements.get('my-first-class')).to.equal(MyFirstClass)
|
||||
})
|
||||
|
||||
it('does not register controllers that already exist', () => {
|
||||
{
|
||||
@register
|
||||
class MySecondClass {}
|
||||
class MySecondClass extends HTMLElement {}
|
||||
expect(window.customElements.get('my-second-class')).to.equal(MySecondClass)
|
||||
}
|
||||
{
|
||||
@register
|
||||
class MySecondClass {}
|
||||
class MySecondClass extends HTMLElement {}
|
||||
expect(window.customElements.get('my-second-class')).to.not.equal(MySecondClass)
|
||||
}
|
||||
})
|
||||
|
@ -31,23 +31,23 @@ describe('register', () => {
|
|||
replace(
|
||||
customElements,
|
||||
'get',
|
||||
fake(() => class {})
|
||||
fake(() => class extends HTMLElement {})
|
||||
)
|
||||
{
|
||||
@register
|
||||
class MyThirdClass {}
|
||||
class MyThirdClass extends HTMLElement {}
|
||||
expect(customElements.define).to.be.calledOnceWithExactly('my-third-class', MyThirdClass)
|
||||
}
|
||||
expect(() => {
|
||||
@register
|
||||
class MyThirdClass {}
|
||||
class MyThirdClass extends HTMLElement {}
|
||||
expect(customElements.define).to.be.calledOnceWithExactly('my-third-class', MyThirdClass)
|
||||
}).to.throw(Error)
|
||||
})
|
||||
|
||||
it('dasherises class names', () => {
|
||||
@register
|
||||
class ThisIsAnExampleOfDasherisedClassNames {}
|
||||
class ThisIsAnExampleOfDasherisedClassNames extends HTMLElement {}
|
||||
expect(window.customElements.get('this-is-an-example-of-dasherised-class-names')).to.equal(
|
||||
ThisIsAnExampleOfDasherisedClassNames
|
||||
)
|
||||
|
@ -55,19 +55,19 @@ describe('register', () => {
|
|||
|
||||
it('will intuitively dasherize acryonyms', () => {
|
||||
@register
|
||||
class URLBar {}
|
||||
class URLBar extends HTMLElement {}
|
||||
expect(window.customElements.get('url-bar')).to.equal(URLBar)
|
||||
})
|
||||
|
||||
it('dasherizes cap suffixed names correctly', () => {
|
||||
@register
|
||||
class ClipX {}
|
||||
class ClipX extends HTMLElement {}
|
||||
expect(window.customElements.get('clip-x')).to.equal(ClipX)
|
||||
})
|
||||
|
||||
it('automatically drops the `Element` suffix', () => {
|
||||
@register
|
||||
class FirstSuffixElement {}
|
||||
class FirstSuffixElement extends HTMLElement {}
|
||||
expect(window.customElements.get('first-suffix')).to.equal(FirstSuffixElement)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -6,20 +6,20 @@ describe('Targetable', () => {
|
|||
@controller
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
class TargetTestElement extends HTMLElement {
|
||||
@target foo
|
||||
@target foo!: Element
|
||||
bar = 'hello'
|
||||
@target baz
|
||||
@target qux
|
||||
@target shadow
|
||||
@target baz!: Element
|
||||
@target qux!: Element
|
||||
@target shadow!: Element
|
||||
|
||||
@target bing
|
||||
@targets foos
|
||||
@target bing!: Element
|
||||
@targets foos!: Element[]
|
||||
bars = 'hello'
|
||||
@target quxs
|
||||
@target shadows
|
||||
@target quxs!: Element[]
|
||||
@target shadows!: Element[]
|
||||
}
|
||||
|
||||
let instance
|
||||
let instance: HTMLElement
|
||||
beforeEach(async () => {
|
||||
instance = await fixture(html`<target-test>
|
||||
<target-test>
|
||||
|
@ -61,7 +61,7 @@ describe('Targetable', () => {
|
|||
instance.attachShadow({mode: 'open'})
|
||||
const el = document.createElement('div')
|
||||
el.setAttribute('data-target', 'target-test.shadow')
|
||||
instance.shadowRoot.appendChild(el)
|
||||
instance.shadowRoot!.appendChild(el)
|
||||
expect(instance).to.have.property('shadow', el)
|
||||
})
|
||||
|
||||
|
@ -69,7 +69,7 @@ describe('Targetable', () => {
|
|||
instance.attachShadow({mode: 'open'})
|
||||
const shadowEl = document.createElement('div')
|
||||
shadowEl.setAttribute('data-target', 'target-test.foo')
|
||||
instance.shadowRoot.appendChild(shadowEl)
|
||||
instance.shadowRoot!.appendChild(shadowEl)
|
||||
expect(instance).to.have.property('foo', shadowEl)
|
||||
})
|
||||
})
|
||||
|
@ -85,7 +85,7 @@ describe('Targetable', () => {
|
|||
instance.attachShadow({mode: 'open'})
|
||||
const els = [document.createElement('div'), document.createElement('div'), document.createElement('div')]
|
||||
for (const el of els) el.setAttribute('data-targets', 'target-test.foos')
|
||||
instance.shadowRoot.append(...els)
|
||||
instance.shadowRoot!.append(...els)
|
||||
|
||||
expect(instance).to.have.property('foos').with.lengthOf(5)
|
||||
expect(instance).to.have.nested.property('foos[0]', els[0])
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"exclude": ["test"],
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"outDir": "./lib",
|
||||
"noEmit": false
|
||||
}
|
||||
}
|
|
@ -1,16 +1,13 @@
|
|||
{
|
||||
"include": ["src"],
|
||||
"include": ["src", "test"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"lib": ["es6", "dom", "dom.iterable"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"noEmit": false,
|
||||
"outDir": "./lib",
|
||||
"noEmit": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"target": "ES2020"
|
||||
|
|
Загрузка…
Ссылка в новой задаче