@@ -44,6 +44,8 @@ let driver: webdriverio.Browser | null = null;
4444 */
4545export const PAUSE_TIME = 0 ;
4646
47+ var synchronizeCoreBlocklyRendering : boolean = true ;
48+
4749/**
4850 * Start up WebdriverIO and load the test page. This should only be
4951 * done once, to avoid constantly popping browser windows open and
@@ -119,6 +121,9 @@ export async function testSetup(
119121 playgroundUrl : string ,
120122 wdioWaitTimeoutMs : number ,
121123) : Promise < webdriverio . Browser > {
124+ // Reset back to default state between tests.
125+ synchronizeCoreBlocklyRendering = true ;
126+
122127 if ( ! driver ) {
123128 driver = await driverSetup ( wdioWaitTimeoutMs ) ;
124129 }
@@ -202,26 +207,63 @@ export async function getSelectedBlockId(browser: WebdriverIO.Browser) {
202207 } ) ;
203208}
204209
205- export async function idle ( browser : WebdriverIO . Browser ) {
206- // First, attempt to synchronize on rendering to ensure that Blockly is fully
207- // rendered before pausing for browser execution. This works around potential
208- // bugs when running in headless mode that can cause requestAnimationFrame to
209- // not call back (and cause state inconsistencies in block positions and sizes
210- // per #770).
211- await browser . execute ( ( ) => {
212- const workspace = Blockly . getMainWorkspace ( ) as Blockly . WorkspaceSvg ;
213- // Queue re-rendering all blocks.
214- workspace . render ( ) ;
215- // Flush the rendering queue (this is a slight hack to leverage
216- // BlockSvg.render() directly blocking on rendering finishing).
217- const blocks = workspace . getTopBlocks ( ) ;
218- if ( blocks . length > 0 ) {
219- blocks [ 0 ] . render ( ) ;
220- }
221- } ) ;
210+ /**
211+ * Idles the browser for PAUSE_TIME, also possibly synchronizing rendering in
212+ * core Blockly.
213+ *
214+ * This generally should always be preferred over calling browser.pause()
215+ * directly.
216+ *
217+ * See setSynchronizeCoreBlocklyRendering() for additional details on
218+ * configuring how this function behaves.
219+ *
220+ * @param browser The active WebdriverIO Browser object.
221+ */
222+ export async function idle ( browser : WebdriverIO . Browser , synchronizeRendering : boolean = true ) {
223+ if ( synchronizeCoreBlocklyRendering ) {
224+ // First, attempt to synchronize on rendering to ensure that Blockly is
225+ // fully rendered before pausing for browser execution. This works around
226+ // potential bugs when running in headless mode that can cause
227+ // requestAnimationFrame to not call back (and cause state inconsistencies
228+ // in block positions and sizes per #770).
229+ await browser . execute ( ( ) => {
230+ const workspace = Blockly . getMainWorkspace ( ) as Blockly . WorkspaceSvg ;
231+ // Queue re-rendering all blocks.
232+ workspace . render ( ) ;
233+ // Flush the rendering queue (this is a slight hack to leverage
234+ // BlockSvg.render() directly blocking on rendering finishing).
235+ const blocks = workspace . getTopBlocks ( ) ;
236+ if ( blocks . length > 0 ) {
237+ blocks [ 0 ] . render ( ) ;
238+ }
239+ } ) ;
240+ }
222241 await browser . pause ( PAUSE_TIME ) ;
223242}
224243
244+ /**
245+ * Configures whether to synchronize core Blockly's rendering system when trying
246+ * to idle tests to wait for operations to complete.
247+ *
248+ * This is enabled by default and changes the behavior of idle() which is used
249+ * both directly in tests and indirectly via the many test helpers in this file.
250+ *
251+ * Synchronization is useful because it ensures Blockly is fully rendered and
252+ * stable before proceeding with the test (which can sometimes be desynchronized
253+ * if the headless test environment drops a request for animation rendering
254+ * frame which has been observed in CI environments).
255+ *
256+ * Synchronization must be disabled in certain tests, particularly those that
257+ * can trigger alert dialogs since, when open, these will always cause any
258+ * browser.execute() calls to fail the test (and rendering synchronization
259+ * relies on this WebdriverIO mechanism).
260+ *
261+ * @param enableSynchronization
262+ */
263+ export async function setSynchronizeCoreBlocklyRendering ( enableSynchronization : boolean ) {
264+ synchronizeCoreBlocklyRendering = enableSynchronization ;
265+ }
266+
225267/**
226268 * Clicks in the workspace to focus it.
227269 *
0 commit comments