Skip to content

Commit

Permalink
Invoke promise fix (#208)
Browse files Browse the repository at this point in the history
* fix: do not fire promise events after state changes

* chore: update tests

* Add a changeset

Create odd-lizards-guess.md

* Fix typo

Co-authored-by: edwardsnjd <[email protected]>

* Fix typo

Co-authored-by: edwardsnjd <[email protected]>

---------

Co-authored-by: Ruslan Kyba <[email protected]>
Co-authored-by: edwardsnjd <[email protected]>
  • Loading branch information
3 people authored Jul 17, 2024
1 parent c953ce8 commit 1fc7737
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/odd-lizards-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"robot3": patch
---

Don't make a state transition if the state is left before the invoked promise resolves, *even* if there's a transition with the same name.
11 changes: 9 additions & 2 deletions packages/core/machine.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,15 @@ let invokeFnType = {
machine: valueEnumerable(rn),
transitions: valueEnumerable(this.transitions)
}).enter(machine2, service, event)
rn.then(data => service.send({ type: 'done', data }))
.catch(error => service.send({ type: 'error', error }));
rn
.then(data => {
if (machine2 === service.machine)
return service.send({ type: 'done', data });
})
.catch(error => {
if (machine2 === service.machine)
return service.send({ type: 'error', error });
});
return machine2;
}
};
Expand Down
44 changes: 44 additions & 0 deletions packages/core/test/test-invoke.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,50 @@ QUnit.module('Invoke', hooks => {
assert.equal(service.machine.current, 'two', 'in the new state');
});

QUnit.test('Should not fire "done" event when state changes', async assert => {
const wait = ms => () => new Promise(resolve => setTimeout(resolve, ms));

let machine = createMachine({
one: state(transition('click', 'two')),
two: invoke(wait(10),
transition('done', 'one'),
transition('click', 'three')
),
three: state(
transition('done', 'error'),
),
error: state(),
});

let service = interpret(machine, () => { });
service.send('click');
service.send('click');
await wait(15)()
assert.equal(service.machine.current, 'three', 'now in the next state');
});

QUnit.test('Should fire "done" when context changes', async assert => {
const wait = ms => () => new Promise(resolve => setTimeout(resolve, ms));

let machine = createMachine({
one: state(transition('click', 'two')),
two: invoke(wait(10),
transition('done', 'three'),
transition('click', 'two', reduce((ctx) => ({ value: ctx.value + 1 })))
),
three: state(),
error: state(),
}, () => ({ value: 0 }));

let service = interpret(machine, () => { });
service.send('click');
service.send('click');
service.send('click');
await wait(15)()
assert.equal(service.context.value, 2, 'value should be 2');
assert.equal(service.machine.current, 'three', 'now in the correct state');
});

QUnit.module('Machine');

QUnit.test('Can invoke a child machine', async assert => {
Expand Down

0 comments on commit 1fc7737

Please sign in to comment.