@@ -6,6 +6,7 @@ import { preprocessForSerialization, reifyCrossDomainError } from '../util/seria
66const debug = debugFn ( 'cypress:driver:multi-domain' )
77
88const CROSS_DOMAIN_PREFIX = 'cross:domain:'
9+ let primaryDomainCommunicatorSingleton : PrimaryDomainCommunicator | null = null
910
1011/**
1112 * Primary domain communicator. Responsible for sending/receiving events throughout
@@ -23,6 +24,24 @@ export class PrimaryDomainCommunicator extends EventEmitter {
2324 private crossDomainDriverWindows : { [ key : string ] : Window } = { }
2425 userInvocationStack ?: string
2526
27+ constructor ( ) {
28+ // There should only be one PrimaryDomainCommunicator per Cypress instance (Ex: primary domain, specbridge1, specbridge2, ...).
29+ // Spec Bridges will create a PrimaryDomainCommunicator instance, but will never initialize the window.top message listener
30+ // this means that methods that communicate through postMessage can send, but spec bridge PrimaryDomainCommunicator
31+ // will never receive any events.
32+ if ( ! primaryDomainCommunicatorSingleton ) {
33+ // @ts -ignore
34+ super ( )
35+ primaryDomainCommunicatorSingleton = this
36+ }
37+
38+ // for the primary domain, the PrimaryDomainCommunicator needs to be a singleton.
39+ // multiple PrimaryDomainCommunicator instances recreated on test refreshes/reloads cause dangling instances
40+ // of the window.top message listener, stacking message events multiple times.
41+ // The window.top instance does not change between test reloads, and we only need to bind it once
42+ return primaryDomainCommunicatorSingleton
43+ }
44+
2645 /**
2746 * Initializes the event handler to receive messages from the spec bridge.
2847 * @param {Window } win - a reference to the window object in the primary domain.
0 commit comments