Skip to content

test: multi-handler ordering regression in ExternalActionPlugin#838

Draft
shahabdsh wants to merge 1 commit intoplayer-ui:mainfrom
shahabdsh:test/external-action-multi-handler-ordering
Draft

test: multi-handler ordering regression in ExternalActionPlugin#838
shahabdsh wants to merge 1 commit intoplayer-ui:mainfrom
shahabdsh:test/external-action-multi-handler-ordering

Conversation

@shahabdsh
Copy link
Copy Markdown
Contributor

Summary

Adds tests demonstrating a behavioral regression introduced in #832 (refactor of ExternalActionPlugin from transition + setTimeout to afterTransition).

The issue

When multiple ExternalActionPlugin instances are registered on the same Player (common in plugin architectures where a host and embedded component each register their own handler):

  • Before Refactor external action plugin #832: If the first handler resolved synchronously, the second handler was never invoked — the player had already transitioned away from the external state by the time the second handler's setTimeout callback ran.
  • After Refactor external action plugin #832: Both handlers are always invoked regardless, because afterTransition fires both synchronously in the same tick, and both capture currentState before either has transitioned.

This means handlers that have side effects (logging, analytics, network calls, state mutations) now execute even when another handler has already resolved the external state — which can cause unexpected behavior in plugin architectures.

Test cases

Test Expected Actual (main)
First handler sync, second should not be called PASS FAIL — second handler is called
First handler async fast, second async slow PASS PASS
First handler returns undefined, second handles PASS PASS

Suggested fix

The afterTransition approach should check whether the external state has already been resolved before invoking the handler, or use a coordination mechanism (e.g., a flag on the flow instance) to prevent multiple handlers from racing.

🤖 Generated with Claude Code

When multiple ExternalActionPlugin instances are registered (e.g. in a
plugin architecture where a host and embedded component each register
their own handler), the interaction between handlers matters.

Previously (transition hook + setTimeout), if the first handler resolved
synchronously, the second handler was never invoked because the player
had already transitioned away from the external state. After the refactor
to afterTransition, both handlers are always invoked regardless, which
can cause unexpected side effects in the second handler.

These tests document the expected behavior: a synchronously-resolving
first handler should prevent the second handler from executing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant