Skip to content

Commit 2e589d3

Browse files
chore(deps): update to electron 10.1.5 (#3599)
1 parent b26da52 commit 2e589d3

File tree

12 files changed

+619
-210
lines changed

12 files changed

+619
-210
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@
144144
"serve-static": "^1.13.2",
145145
"simple-git": "^2.21.0",
146146
"source-map-loader": "^1.1.2",
147-
"spectron": "^10.0.1",
147+
"spectron": "^12.0.0",
148148
"terser-webpack-plugin": "^4.2.3",
149149
"ts-jest": "^26.4.3",
150150
"ts-loader": "^8.0.8",
@@ -163,7 +163,7 @@
163163
"axe-core": "4.0.2",
164164
"axios": "^0.21.0",
165165
"classnames": "^2.2.6",
166-
"electron": "8.4.1",
166+
"electron": "10.1.5",
167167
"electron-log": "^4.3.0",
168168
"electron-updater": "^4.3.5",
169169
"idb-keyval": "^3.2.0",

pipeline/scripts/download-electron-mirror.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (
2727
process.exit(1);
2828
}
2929

30-
const assetNumber = '5424028';
30+
const assetNumber = '6179765';
3131

3232
const downloadMirrors = async () => {
3333
await downloadElectronArtifact('electron', 'node_modules/electron/dist');

src/electron/main/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ const electronAutoUpdateCheck = new AutoUpdaterClient(autoUpdater);
3737
const createWindow = () => {
3838
mainWindow = new BrowserWindow({
3939
show: false,
40-
webPreferences: { nodeIntegration: true },
40+
// enableRemoteModule required for spectron (https://github.com/electron-userland/spectron/issues/693#issuecomment-696957538)
41+
webPreferences: { nodeIntegration: true, enableRemoteModule: true },
4142
titleBarStyle: 'hidden',
4243
width: mainWindowConfig.defaultWidth,
4344
height: mainWindowConfig.defaultHeight,

src/tests/electron/common/create-application.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ export async function createAppController(
5757
operationLabel: 'app.start',
5858
warnOnRetry: true,
5959
maxRetries: DEFAULT_CHROMEDRIVER_START_RETRIES,
60-
retryOnlyIfMatches: err => err?.message?.includes('ChromeDriver did not start within'),
60+
retryOnlyIfMatches: err =>
61+
err?.message?.includes('ChromeDriver did not start within') ||
62+
err?.message?.includes('Failed to create session.\nread ECONNRESET'),
6163
},
6264
);
6365

src/tests/electron/common/scan-for-accessibility-issues.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ async function runAxeScan(
3939
},
4040
};
4141

42-
const executeOutput = await spectronClient.executeAsync(
42+
const axeResults = await spectronClient.executeAsync(
4343
(options, selectorInEvaluate, done) => {
4444
const elementContext =
4545
selectorInEvaluate === null ? document : { include: [selectorInEvaluate] };
@@ -55,11 +55,6 @@ async function runAxeScan(
5555
selector,
5656
);
5757

58-
// This is how webdriverio indicates success
59-
expect(executeOutput).toHaveProperty('status', 0);
60-
61-
const axeResults = executeOutput.value;
62-
6358
return prettyPrintAxeViolations(axeResults);
6459
}
6560

src/tests/electron/common/view-controllers/app-controller.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,18 @@ import { AndroidSetupStepId } from 'electron/platform/android/setup/android-setu
44
import { Application } from 'spectron';
55
import { AndroidSetupViewController } from 'tests/electron/common/view-controllers/android-setup-view-controller';
66
import { DeviceConnectionDialogController } from 'tests/electron/common/view-controllers/device-connection-dialog-controller';
7-
import { SpectronAsyncClient } from 'tests/electron/common/view-controllers/spectron-async-client';
7+
import {
8+
getSpectronAsyncClient,
9+
SpectronAsyncClient,
10+
} from 'tests/electron/common/view-controllers/spectron-async-client';
811
import { DEFAULT_WAIT_FOR_ELEMENT_TO_BE_VISIBLE_TIMEOUT_MS } from 'tests/electron/setup/timeouts';
912
import { AutomatedChecksViewController } from './automated-checks-view-controller';
1013

1114
export class AppController {
1215
public client: SpectronAsyncClient;
1316

1417
constructor(public app: Application) {
15-
this.client = app.client as any;
18+
this.client = getSpectronAsyncClient(app.client, app.browserWindow);
1619
}
1720

1821
public async stop(): Promise<void> {
@@ -28,8 +31,10 @@ export class AppController {
2831
const title = await this.app.webContents.getTitle();
2932
return title === expectedTitle;
3033
},
31-
timeout,
32-
`was expecting window title to transition to ${expectedTitle} within ${timeout}ms`,
34+
{
35+
timeout,
36+
timeoutMsg: `was expecting window title to transition to ${expectedTitle} within ${timeout}ms`,
37+
},
3338
);
3439
}
3540

@@ -77,13 +82,15 @@ export class AppController {
7782

7883
await this.client.waitUntil(
7984
async () => {
80-
const classes = await this.client.getAttribute<string>('body', 'class');
85+
const classes = await this.client.getAttribute('body', 'class');
8186
return expectedHighContrastMode === classes.includes(highContrastThemeClass);
8287
},
83-
DEFAULT_WAIT_FOR_ELEMENT_TO_BE_VISIBLE_TIMEOUT_MS,
84-
`was expecting body element ${
85-
expectedHighContrastMode ? 'with' : 'without'
86-
} class high-contrast-theme`,
88+
{
89+
timeout: DEFAULT_WAIT_FOR_ELEMENT_TO_BE_VISIBLE_TIMEOUT_MS,
90+
timeoutMsg: `was expecting body element ${
91+
expectedHighContrastMode ? 'with' : 'without'
92+
} class high-contrast-theme`,
93+
},
8794
);
8895
}
8996

@@ -108,14 +115,14 @@ export class AppController {
108115
): Promise<void> {
109116
await this.client.waitUntil(
110117
async () => {
111-
const executeOutput = await this.client.executeAsync((prop, done) => {
118+
return await this.client.executeAsync((prop, done) => {
112119
done((window as any)[prop] != null);
113120
}, propertyName);
114-
115-
return executeOutput.status === 0 && executeOutput.value === true;
116121
},
117-
DEFAULT_WAIT_FOR_ELEMENT_TO_BE_VISIBLE_TIMEOUT_MS,
118-
`was expecting window.${propertyName} to be defined`,
122+
{
123+
timeout: DEFAULT_WAIT_FOR_ELEMENT_TO_BE_VISIBLE_TIMEOUT_MS,
124+
timeoutMsg: `was expecting window.${propertyName} to be defined`,
125+
},
119126
);
120127
}
121128
}

src/tests/electron/common/view-controllers/automated-checks-view-controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export class AutomatedChecksViewController extends ViewController {
4848

4949
public async setToggleState(toggleSelector: string, newState: boolean): Promise<void> {
5050
await this.waitForSelector(toggleSelector);
51-
const oldState = await this.client.getAttribute<string>(toggleSelector, 'aria-checked');
51+
const oldState = await this.client.getAttribute(toggleSelector, 'aria-checked');
5252

5353
const oldStateBool = oldState.toLowerCase() === 'true';
5454
if (oldStateBool !== newState) {
Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,67 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
import { SpectronWindow } from 'spectron';
4+
import { SpectronClient, SpectronWindow } from 'spectron';
55
import * as WebDriverIO from 'webdriverio';
66

7-
// spectron 10.0.1 includes @types/webdriverio, whose absence
8-
// we worked around when initially consuming spectron.
9-
// @types/webdriver lacks promises, so this file adds
10-
// promise-based signatures that our e2e code can rely on.
11-
// @types/webdriver has been superceded by improved types
12-
// in webdriverio 5 directly, but Spectron has not consumed them
7+
// This file worked around incorrect or missing spectron/webdriverio
8+
// typings in the past. webdriverio types are improved in spectron 12.0.0,
9+
// so parts of this file can be removed by updating individual end-to-end
10+
// tests/controllers to consume SpectronClient directly. SpectronAsyncWindow
11+
// works around github issue spectron@343
12+
13+
export function getSpectronAsyncClient(client: SpectronClient, browserWindow: SpectronWindow) {
14+
const typedAsyncClient: SpectronAsyncClient = {
15+
browserWindow: (browserWindow as unknown) as SpectronAsyncWindow,
16+
$: (selector: string) => client.$(selector),
17+
$$: (selector: string) => client.$$(selector),
18+
click: async (selector: string) => {
19+
const element = await client.$(selector);
20+
return await element.click();
21+
},
22+
execute: (script: string | ((...args: any[]) => void), ...args: any[]) =>
23+
client.execute(script, ...args),
24+
executeAsync: (script: string | ((...args: any[]) => void), ...args: any[]) =>
25+
client.executeAsync(script, ...args),
26+
getAttribute: async (selector: string, attributeName: string) => {
27+
const element = await client.$(selector);
28+
return await element.getAttribute(attributeName);
29+
},
30+
getText: async (selector: string) => {
31+
const element = await client.$(selector);
32+
return await element.getText();
33+
},
34+
isEnabled: async (selector: string) => {
35+
const element = await client.$(selector);
36+
return await element.isEnabled();
37+
},
38+
keys: (keys: string) => client.keys(keys),
39+
pause: (milliseconds: number) => client.pause(milliseconds),
40+
waitForEnabled: async (selector: string, milliseconds?: number, reverse?: boolean) => {
41+
const element = await client.$(selector);
42+
return await element.waitForEnabled({
43+
timeout: milliseconds,
44+
reverse,
45+
});
46+
},
47+
waitForExist: async (
48+
selector: string,
49+
milliseconds?: number,
50+
reverse?: boolean,
51+
timeoutMsg?: string,
52+
) => {
53+
const element = await client.$(selector);
54+
return await element.waitForExist({
55+
timeout: milliseconds,
56+
reverse,
57+
timeoutMsg,
58+
});
59+
},
60+
waitUntil: (condition: () => Promise<Boolean>, options?: WebDriverIO.WaitUntilOptions) =>
61+
client.waitUntil(condition, options),
62+
};
63+
return typedAsyncClient;
64+
}
1365

1466
export interface SpectronAsyncWindow {
1567
restore(): Promise<void>;
@@ -20,26 +72,25 @@ export interface SpectronAsyncWindow {
2072
export interface SpectronAsyncClient {
2173
// https://github.com/electron-userland/spectron/blob/cd733c4bc6b28eb5a1041ed79eef5563e75432ae/lib/api.js#L311
2274
browserWindow: SpectronAsyncWindow;
23-
24-
$(selector: string): Promise<WebDriverIO.RawResult<any>>;
25-
$$(selector: string): Promise<WebDriverIO.RawResult<any>[]>;
26-
click(selector?: string): Promise<void>;
75+
$(selector: string): Promise<WebDriverIO.Element>;
76+
$$(selector: string): Promise<WebDriverIO.Element[]>;
77+
click(selector: string): Promise<void>;
2778
executeAsync(script: string | ((...args: any[]) => void), ...args: any[]): Promise<any>;
2879
execute(script: string | ((...args: any[]) => void), ...args: any[]): Promise<any>;
29-
getAttribute<P>(selector: string, attributeName: string): Promise<P>;
80+
getAttribute(selector: string, attributeName: string): Promise<string>;
3081
getText(selector?: string): Promise<string>;
3182
isEnabled(selector?: string): Promise<boolean>;
3283
keys(keys: string): Promise<void>;
3384
pause(milliseconds: number): Promise<void>;
3485
waitForEnabled(selector: string, milliseconds?: number, reverse?: boolean): Promise<boolean>;
35-
waitForExist(selector: string, milliseconds?: number, reverse?: boolean): Promise<boolean>;
36-
waitUntil(
37-
condition: () =>
38-
| boolean
39-
| Promise<boolean>
40-
| (WebDriverIO.Client<WebDriverIO.RawResult<any>> & WebDriverIO.RawResult<any>),
41-
timeout?: number,
86+
waitForExist(
87+
selector: string,
88+
milliseconds?: number,
89+
reverse?: boolean,
4290
timeoutMsg?: string,
43-
interval?: number,
91+
): Promise<boolean>;
92+
waitUntil(
93+
condition: () => Promise<Boolean>,
94+
options?: WebDriverIO.WaitUntilOptions,
4495
): Promise<boolean>;
4596
}

src/tests/electron/common/view-controllers/view-controller.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,26 @@ export abstract class ViewController {
2929
async () => {
3030
return (await this.client.$$(selector)).length === expectedNumber;
3131
},
32-
timeout,
33-
`expected to find ${expectedNumber} matches for selector ${selector} within ${timeout}ms`,
32+
{
33+
timeout,
34+
timeoutMsg: `expected to find ${expectedNumber} matches for selector ${selector} within ${timeout}ms`,
35+
},
3436
);
3537
});
3638
}
3739

40+
// Webdriver waits the full implicit waitForTimeout before returning not-found.
41+
// This means we need to wrap the waitForExist call with a longer timeout when
42+
// reverse is true. See webdriverio@2082 and ai-web@3599.
3843
public async waitForSelectorToDisappear(
3944
selector: string,
40-
timeout: number = DEFAULT_WAIT_FOR_ELEMENT_TO_BE_VISIBLE_TIMEOUT_MS,
45+
timeout: number = DEFAULT_WAIT_FOR_ELEMENT_TO_BE_VISIBLE_TIMEOUT_MS * 2,
4146
): Promise<void> {
4247
await this.screenshotOnError(async () =>
43-
this.client.waitUntil(
44-
async () => {
45-
const selected = await this.client.$(selector);
46-
return selected.value === null;
47-
},
48+
this.client.waitForExist(
49+
selector,
4850
timeout,
51+
true,
4952
`was expecting element by selector ${selector} to disappear`,
5053
),
5154
);

src/tests/electron/tests/automated-checks-view.test.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import { AutomatedChecksViewController } from 'tests/electron/common/view-contro
1515
import { commonAdbConfigs, setupMockAdb } from 'tests/miscellaneous/mock-adb/setup-mock-adb';
1616
import { testResourceServerConfig } from '../setup/test-resource-server-config';
1717
import { androidTestConfigs } from 'electron/platform/android/test-configs/android-test-configs';
18-
import { RawResult } from 'webdriverio';
1918

2019
describe('AutomatedChecksView', () => {
2120
let app: AppController;
@@ -151,7 +150,7 @@ describe('AutomatedChecksView', () => {
151150
'data:image/png;base64,' + axeRuleResultExample.axeContext.screenshot;
152151

153152
await automatedChecksView.waitForSelector(ScreenshotViewSelectors.screenshotImage);
154-
const actualScreenshotImage = await automatedChecksView.client.getAttribute<string>(
153+
const actualScreenshotImage = await automatedChecksView.client.getAttribute(
155154
ScreenshotViewSelectors.screenshotImage,
156155
'src',
157156
);
@@ -161,11 +160,9 @@ describe('AutomatedChecksView', () => {
161160

162161
it('ScreenshotView renders expected number/size of highlight boxes in expected positions', async () => {
163162
await automatedChecksView.waitForSelector(ScreenshotViewSelectors.highlightBox);
164-
const styles = await automatedChecksView.client.getAttribute<string[]>(
165-
ScreenshotViewSelectors.highlightBox,
166-
'style',
167-
);
168163

164+
const boxes = await automatedChecksView.client.$$(ScreenshotViewSelectors.highlightBox);
165+
const styles = await Promise.all(boxes.map(async b => await b.getAttribute('style')));
169166
const actualHighlightBoxStyles = styles.map(extractPositionStyles);
170167
verifyHighlightBoxStyles(actualHighlightBoxStyles, [
171168
{ width: 10.7407, height: 6.04167, top: 3.28125, left: 89.2593 },

0 commit comments

Comments
 (0)