diff --git a/.eslintignore b/.eslintignore
index 26e22adb55d..b8e1c93a818 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -7,7 +7,7 @@
/tests/compile/*
/tests/jsunit/*
/tests/generators/*
-/tests/mocha/run_mocha_tests_in_browser.js
+/tests/mocha/webdriver.js
/tests/screenshot/*
/tests/test_runner.js
/tests/workspace_svg/*
diff --git a/scripts/gulpfiles/appengine_tasks.js b/scripts/gulpfiles/appengine_tasks.js
index ea5b6a53aca..cb9ff8fed31 100644
--- a/scripts/gulpfiles/appengine_tasks.js
+++ b/scripts/gulpfiles/appengine_tasks.js
@@ -8,16 +8,16 @@
* @fileoverview Gulp script to deploy Blockly demos on appengine.
*/
-var gulp = require('gulp');
+const gulp = require('gulp');
-var fs = require('fs');
-var rimraf = require('rimraf');
-var path = require('path');
-var execSync = require('child_process').execSync;
+const fs = require('fs');
+const rimraf = require('rimraf');
+const path = require('path');
+const execSync = require('child_process').execSync;
const buildTasks = require('./build_tasks.js');
const packageTasks = require('./package_tasks.js');
-var packageJson = require('../../package.json');
+const packageJson = require('../../package.json');
const demoTmpDir = '../_deploy';
const demoStaticTmpDir = '../_deploy/static';
@@ -121,10 +121,10 @@ function deployAndClean(done) {
* Constructs a beta demo version name based on the current date.
*/
function getDemosBetaVersion() {
- var date = new Date();
- var mm = date.getMonth() + 1; // Month, 0-11
- var dd = date.getDate(); // Day of the month, 1-31
- var yyyy = date.getFullYear();
+ const date = new Date();
+ const mm = date.getMonth() + 1; // Month, 0-11
+ const dd = date.getDate(); // Day of the month, 1-31
+ const yyyy = date.getFullYear();
return `${yyyy}${mm < 10 ? '0' + mm : mm}${dd}-beta`;
}
@@ -140,7 +140,7 @@ function deployBetaAndClean(done) {
/**
* Prepares demos.
- *
+ *
* Prerequisites (invoked): clean, build
*/
const prepareDemos = gulp.series(
diff --git a/scripts/gulpfiles/build_tasks.js b/scripts/gulpfiles/build_tasks.js
index fa1d962f3ba..4358ad8e518 100644
--- a/scripts/gulpfiles/build_tasks.js
+++ b/scripts/gulpfiles/build_tasks.js
@@ -8,27 +8,27 @@
* @fileoverview Gulp script to build Blockly for Node & NPM.
*/
-var gulp = require('gulp');
+const gulp = require('gulp');
gulp.replace = require('gulp-replace');
gulp.rename = require('gulp-rename');
gulp.sourcemaps = require('gulp-sourcemaps');
-var path = require('path');
-var fs = require('fs');
+const path = require('path');
+const fs = require('fs');
const {exec, execSync} = require('child_process');
-var through2 = require('through2');
+const through2 = require('through2');
const clangFormat = require('clang-format');
const clangFormatter = require('gulp-clang-format');
-var closureCompiler = require('google-closure-compiler').gulp();
-var closureDeps = require('google-closure-deps');
-var argv = require('yargs').argv;
-var rimraf = require('rimraf');
+const closureCompiler = require('google-closure-compiler').gulp();
+const closureDeps = require('google-closure-deps');
+const argv = require('yargs').argv;
+const rimraf = require('rimraf');
-var {BUILD_DIR, DEPS_FILE, RELEASE_DIR, TEST_DEPS_FILE, TSC_OUTPUT_DIR, TYPINGS_BUILD_DIR} = require('./config');
-var {getPackageJson} = require('./helper_tasks');
+const {BUILD_DIR, DEPS_FILE, RELEASE_DIR, TEST_DEPS_FILE, TSC_OUTPUT_DIR, TYPINGS_BUILD_DIR} = require('./config');
+const {getPackageJson} = require('./helper_tasks');
-var {posixPath} = require('../helpers');
+const {posixPath} = require('../helpers');
////////////////////////////////////////////////////////////
// Build //
@@ -173,9 +173,9 @@ function stripApacheLicense() {
}
/**
- * Closure compiler diagnostic groups we want to be treated as errors.
+ * Closure Compiler diagnostic groups we want to be treated as errors.
* These are effected when the --debug or --strict flags are passed.
- * For a full list of closure compiler groups, consult the output of
+ * For a full list of Closure Compiler groups, consult the output of
* google-closure-compiler --help or look in the source here:
* https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/DiagnosticGroups.java#L117
*
@@ -185,7 +185,7 @@ function stripApacheLicense() {
* appearing on any list will default to setting provided by the
* compiler, which may vary depending on compilation level.
*/
-var JSCOMP_ERROR = [
+const JSCOMP_ERROR = [
// 'accessControls', // Deprecated; means same as visibility.
// 'checkPrototypalTypes', // override annotations are stripped by tsc.
'checkRegExp',
@@ -235,25 +235,25 @@ var JSCOMP_ERROR = [
];
/**
- * Closure compiler diagnostic groups we want to be treated as warnings.
+ * Closure Compiler diagnostic groups we want to be treated as warnings.
* These are effected when the --debug or --strict flags are passed.
*
* For most (all?) diagnostic groups this is the default level, so
* it's generally sufficient to remove them from JSCOMP_ERROR.
*/
-var JSCOMP_WARNING = [
+const JSCOMP_WARNING = [
];
/**
- * Closure compiler diagnostic groups we want to be ignored. These
+ * Closure Compiler diagnostic groups we want to be ignored. These
* suppressions are always effected by default.
*
* Make sure that anything added here is commented out of JSCOMP_ERROR
* above, as that takes precedence.)
*/
-var JSCOMP_OFF = [
+const JSCOMP_OFF = [
/* The removal of Closure type system types from our JSDoc
- * annotations means that the closure compiler now generates certain
+ * annotations means that the Closure Compiler now generates certain
* diagnostics because it no longer has enough information to be
* sure that the input code is correct. The following diagnostic
* groups are turned off to suppress such errors.
@@ -315,6 +315,7 @@ function buildJavaScript(done) {
execSync(
`tsc -outDir "${TSC_OUTPUT_DIR}" -declarationDir "${TYPINGS_BUILD_DIR}"`,
{stdio: 'inherit'});
+ execSync(`node scripts/tsick.js "${TSC_OUTPUT_DIR}"`, {stdio: 'inherit'});
done();
}
@@ -452,7 +453,7 @@ function buildLangfiles(done) {
}
/**
- * A helper method to return an closure compiler chunk wrapper that
+ * A helper method to return an Closure Compiler chunk wrapper that
* wraps the compiler output for the given chunk in a Universal Module
* Definition.
*/
@@ -612,7 +613,7 @@ function getChunkOptions() {
const pathSepRegExp = new RegExp(path.sep.replace(/\\/, '\\\\'), "g");
/**
- * Helper method for calling the Closure compiler, establishing
+ * Helper method for calling the Closure Compiler, establishing
* default options (that can be overridden by the caller).
* @param {*} options Caller-supplied options that will override the
* defaultOptions.
@@ -663,7 +664,7 @@ function buildCompiled() {
const packageJson = getPackageJson(); // For version number.
const options = {
// The documentation for @define claims you can't use it on a
- // non-global, but the closure compiler turns everything in to a
+ // non-global, but the Closure Compiler turns everything in to a
// global - you just have to know what the new name is! With
// declareLegacyNamespace this was very straightforward. Without
// it, we have to rely on implmentation details. See
@@ -688,11 +689,19 @@ function buildCompiled() {
/**
* This task builds Blockly core, blocks and generators together and uses
- * closure compiler's ADVANCED_COMPILATION mode.
+ * Closure Compiler's ADVANCED_COMPILATION mode.
*
* Prerequisite: buildDeps.
*/
function buildAdvancedCompilationTest() {
+ // If main_compressed.js exists (from a previous run) delete it so that
+ // a later browser-based test won't check it should the compile fail.
+ try {
+ fs.unlinkSync('./tests/compile/main_compressed.js');
+ } catch (_e) {
+ // Probably it didn't exist.
+ }
+
const srcs = [
TSC_OUTPUT_DIR + '/closure/goog/base_minimal.js',
TSC_OUTPUT_DIR + '/closure/goog/goog.js',
diff --git a/scripts/gulpfiles/config.js b/scripts/gulpfiles/config.js
index 200d6ac45a4..5f3cad99d32 100644
--- a/scripts/gulpfiles/config.js
+++ b/scripts/gulpfiles/config.js
@@ -8,7 +8,7 @@
* @fileoverview Common configuration for Gulp scripts.
*/
-var path = require('path');
+const path = require('path');
// Paths are all relative to the repository root. Do not include
// trailing slash.
diff --git a/scripts/gulpfiles/git_tasks.js b/scripts/gulpfiles/git_tasks.js
index 0f14133500a..eb3a825c025 100644
--- a/scripts/gulpfiles/git_tasks.js
+++ b/scripts/gulpfiles/git_tasks.js
@@ -8,10 +8,10 @@
* @fileoverview Git-related gulp tasks for Blockly.
*/
-var gulp = require('gulp');
-var execSync = require('child_process').execSync;
+const gulp = require('gulp');
+const execSync = require('child_process').execSync;
-var buildTasks = require('./build_tasks');
+const buildTasks = require('./build_tasks');
const packageTasks = require('./package_tasks');
const upstream_url = "https://github.com/google/blockly.git";
@@ -41,18 +41,18 @@ function syncMaster() {
// Helper function: get a name for a rebuild branch. Format: rebuild_mm_dd_yyyy.
function getRebuildBranchName() {
- var date = new Date();
- var mm = date.getMonth() + 1; // Month, 0-11
- var dd = date.getDate(); // Day of the month, 1-31
- var yyyy = date.getFullYear();
+ const date = new Date();
+ const mm = date.getMonth() + 1; // Month, 0-11
+ const dd = date.getDate(); // Day of the month, 1-31
+ const yyyy = date.getFullYear();
return 'rebuild_' + mm + '_' + dd + '_' + yyyy;
};
// Helper function: get a name for a rebuild branch. Format: rebuild_yyyy_mm.
function getRCBranchName() {
- var date = new Date();
- var mm = date.getMonth() + 1; // Month, 0-11
- var yyyy = date.getFullYear();
+ const date = new Date();
+ const mm = date.getMonth() + 1; // Month, 0-11
+ const yyyy = date.getFullYear();
return 'rc_' + yyyy + '_' + mm;
};
@@ -68,7 +68,7 @@ function checkoutBranch(branchName) {
const createRC = gulp.series(
syncDevelop(),
function(done) {
- var branchName = getRCBranchName();
+ const branchName = getRCBranchName();
execSync('git checkout -b ' + branchName, { stdio: 'inherit' });
execSync('git push ' + upstream_url + ' ' + branchName,
{ stdio: 'inherit' });
@@ -78,7 +78,7 @@ const createRC = gulp.series(
// Create the rebuild branch.
function createRebuildBranch(done) {
- var branchName = getRebuildBranchName();
+ const branchName = getRebuildBranchName();
console.log('make-rebuild-branch: creating branch ' + branchName);
execSync('git checkout -b ' + branchName, { stdio: 'inherit' });
done();
@@ -88,7 +88,7 @@ function createRebuildBranch(done) {
function pushRebuildBranch(done) {
console.log('push-rebuild-branch: committing rebuild');
execSync('git commit -am "Rebuild"', { stdio: 'inherit' });
- var branchName = getRebuildBranchName();
+ const branchName = getRebuildBranchName();
execSync('git push origin ' + branchName, { stdio: 'inherit' });
console.log('Branch ' + branchName + ' pushed to GitHub.');
console.log('Next step: create a pull request against develop.');
diff --git a/scripts/gulpfiles/package_tasks.js b/scripts/gulpfiles/package_tasks.js
index 2408641f7c5..d5fba6258de 100644
--- a/scripts/gulpfiles/package_tasks.js
+++ b/scripts/gulpfiles/package_tasks.js
@@ -8,7 +8,7 @@
* @fileoverview Gulp tasks to package Blockly for distribution on NPM.
*/
-var gulp = require('gulp');
+const gulp = require('gulp');
gulp.concat = require('gulp-concat');
gulp.replace = require('gulp-replace');
gulp.rename = require('gulp-rename');
@@ -16,12 +16,12 @@ gulp.insert = require('gulp-insert');
gulp.umd = require('gulp-umd');
gulp.replace = require('gulp-replace');
-var path = require('path');
-var fs = require('fs');
-var rimraf = require('rimraf');
-var build = require('./build_tasks');
-var {getPackageJson} = require('./helper_tasks');
-var {BUILD_DIR, RELEASE_DIR, TYPINGS_BUILD_DIR} = require('./config');
+const path = require('path');
+const fs = require('fs');
+const rimraf = require('rimraf');
+const build = require('./build_tasks');
+const {getPackageJson} = require('./helper_tasks');
+const {BUILD_DIR, RELEASE_DIR, TYPINGS_BUILD_DIR} = require('./config');
// Path to template files for gulp-umd.
const TEMPLATE_DIR = 'scripts/package/templates';
@@ -290,7 +290,7 @@ function packageLocales() {
* @example
*/
function packageUMDBundle() {
- var srcs = [
+ const srcs = [
`${RELEASE_DIR}/blockly_compressed.js`,
`${RELEASE_DIR}/msg/en.js`,
`${RELEASE_DIR}/blocks_compressed.js`,
diff --git a/scripts/gulpfiles/release_tasks.js b/scripts/gulpfiles/release_tasks.js
index 4a387705f9e..58717985c0c 100644
--- a/scripts/gulpfiles/release_tasks.js
+++ b/scripts/gulpfiles/release_tasks.js
@@ -8,22 +8,22 @@
* @fileoverview Gulp scripts for releasing Blockly.
*/
-var execSync = require('child_process').execSync;
-var fs = require('fs');
-var gulp = require('gulp');
-var readlineSync = require('readline-sync');
+const execSync = require('child_process').execSync;
+const fs = require('fs');
+const gulp = require('gulp');
+const readlineSync = require('readline-sync');
-var gitTasks = require('./git_tasks');
-var packageTasks = require('./package_tasks');
-var {getPackageJson} = require('./helper_tasks');
-var {RELEASE_DIR} = require('./config');
+const gitTasks = require('./git_tasks');
+const packageTasks = require('./package_tasks');
+const {getPackageJson} = require('./helper_tasks');
+const {RELEASE_DIR} = require('./config');
// Gets the current major version.
function getMajorVersion() {
- var { version } = getPackageJson();
- var re = new RegExp(/^(\d)./);
- var match = re.exec(version);
+ const { version } = getPackageJson();
+ const re = new RegExp(/^(\d)./);
+ const match = re.exec(version);
if (!match[0]) {
return null;
}
@@ -33,7 +33,7 @@ function getMajorVersion() {
// Updates the version depending on user input.
function updateVersion(done, updateType) {
- var majorVersion = getMajorVersion();
+ const majorVersion = getMajorVersion();
if (!majorVersion) {
done(new Error('Something went wrong when getting the major version number.'));
} else if (!updateType) {
@@ -62,14 +62,14 @@ function updateVersion(done, updateType) {
// Prompt the user to figure out what kind of version update we should do.
function updateVersionPrompt(done) {
- var releaseTypes = ['Major', 'Minor', 'Patch'];
- var index = readlineSync.keyInSelect(releaseTypes, 'Which version type?');
+ const releaseTypes = ['Major', 'Minor', 'Patch'];
+ const index = readlineSync.keyInSelect(releaseTypes, 'Which version type?');
updateVersion(done, releaseTypes[index]);
}
// Checks with the user that they are on the correct git branch.
function checkBranch(done) {
- var gitBranchName = execSync('git rev-parse --abbrev-ref HEAD').toString();
+ const gitBranchName = execSync('git rev-parse --abbrev-ref HEAD').toString();
if (readlineSync.keyInYN(`You are on '${gitBranchName.trim()}'. Is this the correct branch?`)) {
done();
} else {
@@ -101,7 +101,7 @@ function checkReleaseDir(done) {
// Check with the user that the version number is correct, then login and publish to npm.
function loginAndPublish_(done, isBeta) {
- var { version } = getPackageJson();
+ const { version } = getPackageJson();
if(readlineSync.keyInYN(`You are about to publish blockly with the version number:${version}. Do you want to continue?`)) {
execSync(`npm login --registry https://wombat-dressing-room.appspot.com`, {stdio: 'inherit'});
execSync(`npm publish --registry https://wombat-dressing-room.appspot.com ${isBeta ? '--tag beta' : ''}`, {cwd: RELEASE_DIR, stdio: 'inherit'});
@@ -124,15 +124,15 @@ function loginAndPublishBeta(done) {
// Repeatedly prompts the user for a beta version number until a valid one is given.
// A valid version number must have '-beta.x' and can not have already been used to publish to npm.
function updateBetaVersion(done) {
- var isValid = false;
- var newVersion = null;
- var blocklyVersions = JSON.parse(execSync('npm view blockly versions --json').toString());
- var re = new RegExp(/-beta\.(\d)/);
- var latestBetaVersion = execSync('npm show blockly version --tag beta').toString().trim();
+ let isValid = false;
+ let newVersion = null;
+ const blocklyVersions = JSON.parse(execSync('npm view blockly versions --json').toString());
+ const re = new RegExp(/-beta\.(\d)/);
+ const latestBetaVersion = execSync('npm show blockly version --tag beta').toString().trim();
while(!isValid) {
newVersion = readlineSync.question(`What is the new beta version? (latest beta version: ${latestBetaVersion})`);
- var existsOnNpm = blocklyVersions.indexOf(newVersion) > -1;
- var isFormatted = newVersion.search(re) > -1;
+ const existsOnNpm = blocklyVersions.indexOf(newVersion) > -1;
+ const isFormatted = newVersion.search(re) > -1;
if (!existsOnNpm && isFormatted) {
isValid = true;
} else if (existsOnNpm) {
diff --git a/scripts/gulpfiles/test_tasks.js b/scripts/gulpfiles/test_tasks.js
index 0712278b3a6..68fb6396375 100644
--- a/scripts/gulpfiles/test_tasks.js
+++ b/scripts/gulpfiles/test_tasks.js
@@ -20,11 +20,9 @@ const rimraf = require('rimraf');
const buildTasks = require('./build_tasks');
const {BUILD_DIR, RELEASE_DIR} = require('./config');
-const runMochaTestsInBrowser =
- require('../../tests/mocha/run_mocha_tests_in_browser.js');
-
-const runGeneratorsInBrowser =
- require('../../tests/generators/run_generators_in_browser.js');
+const {runMochaTestsInBrowser} = require('../../tests/mocha/webdriver.js');
+const {runGeneratorsInBrowser} = require('../../tests/generators/webdriver.js');
+const {runCompileCheckInBrowser} = require('../../tests/compile/webdriver.js');
const OUTPUT_DIR = 'build/generators';
const GOLDEN_DIR = 'tests/generators/golden';
@@ -39,7 +37,7 @@ class Tester {
this.failCount = 0;
this.tasks = tasks;
}
-
+
/**
* Run all tests in sequence.
*/
@@ -56,11 +54,11 @@ class Tester {
asTask() {
return this.runAll.bind(this);
}
-
+
/**
* Run an arbitrary Gulp task as a test.
- * @param {function} task Any gulp task
- * @return {Promise} asynchronous result
+ * @param {function} task Any Gulp task.
+ * @return {Promise} Asynchronous result.
*/
async runTestTask(task) {
const id = task.name;
@@ -106,8 +104,8 @@ class Tester {
/**
* Helper method for running test command.
- * @param {string} command command line to run
- * @return {Promise} asynchronous result
+ * @param {string} command Command line to run.
+ * @return {Promise} Asynchronous result.
*/
async function runTestCommand(command) {
execSync(command, {stdio: 'inherit'});
@@ -116,7 +114,7 @@ async function runTestCommand(command) {
/**
* Lint the codebase.
* Skip for CI environments, because linting is run separately.
- * @return {Promise} asynchronous result
+ * @return {Promise} Asynchronous result.
*/
function eslint() {
if (process.env.CI) {
@@ -128,8 +126,8 @@ function eslint() {
/**
* Run the full usual build and package process, checking to ensure
- * there are no closure compiler warnings / errors.
- * @return {Promise} asynchronous result
+ * there are no Closure Compiler warnings / errors.
+ * @return {Promise} Asynchronous result.
*/
function build() {
return runTestCommand('npm run package -- --verbose --debug');
@@ -137,7 +135,7 @@ function build() {
/**
* Run renaming validation test.
- * @return {Promise} asynchronous result
+ * @return {Promise} Asynchronous result.
*/
function renamings() {
return runTestCommand('node tests/migration/validate-renamings.js');
@@ -145,16 +143,16 @@ function renamings() {
/**
* Helper method for gzipping file.
- * @param {string} file target file
- * @return {Promise} asynchronous result
+ * @param {string} file Target file.
+ * @return {Promise} Asynchronous result.
*/
function gzipFile(file) {
return new Promise((resolve) => {
const name = path.posix.join(RELEASE_DIR, file);
const stream = gulp.src(name)
- .pipe(gzip())
- .pipe(gulp.dest(RELEASE_DIR));
+ .pipe(gzip())
+ .pipe(gulp.dest(RELEASE_DIR));
stream.on('end', () => {
resolve();
@@ -164,9 +162,9 @@ function gzipFile(file) {
/**
* Helper method for comparing file size.
- * @param {string} file target file
- * @param {number} expected expected size
- * @return {number} 0: success / 1: failed
+ * @param {string} file Target file.
+ * @param {number} expected Expected size.
+ * @return {number} 0: success / 1: failed.
*/
function compareSize(file, expected) {
const name = path.posix.join(RELEASE_DIR, file);
@@ -176,12 +174,12 @@ function compareSize(file, expected) {
if (size > compare) {
const message = `Failed: ` +
- `Size of ${name} has grown more than 10%. ${size} vs ${expected} `;
+ `Size of ${name} has grown more than 10%. ${size} vs ${expected}`;
console.log(`${BOLD_RED}${message}${ANSI_RESET}`);
return 1;
} else {
const message =
- `Size of ${name} at ${size} compared to previous ${expected}`;
+ `Size of ${name} at ${size} compared to previous ${expected}`;
console.log(`${BOLD_GREEN}${message}${ANSI_RESET}`);
return 0;
}
@@ -189,7 +187,7 @@ function compareSize(file, expected) {
/**
* Helper method for zipping the compressed files.
- * @return {Promise} asynchronous result
+ * @return {Promise} Asynchronous result.
*/
function zippingFiles() {
// GZip them for additional size comparisons (keep originals, force
@@ -202,7 +200,7 @@ function zippingFiles() {
/**
* Check the sizes of built files for unexpected growth.
- * @return {Promise} asynchronous result
+ * @return {Promise} Asynchronous result.
*/
async function metadata() {
// Zipping the compressed files.
@@ -234,10 +232,10 @@ async function metadata() {
/**
* Run Mocha tests inside a browser.
- * @return {Promise} asynchronous result
+ * @return {Promise} Asynchronous result.
*/
async function mocha() {
- const result = await runMochaTestsInBrowser().catch(e => {
+ const result = await runMochaTestsInBrowser().catch(e => {
throw e;
});
if (result) {
@@ -248,9 +246,9 @@ async function mocha() {
/**
* Helper method for comparison file.
- * @param {string} file1 first target file
- * @param {string} file2 second target file
- * @return {boolean} comparison result (true: same / false: different)
+ * @param {string} file1 First target file.
+ * @param {string} file2 Second target file.
+ * @return {boolean} Comparison result (true: same / false: different).
*/
function compareFile(file1, file2) {
const buf1 = fs.readFileSync(file1);
@@ -258,14 +256,13 @@ function compareFile(file1, file2) {
// Normalize the line feed.
const code1 = buf1.toString().replace(/(?:\r\n|\r|\n)/g, '\n');
const code2 = buf2.toString().replace(/(?:\r\n|\r|\n)/g, '\n');
- const result = (code1 === code2);
- return result;
+ return code1 === code2;
}
/**
* Helper method for checking the result of generator.
- * @param {string} suffix target suffix
- * @return {number} check result (0: success / 1: failed)
+ * @param {string} suffix Target suffix.
+ * @return {number} Check result (0: success / 1: failed).
*/
function checkResult(suffix) {
const fileName = `generated.${suffix}`;
@@ -279,12 +276,12 @@ function checkResult(suffix) {
if (fs.existsSync(goldenFileName)) {
if (compareFile(resultFileName, goldenFileName)) {
console.log(`${SUCCESS_PREFIX} ${suffix}: ` +
- `${resultFileName} matches ${goldenFileName}`);
+ `${resultFileName} matches ${goldenFileName}`);
return 0;
} else {
console.log(
- `${FAILURE_PREFIX} ${suffix}: ` +
- `${resultFileName} does not match ${goldenFileName}`);
+ `${FAILURE_PREFIX} ${suffix}: ` +
+ `${resultFileName} does not match ${goldenFileName}`);
}
} else {
console.log(`File ${goldenFileName} not found!`);
@@ -297,7 +294,7 @@ function checkResult(suffix) {
/**
* Run generator tests inside a browser and check the results.
- * @return {Promise} asynchronous result
+ * @return {Promise} Asynchronous result.
*/
async function generators() {
// Clean up.
@@ -311,7 +308,7 @@ async function generators() {
generatorSuffixes.forEach((suffix) => {
failed += checkResult(suffix);
});
-
+
if (failed === 0) {
console.log(`${BOLD_GREEN}All generator tests passed.${ANSI_RESET}`);
} else {
@@ -323,12 +320,20 @@ async function generators() {
/**
* Run Node tests.
- * @return {Promise} asynchronous result
+ * @return {Promise} Asynchronous result.
*/
function node() {
return runTestCommand('mocha tests/node --config tests/node/.mocharc.js');
}
+/**
+ * Attempt advanced compilation of a Blockly app.
+ * @return {Promise} Asynchronous result.
+ */
+function advancedCompile() {
+ const compilePromise = runTestCommand('npm run test:compile:advanced');
+ return compilePromise.then(runCompileCheckInBrowser);
+}
// Run all tests in sequence.
const test = new Tester([
@@ -339,7 +344,7 @@ const test = new Tester([
mocha,
generators,
node,
- buildTasks.onlyBuildAdvancedCompilationTest,
+ advancedCompile,
]).asTask();
diff --git a/scripts/tsick.js b/scripts/tsick.js
new file mode 100644
index 00000000000..cfe5eaf72ba
--- /dev/null
+++ b/scripts/tsick.js
@@ -0,0 +1,83 @@
+/**
+ * @license
+ * Copyright 2022 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @fileoverview Lightweight conversion from tsc ouptut to Closure Compiler
+ * compatible input.
+ */
+'use strict';
+
+// eslint-disable-next-line no-undef
+const fs = require('fs');
+
+// eslint-disable-next-line no-undef
+const DIR = process.argv[2];
+
+// Number of files rewritten.
+let fileCount = 0;
+
+/**
+ * Recursively spider the given directory and rewrite any JS files found.
+ * @param {string} dir Directory path to start from.
+ */
+function spider(dir) {
+ if (!dir.endsWith('/')) {
+ dir += '/';
+ }
+ const entries = fs.readdirSync(dir, {withFileTypes: true});
+ for (const entry of entries) {
+ if (entry.isDirectory()) {
+ spider(dir + entry.name + '/');
+ } else if (entry.name.endsWith('.js')) {
+ rewriteFile(dir + entry.name);
+ }
+ }
+}
+
+/**
+ * Given a file, rewrite it if it contains problematic patterns.
+ * @param {string} path Path of file to potentially rewrite.
+ */
+function rewriteFile(path) {
+ const oldCode = fs.readFileSync(path, 'utf8');
+ const newCode = rewriteEnum(oldCode);
+ if (newCode !== oldCode) {
+ fileCount++;
+ fs.writeFileSync(path, newCode);
+ }
+}
+
+/**
+ * Unquote enum definitions in the given code string.
+ * @param {string} code Original code generated by tsc.
+ * @return {string} Rewritten code for Closure Compiler.
+ */
+function rewriteEnum(code) {
+ // Find all enum definitions. They look like this:
+ // (function (names) {
+ // ...
+ // })(names || (names = {}));
+ const enumDefs = code.match(/\s+\(function \((\w+)\) \{\n[^}]*\}\)\(\1 [^)]+\1 = \{\}\)\);/g) || [];
+ for (const oldEnumDef of enumDefs) {
+ // enumDef looks like a bunch of lines in one of these two formats:
+ // ScopeType["BLOCK"] = "block";
+ // KeyCodes[KeyCodes["TAB"] = 9] = "TAB";
+ // We need to unquote them to look like one of these two formats:
+ // ScopeType.BLOCK = "block";
+ // KeyCodes[KeyCodes.TAB = 9] = "TAB";
+ let newEnumDef = oldEnumDef.replace(/\["(\w+)"\]/g, '.$1');
+ newEnumDef = newEnumDef.replace(') {', ') { // Converted by tsick.');
+ code = code.replace(oldEnumDef, newEnumDef);
+ }
+ return code;
+}
+
+if (DIR) {
+ spider(DIR);
+ console.log(`Unquoted enums in ${fileCount} files.`);
+} else {
+ throw Error('No source directory specified');
+}
diff --git a/tests/compile/main.js b/tests/compile/main.js
index 9e4aad1d7ec..c34f1bf1cb9 100644
--- a/tests/compile/main.js
+++ b/tests/compile/main.js
@@ -12,10 +12,13 @@ goog.module('Main');
// TODO: I think we need to make sure these get exported?
// const {BlocklyOptions} = goog.requireType('Blockly.BlocklyOptions');
const {inject} = goog.require('Blockly.inject');
+const {getMainWorkspace} = goog.require('Blockly.common');
+const {Msg} = goog.require('Blockly.Msg');
/** @suppress {extraRequire} */
goog.require('Blockly.geras.Renderer');
/** @suppress {extraRequire} */
goog.require('Blockly.VerticalFlyout');
+
// Blocks
/** @suppress {extraRequire} */
goog.require('Blockly.libraryBlocks.logic');
@@ -30,8 +33,25 @@ goog.require('testBlocks');
function init() {
+ Object.assign(Msg, window['Blockly']['Msg']);
inject('blocklyDiv', /** @type {BlocklyOptions} */ ({
'toolbox': document.getElementById('toolbox')
}));
-};
+}
window.addEventListener('load', init);
+
+
+// Called externally from our test driver to see if Blockly loaded more or less
+// correctly. This is not a comprehensive test, but it will catch catastrophic
+// fails (by far the most common cases).
+window['healthCheck'] = function() {
+ // Just check that we have a reasonable number of blocks in the flyout.
+ // Expecting 8 blocks, but leave a wide margin.
+ try {
+ const blockCount =
+ getMainWorkspace().getFlyout().getWorkspace().getTopBlocks().length;
+ return (blockCount > 5 && blockCount < 100);
+ } catch (_e) {
+ return false;
+ }
+};
diff --git a/tests/compile/webdriver.js b/tests/compile/webdriver.js
new file mode 100644
index 00000000000..50084c73b89
--- /dev/null
+++ b/tests/compile/webdriver.js
@@ -0,0 +1,82 @@
+/**
+ * @license
+ * Copyright 2022 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @fileoverview Node.js script to check the health of the compile test in
+ * Chrome, via webdriver.
+ */
+const webdriverio = require('webdriverio');
+
+
+/**
+ * Run the generator for a given language and save the results to a file.
+ * @param {Thenable} browser A Thenable managing the processing of the browser
+ * tests.
+ */
+async function runHealthCheckInBrowser(browser) {
+ const result = await browser.execute(() => {
+ return healthCheck();
+ })
+ if (!result) throw Error('Health check failed in advanced compilation test.');
+ console.log('Health check completed successfully.');
+}
+
+/**
+ * Runs the generator tests in Chrome. It uses webdriverio to
+ * launch Chrome and load index.html. Outputs a summary of the test results
+ * to the console and outputs files for later validation.
+ * @return the Thenable managing the processing of the browser tests.
+ */
+async function runCompileCheckInBrowser() {
+ const options = {
+ capabilities: {
+ browserName: 'chrome',
+ },
+ logLevel: 'warn',
+ services: ['selenium-standalone']
+ };
+ // Run in headless mode on Github Actions.
+ if (process.env.CI) {
+ options.capabilities['goog:chromeOptions'] = {
+ args: ['--headless', '--no-sandbox', '--disable-dev-shm-usage']
+ };
+ } else {
+ // --disable-gpu is needed to prevent Chrome from hanging on Linux with
+ // NVIDIA drivers older than v295.20. See
+ // https://github.com/google/blockly/issues/5345 for details.
+ options.capabilities['goog:chromeOptions'] = {
+ args: ['--disable-gpu']
+ };
+ }
+
+ const url = 'file://' + __dirname + '/index.html';
+
+ console.log('Starting webdriverio...');
+ const browser = await webdriverio.remote(options);
+ console.log('Loading url: ' + url);
+ await browser.url(url);
+
+ await runHealthCheckInBrowser(browser);
+
+ await browser.deleteSession();
+}
+
+if (require.main === module) {
+ runCompileCheckInBrowser().catch(e => {
+ console.error(e);
+ process.exit(1);
+ }).then(function(result) {
+ if (result) {
+ console.log('Compile test failed');
+ process.exit(1);
+ } else {
+ console.log('Compile test passed');
+ process.exit(0);
+ }
+ });
+}
+
+module.exports = {runCompileCheckInBrowser};
diff --git a/tests/generators/index.html b/tests/generators/index.html
index 3b108867775..c93e966d99e 100644
--- a/tests/generators/index.html
+++ b/tests/generators/index.html
@@ -19,7 +19,6 @@
-