Skip to content

Commit

Permalink
Notify the error listener when subscribing to an errored actor (#4570)
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist authored Dec 7, 2023
1 parent a5c55fa commit c111273
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/rich-ears-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'xstate': patch
---

Fixed an issue that caused a `complete` listener to be called instead of the `error` one when the actor was subscribed after being stopped.
25 changes: 21 additions & 4 deletions packages/core/src/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,27 @@ export class Actor<TLogic extends AnyActorLogic>
if (this._processingStatus !== ProcessingStatus.Stopped) {
this.observers.add(observer);
} else {
try {
observer.complete?.();
} catch (err) {
reportUnhandledError(err);
switch ((this._snapshot as any).status) {
case 'done':
try {
observer.complete?.();
} catch (err) {
reportUnhandledError(err);
}
break;
case 'error': {
const err = (this._snapshot as any).error;
if (!observer.error) {
reportUnhandledError(err);
} else {
try {
observer.error(err);
} catch (err) {
reportUnhandledError(err);
}
}
break;
}
}
}

Expand Down
53 changes: 53 additions & 0 deletions packages/core/test/interpreter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1849,3 +1849,56 @@ it('should not process events sent directly to own actor ref before initial entr
'EV transition'
]);
});

it('should not notify the completion observer for an active logic when it gets subscribed before starting', () => {
const spy = jest.fn();

const machine = createMachine({});
createActor(machine).subscribe({ complete: spy });

expect(spy).not.toHaveBeenCalled();
});

it('should not notify the completion observer for an errored logic when it gets subscribed after it errors', () => {
const spy = jest.fn();

const machine = createMachine({
entry: () => {
throw new Error('error');
}
});
const actorRef = createActor(machine);
actorRef.subscribe({ error: () => {} });
actorRef.start();

actorRef.subscribe({
complete: spy
});

expect(spy).not.toHaveBeenCalled();
});

it('should notify the error observer for an errored logic when it gets subscribed after it errors', () => {
const spy = jest.fn();

const machine = createMachine({
entry: () => {
throw new Error('error');
}
});
const actorRef = createActor(machine);
actorRef.subscribe({ error: () => {} });
actorRef.start();

actorRef.subscribe({
error: spy
});

expect(spy).toMatchMockCallsInlineSnapshot(`
[
[
[Error: error],
],
]
`);
});

0 comments on commit c111273

Please sign in to comment.