fix: Fix the compiler test, and check if it worked. (#6638)

* Add tsick.js to rewrite enums.

tsc generates JavaScript which is incompatible with the Closure Compiler's advanced optimizations.

* Remove unused 'outputCode' variable.

* Rename 'run_X_in_browser.js' to 'webdriver.js'

The Mocha and generator tests can both be run either manually or via our webdriver.  In all cases they run in a browser.  These two 'run_X_in_browser.js' files only apply to webdriver, thus they are confusingly named.

Also delete completely unused (and broken) `run_all_tests.sh`

* Linting improvements to mocha/webdriver.js

Still not at 100%.  Complains about require/module/process/__dirname not being defined in multiple places.

* runTestBlock -> runTestFunction

'Block' means something very different in Blockly.

* Removal of `var` from scripts.

* Add webdriver test to verify compile test worked.

* Resolve conficts with 'develop'.

* Address PR comments.
This commit is contained in:
Neil Fraser
2022-11-25 20:45:00 +01:00
committed by GitHub
parent be4b8323c5
commit 5a64a9a7f7
14 changed files with 349 additions and 154 deletions

View File

@@ -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/*

View File

@@ -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(

View File

@@ -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',

View File

@@ -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.

View File

@@ -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.');

View File

@@ -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 <script src="https://unpkg.com/blockly/blockly.min.js"></script>
*/
function packageUMDBundle() {
var srcs = [
const srcs = [
`${RELEASE_DIR}/blockly_compressed.js`,
`${RELEASE_DIR}/msg/en.js`,
`${RELEASE_DIR}/blocks_compressed.js`,

View File

@@ -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) {

View File

@@ -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();

83
scripts/tsick.js Normal file
View File

@@ -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');
}

View File

@@ -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;
}
};

View File

@@ -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};

View File

@@ -19,7 +19,6 @@
<script src="../bootstrap.js"></script>
<script>
var demoWorkspace = null;
var outputCode = '';
function start() {
demoWorkspace = Blockly.inject('blocklyDiv', {
@@ -172,31 +171,26 @@ function toJavaScript() {
var code = '\'use strict\';\n\n'
code += javascriptGenerator.workspaceToCode(demoWorkspace);
setOutput(code);
outputCode = code;
}
function toPython() {
var code = pythonGenerator.workspaceToCode(demoWorkspace);
setOutput(code);
outputCode = code;
}
function toPhp() {
var code = phpGenerator.workspaceToCode(demoWorkspace);
setOutput(code);
outputCode = code;
}
function toLua() {
var code = luaGenerator.workspaceToCode(demoWorkspace);
setOutput(code);
outputCode = code;
}
function toDart() {
var code = dartGenerator.workspaceToCode(demoWorkspace);
setOutput(code);
outputCode = code;
}
function changeIndex() {
@@ -205,7 +199,7 @@ function changeIndex() {
demoWorkspace.getToolbox().flyout_.workspace_.options.oneBasedIndex = oneBasedIndex;
}
</script>
<script type=module>
<script type="module">
// Wait for Blockly to finish loading before running tests.
import '../bootstrap_done.mjs';

View File

@@ -5,13 +5,12 @@
*/
/**
* @fileoverview Node.js script to run generator tests in Firefox, via webdriver.
* @fileoverview Node.js script to run generator tests in Chrome, via webdriver.
*/
var webdriverio = require('webdriverio');
var fs = require('fs');
var path = require('path');
module.exports = runGeneratorsInBrowser;
/**
* Run the generator for a given language and save the results to a file.
@@ -36,8 +35,8 @@ async function runLangGeneratorInBrowser(browser, filename, codegenFn) {
* 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.
* @param {string} outputDir output directory
* @return the Thenable managing the processing of the browser tests.
* @param {string} outputDir Output directory.
* @return The Thenable managing the processing of the browser tests.
*/
async function runGeneratorsInBrowser(outputDir) {
var options = {
@@ -66,7 +65,7 @@ async function runGeneratorsInBrowser(outputDir) {
console.log('Starting webdriverio...');
const browser = await webdriverio.remote(options);
console.log('Initialized.\nLoading url: ' + url);
console.log('Loading url: ' + url);
await browser.url(url);
await browser.execute(function() {
@@ -112,3 +111,5 @@ if (require.main === module) {
}
});
}
module.exports = {runGeneratorsInBrowser};

View File

@@ -7,10 +7,9 @@
/**
* @fileoverview Node.js script to run Mocha tests in Chrome, via webdriver.
*/
var webdriverio = require('webdriverio');
var {posixPath} = require('../../scripts/helpers');
const webdriverio = require('webdriverio');
const {posixPath} = require('../../scripts/helpers');
module.exports = runMochaTestsInBrowser;
/**
* Runs the Mocha tests in this directory in Chrome. It uses webdriverio to
@@ -19,14 +18,14 @@ module.exports = runMochaTestsInBrowser;
* @return {number} 0 on success, 1 on failure.
*/
async function runMochaTestsInBrowser() {
var options = {
const options = {
capabilities: {
browserName: 'chrome'
browserName: 'chrome',
},
services: [
['selenium-standalone']
['selenium-standalone'],
],
logLevel: 'warn'
logLevel: 'warn',
};
// Run in headless mode on Github Actions.
if (process.env.CI) {
@@ -34,41 +33,41 @@ async function runMochaTestsInBrowser() {
args: [
'--headless', '--no-sandbox', '--disable-dev-shm-usage',
'--allow-file-access-from-files',
]
],
};
} 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: ['--allow-file-access-from-files', '--disable-gpu']
args: ['--allow-file-access-from-files', '--disable-gpu'],
};
}
var url = 'file://' + posixPath(__dirname) + '/index.html';
const url = 'file://' + posixPath(__dirname) + '/index.html';
console.log('Starting webdriverio...');
const browser = await webdriverio.remote(options);
console.log('Initialized.\nLoading url: ' + url);
console.log('Loading URL: ' + url);
await browser.url(url);
await browser.waitUntil(async () => {
var elem = await browser.$('#failureCount');
var text = await elem.getAttribute('tests_failed');
return text != 'unset';
await browser.waitUntil(async() => {
const elem = await browser.$('#failureCount');
const text = await elem.getAttribute('tests_failed');
return text !== 'unset';
}, {
timeout: 50000
timeout: 50000,
});
const elem = await browser.$('#failureCount');
const numOfFailure = await elem.getAttribute('tests_failed');
if (numOfFailure > 0) {
console.log('============Blockly Mocha Test Failures================')
console.log('============Blockly Mocha Test Failures================');
const failureMessagesEls = await browser.$$('#failureMessages p');
if (!failureMessagesEls.length) {
console.log('There is at least one test failure, but no messages reported. Mocha may be failing because no tests are being run.');
}
for (let el of failureMessagesEls) {
for (const el of failureMessagesEls) {
console.log(await el.getText());
}
}
@@ -84,7 +83,7 @@ async function runMochaTestsInBrowser() {
}
if (require.main === module) {
runMochaTestsInBrowser().catch(e => {
runMochaTestsInBrowser().catch((e) => {
console.error(e);
process.exit(1);
}).then(function(result) {
@@ -97,3 +96,5 @@ if (require.main === module) {
}
});
}
module.exports = {runMochaTestsInBrowser};