Skip to content

Commit 4e25629

Browse files
committed
fix nested & partial providers
If a provider cannot supply a value it should not, and so we need to check if it has the available `@provide` name. If a provider _can_ supply a value it should stopPropagation to avoid letting other providers assign and callback.
1 parent e9ed847 commit 4e25629

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

src/providable.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,14 @@ export const providable = createAbility(
8686
constructor(...args: any[]) {
8787
super(...args)
8888
initProvide(this)
89-
if (getProvide(this).size) {
89+
const provides = getProvide(this)
90+
if (provides.size) {
9091
if (!contexts.has(this)) contexts.set(this, new Map())
9192
const instanceContexts = contexts.get(this)!
9293
this.addEventListener('context-request', event => {
9394
if (!isContextEvent(event)) return
9495
const name = event.context.name
96+
if (!provides.has(name)) return
9597
const value = this[name]
9698
const dispose = () => instanceContexts.get(name)?.delete(callback)
9799
const eventCallback = event.callback
@@ -100,6 +102,7 @@ export const providable = createAbility(
100102
if (!instanceContexts.has(name)) instanceContexts.set(name, new Set())
101103
instanceContexts.get(name)!.add(callback)
102104
}
105+
event.stopPropagation()
103106
callback(value)
104107
})
105108
}

test/providable.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ describe('Providable', () => {
1616
}
1717
window.customElements.define('providable-provider-test', ProvidableProviderTest)
1818

19+
@providable
20+
class ProvidableSomeProviderTest extends HTMLElement {
21+
@provide foo = 'greetings'
22+
bar = 'universe'
23+
baz = 18
24+
@provide qux = 42
25+
}
26+
window.customElements.define('providable-some-provider-test', ProvidableSomeProviderTest)
27+
1928
@providable
2029
class ProvidableConsumerTest extends HTMLElement {
2130
@consume foo = 'goodbye'
@@ -225,6 +234,49 @@ describe('Providable', () => {
225234
})
226235
})
227236

237+
describe('consumer with nested provider parents', () => {
238+
let provider: ProvidableProviderTest
239+
let someProvider: ProvidableSomeProviderTest
240+
let consumer: ProvidableConsumerTest
241+
beforeEach(async () => {
242+
provider = await fixture(html`<providable-provider-test>
243+
<main>
244+
<article>
245+
<providable-some-provider-test>
246+
<section>
247+
<div>
248+
<providable-consumer-test></providable-consumer-test>
249+
</div>
250+
</section>
251+
</providable-some-provider-test>
252+
</article>
253+
</main>
254+
</providable-provider-test>`)
255+
someProvider = provider.querySelector<ProvidableSomeProviderTest>('providable-some-provider-test')!
256+
consumer = provider.querySelector<ProvidableConsumerTest>('providable-consumer-test')!
257+
})
258+
259+
it('only recieves provider responses from first matching provider', () => {
260+
expect(consumer).to.have.property('foo', 'greetings')
261+
expect(consumer).to.have.property('bar', 'world')
262+
expect(consumer).to.have.property('baz', 3)
263+
expect(consumer).to.have.property(sym).eql({provided: true})
264+
expect(consumer).to.have.property('qux').eql(42)
265+
expect(consumer).to.have.property('count').eql(1)
266+
})
267+
268+
it('only updates on appropriate provider changing values', () => {
269+
expect(consumer).to.have.property('qux').eql(42)
270+
expect(consumer).to.have.property('count').eql(1)
271+
provider.qux = 12
272+
expect(consumer).to.have.property('qux').eql(42)
273+
expect(consumer).to.have.property('count').eql(1)
274+
someProvider.qux = 88
275+
expect(consumer).to.have.property('qux').eql(88)
276+
expect(consumer).to.have.property('count').eql(2)
277+
})
278+
})
279+
228280
describe('error scenarios', () => {
229281
it('cannot decorate methods as providers', () => {
230282
expect(() => {

0 commit comments

Comments
 (0)