Skip to content

Commit e9ed847

Browse files
committed
fix bug in providable where it should only dispose of older disposers
This was causing values to be discarded after the first change which is a mistake. The disposer should be called only if it recieves a new one (meaning a different provider has entered the ring).
1 parent a570551 commit e9ed847

2 files changed

Lines changed: 47 additions & 10 deletions

File tree

src/providable.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ const [consume, getConsume, initConsume] = createMark<CustomElement>(
5858
(value: unknown, dispose?: () => void) => {
5959
if (!disposes.has(instance)) disposes.set(instance, new Map())
6060
const instanceDisposes = disposes.get(instance)!
61-
if (instanceDisposes.has(name)) instanceDisposes.get(name)!()
61+
if (instanceDisposes.has(name)) {
62+
const oldDispose = instanceDisposes.get(name)!
63+
if (oldDispose !== dispose) oldDispose()
64+
}
6265
if (dispose) instanceDisposes.set(name, dispose)
6366
currentValue = value
6467
access.set?.call(instance, currentValue)
@@ -84,18 +87,20 @@ export const providable = createAbility(
8487
super(...args)
8588
initProvide(this)
8689
if (getProvide(this).size) {
90+
if (!contexts.has(this)) contexts.set(this, new Map())
91+
const instanceContexts = contexts.get(this)!
8792
this.addEventListener('context-request', event => {
8893
if (!isContextEvent(event)) return
8994
const name = event.context.name
9095
const value = this[name]
91-
const callback = event.callback
96+
const dispose = () => instanceContexts.get(name)?.delete(callback)
97+
const eventCallback = event.callback
98+
const callback = (newValue: unknown) => eventCallback(newValue, dispose)
9299
if (event.multiple) {
93-
if (!contexts.has(this)) contexts.set(this, new Map())
94-
const instanceContexts = contexts.get(this)!
95100
if (!instanceContexts.has(name)) instanceContexts.set(name, new Set())
96101
instanceContexts.get(name)!.add(callback)
97102
}
98-
callback(value, () => contexts.get(this)?.get(name)?.delete(callback))
103+
callback(value)
99104
})
100105
}
101106
}

test/providable.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,15 @@ describe('Providable', () => {
3939

4040
describe('consumer without provider', () => {
4141
let instance: ProvidableConsumerTest
42+
let events = fake()
4243
beforeEach(async () => {
44+
events = fake()
45+
document.body.addEventListener('context-request', events)
4346
instance = await fixture(html`<providable-consumer-test />`)
4447
})
48+
afterEach(() => {
49+
document.body.removeEventListener('context-request', events)
50+
})
4551

4652
it('uses the given values', () => {
4753
expect(instance).to.have.property('foo', 'goodbye')
@@ -59,11 +65,6 @@ describe('Providable', () => {
5965
})
6066

6167
it('emits the `context-request` event when connected, for each field', async () => {
62-
instance = document.createElement('providable-consumer-test') as ProvidableConsumerTest
63-
const events = fake()
64-
instance.addEventListener('context-request', events)
65-
await fixture(instance)
66-
6768
expect(events).to.have.callCount(5)
6869
const fooEvent = events.getCall(0).args[0]
6970
expect(fooEvent).to.be.instanceof(ContextEvent)
@@ -100,6 +101,34 @@ describe('Providable', () => {
100101
expect(quxEvent).to.have.property('multiple', true)
101102
expect(quxEvent).to.have.property('bubbles', true)
102103
})
104+
105+
it('changes value based on callback new value', async () => {
106+
expect(events).to.have.callCount(5)
107+
const fooCallback = events.getCall(0).args[0].callback
108+
fooCallback('hello')
109+
expect(instance).to.have.property('foo', 'hello')
110+
fooCallback('goodbye')
111+
expect(instance).to.have.property('foo', 'goodbye')
112+
})
113+
114+
it('disposes of past callbacks when given new ones', async () => {
115+
const dispose1 = fake()
116+
const dispose2 = fake()
117+
expect(events).to.have.callCount(5)
118+
const fooCallback = events.getCall(0).args[0].callback
119+
fooCallback('hello', dispose1)
120+
expect(dispose1).to.have.callCount(0)
121+
expect(dispose2).to.have.callCount(0)
122+
fooCallback('goodbye', dispose1)
123+
expect(dispose1).to.have.callCount(0)
124+
expect(dispose2).to.have.callCount(0)
125+
fooCallback('greetings', dispose2)
126+
expect(dispose1).to.have.callCount(1)
127+
expect(dispose2).to.have.callCount(0)
128+
fooCallback('hola', dispose1)
129+
expect(dispose1).to.have.callCount(1)
130+
expect(dispose2).to.have.callCount(1)
131+
})
103132
})
104133

105134
describe('provider', () => {
@@ -190,6 +219,9 @@ describe('Providable', () => {
190219
provider.qux = 17
191220
expect(consumer).to.have.property('qux', 17)
192221
expect(consumer).to.have.property('count', 2)
222+
provider.qux = 18
223+
expect(consumer).to.have.property('qux', 18)
224+
expect(consumer).to.have.property('count', 3)
193225
})
194226
})
195227

0 commit comments

Comments
 (0)