From 9c5ae84310e3ade7005df1dc2ebf1619f8e07bf3 Mon Sep 17 00:00:00 2001 From: samuelmaddock Date: Wed, 21 Apr 2021 18:42:10 -0400 Subject: [PATCH] test: add waitForTrue to avoid flaky visibilityState test --- spec-main/api-web-frame-main-spec.ts | 10 +++--- spec-main/spec-helpers.ts | 46 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/spec-main/api-web-frame-main-spec.ts b/spec-main/api-web-frame-main-spec.ts index 8879f5e44652d..3edbadf0ace0d 100644 --- a/spec-main/api-web-frame-main-spec.ts +++ b/spec-main/api-web-frame-main-spec.ts @@ -6,6 +6,7 @@ import { BrowserWindow, WebFrameMain, webFrameMain, ipcMain } from 'electron/mai import { closeAllWindows } from './window-helpers'; import { emittedOnce, emittedNTimes } from './events-helpers'; import { AddressInfo } from 'net'; +import { waitForTrue } from './spec-helpers'; describe('webFrameMain module', () => { const fixtures = path.resolve(__dirname, '..', 'spec-main', 'fixtures'); @@ -143,12 +144,9 @@ describe('webFrameMain module', () => { expect(webFrame.visibilityState).to.equal('visible'); w.hide(); - - // Wait for visibility to propagate. If this ends up being flaky, we can - // look into binding WebContentsObserver::OnVisibilityChanged. - await new Promise(resolve => setTimeout(resolve, 10)); - - expect(webFrame.visibilityState).to.equal('hidden'); + await expect( + waitForTrue(() => webFrame.visibilityState === 'hidden') + ).to.eventually.be.fulfilled(); }); }); diff --git a/spec-main/spec-helpers.ts b/spec-main/spec-helpers.ts index 04dc0abcc312b..acdbd1647b07e 100644 --- a/spec-main/spec-helpers.ts +++ b/spec-main/spec-helpers.ts @@ -86,3 +86,49 @@ export async function startRemoteControlApp () { defer(() => { appProcess.kill('SIGINT'); }); return new RemoteControlApp(appProcess, port); } + +export function waitForTrue ( + callback: () => boolean, + opts: { rate?: number, timeout?: number } = {} +) { + const { rate = 10, timeout = 10000 } = opts; + return new Promise((resolve, reject) => { + let intervalId: NodeJS.Timeout | undefined; // eslint-disable-line prefer-const + let timeoutId: NodeJS.Timeout | undefined; + + const cleanup = () => { + if (intervalId) clearInterval(intervalId); + if (timeoutId) clearTimeout(timeoutId); + }; + + const check = () => { + let result; + + try { + result = callback(); + } catch (e) { + cleanup(); + reject(e); + return; + } + + if (result === true) { + cleanup(); + resolve(); + } + return result; + }; + + if (check()) { + return; + } + + intervalId = setInterval(check, rate); + + timeoutId = setTimeout(() => { + timeoutId = undefined; + cleanup(); + reject(new Error(`waitForTrue timed out after ${timeout}ms`)); + }, timeout); + }); +}