1414
1515import { Injectable } from '@angular/core' ;
1616import { CoreWait } from '@singletons/wait' ;
17- import { makeSingleton , NgZone } from '@singletons' ;
17+ import { makeSingleton , NgZone , Router } from '@singletons' ;
1818import { BehatTestsWindow , TestingBehatRuntime } from './behat-runtime' ;
19+ import {
20+ GuardsCheckEnd ,
21+ GuardsCheckStart ,
22+ NavigationCancel ,
23+ NavigationEnd ,
24+ NavigationError ,
25+ NavigationStart ,
26+ } from '@angular/router' ;
27+ import { Subscription , filter } from 'rxjs' ;
28+ import { CoreNavigator } from '@services/navigator' ;
1929
2030/**
2131 * Behat block JS manager.
@@ -24,10 +34,12 @@ import { BehatTestsWindow, TestingBehatRuntime } from './behat-runtime';
2434export class TestingBehatBlockingService {
2535
2636 protected waitingBlocked = false ;
37+ protected waitingGuardEnd = false ;
2738 protected recentMutation = false ;
2839 protected lastMutation = 0 ;
2940 protected initialized = false ;
3041 protected keyIndex = 0 ;
42+ protected navSubscription ?: Subscription ;
3143
3244 /**
3345 * Listen to mutations and override XML Requests.
@@ -48,6 +60,47 @@ export class TestingBehatBlockingService {
4860 win . M . util = win . M . util ?? { } ;
4961 win . M . util . pending_js = win . M . util . pending_js ?? [ ] ;
5062
63+ this . navSubscription = Router . events
64+ . pipe ( filter ( event =>
65+ event instanceof NavigationStart ||
66+ event instanceof NavigationEnd ||
67+ event instanceof NavigationError ||
68+ event instanceof NavigationCancel ||
69+ event instanceof GuardsCheckStart ||
70+ event instanceof GuardsCheckEnd ) )
71+ . subscribe ( async ( event ) => {
72+ if ( ! ( 'id' in event ) ) {
73+ return ;
74+ }
75+
76+ const blockName = `navigation-${ event . id } ` ;
77+ if ( event instanceof NavigationStart ) {
78+ this . block ( blockName ) ;
79+ } else if ( event instanceof GuardsCheckStart ) {
80+ // This event is triggered before the guards are checked, so we need to wait for the end.
81+ this . waitingGuardEnd = CoreNavigator . currentRouteCanBlockLeave ( ) ;
82+
83+ // No deactivation needed.
84+ if ( ! this . waitingGuardEnd ) {
85+ return ;
86+ }
87+
88+ await CoreWait . wait ( 500 ) ;
89+
90+ if ( this . waitingGuardEnd ) {
91+ // The guard is still running (this case can unexpetedly unblock the tests)
92+ // or a user confirmation is shown. Unblock.
93+ this . waitingGuardEnd = false ;
94+ this . unblock ( blockName ) ;
95+ }
96+ } else if ( event instanceof GuardsCheckEnd ) {
97+ // Guards check ended.
98+ this . waitingGuardEnd = false ;
99+ } else {
100+ this . unblock ( blockName ) ;
101+ }
102+ } ) ;
103+
51104 TestingBehatRuntime . log ( 'Initialized!' ) ;
52105 }
53106
@@ -282,6 +335,13 @@ export class TestingBehatBlockingService {
282335 } ;
283336 }
284337
338+ /**
339+ * Wait for pending list to be empty.
340+ */
341+ async waitForPending ( ) : Promise < void > {
342+ await CoreWait . waitFor ( ( ) => this . pendingList . length === 0 ) ;
343+ }
344+
285345}
286346
287347export const TestingBehatBlocking = makeSingleton ( TestingBehatBlockingService ) ;
0 commit comments