Skip to content

Commit 7682eea

Browse files
authored
chore: make ci more robust, fix stack overflow and import problem (#9948)
* chore: add additional logging to CI to catch circular deps and exit mocha on failure * chore: fix blockly import * chore: format * chore: increase webdriver timeout to allow longer tests * fix: stack overflow if a sound is missing * chore: dont fail for any console errors * chore: needs more timeout * chore: run mocha in a subprocess * chore: fix chromedriver cache issues * chore: remove bad error condition
1 parent 75de6cb commit 7682eea

11 files changed

Lines changed: 614 additions & 228 deletions

File tree

.github/workflows/build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ jobs:
4343
- name: Npm Clean Install
4444
run: npm ci
4545

46+
- name: Setup Chrome
47+
if: runner.os == 'Linux'
48+
uses: browser-actions/setup-chrome@v1
49+
4650
- name: Linux Test Setup
4751
if: runner.os == 'Linux'
4852
run: source ./tests/scripts/setup_linux_env.sh

packages/blockly/core/workspace_audio.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ export class WorkspaceAudio {
106106
source.start();
107107
} else if (this.parentWorkspace) {
108108
// Maybe a workspace on a lower level knows about this sound.
109-
this.parentWorkspace.getAudioManager().play(name, opt_volume);
109+
const parentAudio = this.parentWorkspace.getAudioManager();
110+
if (parentAudio !== this) {
111+
parentAudio.play(name, opt_volume);
112+
}
110113
}
111114
}
112115

packages/blockly/core/zoom_controls.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
// Unused import preserved for side-effects. Remove if unneeded.
1515
import './events/events_click.js';
1616

17-
import {IFocusableNode} from './blockly.js';
1817
import * as browserEvents from './browser_events.js';
1918
import {ComponentManager} from './component_manager.js';
2019
import * as Css from './css.js';
2120
import {EventType} from './events/type.js';
2221
import * as eventUtils from './events/utils.js';
22+
import {IFocusableNode} from './interfaces/i_focusable_node.js';
2323
import type {IPositionable} from './interfaces/i_positionable.js';
2424
import type {UiMetrics} from './metrics_manager.js';
2525
import {Msg} from './msg.js';

packages/blockly/eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ export default [
195195
'tests/mocha/.mocharc.js',
196196
'tests/migration/validate-renamings.mjs',
197197
'tests/scripts/magic_symlink.js',
198+
'tests/scripts/webdriver_helpers.js',
198199
],
199200
languageOptions: {
200201
globals: {

packages/blockly/scripts/gulpfiles/test_tasks.mjs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@ import * as gulp from 'gulp';
1414
import gzip from 'gulp-gzip';
1515
import * as fs from 'fs';
1616
import * as path from 'path';
17-
import {execSync} from 'child_process';
17+
import {spawnSync} from 'child_process';
1818
import {rimraf} from 'rimraf';
1919

2020
import {RELEASE_DIR, TEST_TSC_OUTPUT_DIR} from './config.mjs';
2121

2222
import {runMochaTestsInBrowser} from '../../tests/mocha/webdriver.js';
23-
import {runGeneratorsInBrowser} from '../../tests/generators/webdriver.js';
24-
import {runCompileCheckInBrowser} from '../../tests/compile/webdriver.js';
2523

2624
const OUTPUT_DIR = 'build/generators';
2725
const GOLDEN_DIR = 'tests/generators/golden';
@@ -121,8 +119,20 @@ function reportTestResult() {
121119
* @return {Promise} Asynchronous result.
122120
*/
123121
async function runTestCommand(id, command) {
124-
return runTestTask(id, async() => {
125-
return execSync(command, {stdio: 'inherit'});
122+
return runTestTask(id, async () => {
123+
const result = spawnSync(command, {
124+
shell: true,
125+
stdio: 'inherit',
126+
env: process.env,
127+
});
128+
if (result.error) {
129+
throw result.error;
130+
}
131+
if (result.status !== 0) {
132+
throw new Error(
133+
`Command failed with exit code ${result.status}: ${command}`,
134+
);
135+
}
126136
});
127137
}
128138

@@ -257,24 +267,25 @@ async function metadata() {
257267
* Run Mocha tests inside a browser.
258268
* @return {Promise} Asynchronous result.
259269
*/
260-
async function mocha(exitOnCompletion = true) {
261-
return runTestTask('mocha', async () => {
262-
const result = await runMochaTestsInBrowser(exitOnCompletion).catch(e => {
263-
throw e;
264-
});
265-
if (result) {
266-
throw new Error('Mocha tests failed');
267-
}
268-
console.log('Mocha tests passed');
269-
});
270+
function mocha() {
271+
// Run in a subprocess so webdriverio is not loaded inside gulp's asyncDone
272+
// domain (which has been observed to exit the process on CI after ~2s).
273+
return runTestCommand('mocha', 'node tests/mocha/webdriver.js');
270274
}
271275

272276
/**
273277
* Run Mocha tests inside a browser and keep the browser open upon completion.
274278
* @return {Promise} Asynchronous result.
275279
*/
276-
export async function interactiveMocha() {
277-
return mocha(false);
280+
export function interactiveMocha() {
281+
return runTestTask('interactiveMocha', () => {
282+
return runMochaTestsInBrowser(false).then((result) => {
283+
if (result) {
284+
throw new Error('Mocha tests failed');
285+
}
286+
console.log('Mocha tests passed');
287+
});
288+
});
278289
}
279290

280291
/**
@@ -335,7 +346,16 @@ export async function generators() {
335346
rimraf.sync(OUTPUT_DIR);
336347
fs.mkdirSync(OUTPUT_DIR);
337348

338-
await runGeneratorsInBrowser(OUTPUT_DIR);
349+
const result = spawnSync('node', ['tests/generators/webdriver.js', OUTPUT_DIR], {
350+
stdio: 'inherit',
351+
env: process.env,
352+
});
353+
if (result.error) {
354+
throw result.error;
355+
}
356+
if (result.status !== 0) {
357+
throw new Error('Generator browser tests failed.');
358+
}
339359

340360
const generatorSuffixes = ['js', 'py', 'dart', 'lua', 'php'];
341361
let failed = 0;
@@ -375,7 +395,10 @@ function advancedCompile() {
375395
* @return {Promise} Asynchronous result.
376396
*/
377397
function advancedCompileInBrowser() {
378-
return runTestTask('advanced_compile_in_browser', runCompileCheckInBrowser);
398+
return runTestCommand(
399+
'advanced_compile_in_browser',
400+
'node tests/compile/webdriver.js',
401+
);
379402
}
380403

381404
/**

packages/blockly/tests/compile/webdriver.js

Lines changed: 22 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,78 +9,49 @@
99
* Chrome, via webdriver.
1010
*/
1111
const webdriverio = require('webdriverio');
12-
12+
const {
13+
getWebdriverOptions,
14+
runBrowserTestMain,
15+
} = require('../scripts/webdriver_helpers.js');
1316

1417
/**
15-
* Run the generator for a given language and save the results to a file.
18+
* Run the health check in the browser.
1619
* @param {Thenable} browser A Thenable managing the processing of the browser
1720
* tests.
1821
*/
1922
async function runHealthCheckInBrowser(browser) {
2023
const result = await browser.execute(() => {
21-
return healthCheck();
22-
})
23-
if (!result) throw Error('Health check failed in advanced compilation test.');
24+
return healthCheck();
25+
});
26+
if (!result) {
27+
throw Error('Health check failed in advanced compilation test.');
28+
}
2429
console.log('Health check completed successfully.');
2530
}
2631

2732
/**
28-
* Runs the generator tests in Chrome. It uses webdriverio to
29-
* launch Chrome and load index.html. Outputs a summary of the test results
30-
* to the console and outputs files for later validation.
31-
* @return the Thenable managing the processing of the browser tests.
33+
* Runs the compile health check in Chrome.
34+
* @return {number} 0 on success.
3235
*/
3336
async function runCompileCheckInBrowser() {
34-
const options = {
35-
capabilities: {
36-
browserName: 'chrome',
37-
},
38-
logLevel: 'warn',
39-
};
40-
// Run in headless mode on Github Actions.
41-
if (process.env.CI) {
42-
options.capabilities['goog:chromeOptions'] = {
43-
args: [
44-
'--headless',
45-
'--no-sandbox',
46-
'--disable-dev-shm-usage',
47-
'--allow-file-access-from-files',
48-
]
49-
};
50-
} else {
51-
// --disable-gpu is needed to prevent Chrome from hanging on Linux with
52-
// NVIDIA drivers older than v295.20. See
53-
// https://github.com/google/blockly/issues/5345 for details.
54-
options.capabilities['goog:chromeOptions'] = {
55-
args: ['--allow-file-access-from-files', '--disable-gpu']
56-
};
57-
}
37+
const options = getWebdriverOptions();
5838

5939
const url = 'file://' + __dirname + '/index.html';
6040

6141
console.log('Starting webdriverio...');
6242
const browser = await webdriverio.remote(options);
63-
console.log('Loading url: ' + url);
64-
await browser.url(url);
65-
66-
await runHealthCheckInBrowser(browser);
67-
68-
await browser.deleteSession();
43+
try {
44+
console.log('Loading url: ' + url);
45+
await browser.url(url);
46+
await runHealthCheckInBrowser(browser);
47+
} finally {
48+
await browser.deleteSession();
49+
}
50+
return 0;
6951
}
7052

7153
if (require.main === module) {
72-
runCompileCheckInBrowser().catch(e => {
73-
console.error(e);
74-
process.exit(1);
75-
}).then(function(result) {
76-
if (result) {
77-
console.log('Compile test failed');
78-
process.exit(1);
79-
} else {
80-
console.log('Compile test passed');
81-
process.exit(0);
82-
}
83-
});
54+
runBrowserTestMain(() => runCompileCheckInBrowser());
8455
}
8556

8657
module.exports = {runCompileCheckInBrowser};

0 commit comments

Comments
 (0)