Files
Huáng JùnliàngandGitHub 1711e5338f Migrate regenerator tests (#18020)
* test: migrate regenerator test runner to jest

* perf: parallelize the test tasks

* fix: specify test runner and environment

* Revert "perf: parallelize the test tasks"

This reverts commit 2de536c1e5a1a190ffefd22e4153fdce5c2f9534.

* chore: add comment why these tests can not be parallelized

* remove yargs resolution

* override c8/yargs resolution

* refactor: programmatically run Jest tests

* update jest versions
2026-06-08 09:37:30 -04:00

391 lines
11 KiB
JavaScript

/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var assert = require("assert");
var recast = require("recast");
var v8 = require("v8");
var types = recast.types;
var n = types.namedTypes;
function transform(ast) {
return require("@babel/core")
.transformFromAstAsync(ast, null, {
configFile: false,
ast: true,
cloneInputAst: false,
plugins: [require("../../lib/index.js")],
})
.then(res => res.ast);
}
function compile(code) {
return require("@babel/core").transformAsync(code, {
configFile: false,
plugins: [require("../../lib/index.js")],
});
}
var UglifyJS = require("uglify-js");
describe("_blockHoist nodes", function () {
it("should be hoisted to the outer body", async function () {
var foo;
var names = [];
var ast = recast.parse(
[
"function *foo(doNotHoistMe, hoistMe) {",
" var sent = yield doNotHoistMe();",
" hoistMe();",
" names.push(sent);",
" return 123;",
"}",
].join("\n"),
{
parser: require("@babel/parser"),
},
);
var hoistMeStmt = ast.program.body[0].body.body[1];
n.ExpressionStatement.assert(hoistMeStmt);
n.CallExpression.assert(hoistMeStmt.expression);
n.Identifier.assert(hoistMeStmt.expression.callee);
assert.strictEqual(hoistMeStmt.expression.callee.name, "hoistMe");
hoistMeStmt._blockHoist = 1;
eval(recast.print(await transform(ast)).code);
assert.strictEqual(typeof foo, "function");
//assert.ok(regeneratorRuntime.isGeneratorFunction(foo));
assert.strictEqual(names.length, 0);
var g = foo(
function doNotHoistMe() {
names.push("doNotHoistMe");
return "yielded";
},
function hoistMe() {
names.push("hoistMe");
},
);
assert.deepEqual(names, ["hoistMe"]);
assert.deepEqual(g.next(), { value: "yielded", done: false });
assert.deepEqual(names, ["hoistMe", "doNotHoistMe"]);
assert.deepEqual(g.next("oyez"), { value: 123, done: true });
assert.deepEqual(names, ["hoistMe", "doNotHoistMe", "oyez"]);
});
});
describe("uglifyjs dead code removal", function () {
function uglifyAndParse(file1, file2) {
var code = {
"file1.js": file1,
"file2.js": file2,
};
var options = {
toplevel: true,
// don't mangle function or variable names so we can find them
mangle: false,
output: {
// make it easier to parse the output
beautify: true,
},
};
// uglify our code
var result = UglifyJS.minify(code, options);
// parse and return the output
return recast.parse(result.code, {
parser: require("@babel/parser"),
});
}
it("works with function expressions", async function () {
var file1 = (
await compile(
["var foo = function* () {};", "var bar = function* () {};"].join("\n"),
)
).code;
var file2 = (await compile("console.log(foo());")).code;
var ast = uglifyAndParse(file1, file2);
// the results should have a single variable declaration
var variableDeclarations = ast.program.body.filter(function (b) {
return b.type === "VariableDeclaration";
});
assert.strictEqual(variableDeclarations.length, 1);
assert.strictEqual(variableDeclarations[0].declarations.length, 1);
var declaration = variableDeclarations[0].declarations[0];
// named foo
assert.strictEqual(declaration.id.name, "foo");
});
it("works with function declarations", async function () {
var file1 = (
await compile(["function* foo() {};", "function* bar() {};"].join("\n"))
).code;
var file2 = (await compile("console.log(foo());")).code;
var ast = uglifyAndParse(file1, file2);
// the results should have our foo() function
assert.ok(
ast.program.body.some(function (b) {
return b.type === "FunctionDeclaration" && b.id.name === "foo";
}),
);
// but not our bar() function
assert.ok(
!ast.program.body.some(function (b) {
return b.type === "FunctionDeclaration" && b.id.name === "bar";
}),
);
// and a single mark declaration
var variableDeclarations = ast.program.body.filter(function (b) {
return b.type === "VariableDeclaration";
});
assert.strictEqual(variableDeclarations.length, 1);
var declarations = variableDeclarations[0].declarations;
assert.strictEqual(declarations.length, 1);
var declaration = declarations[0];
// with our function name as an argument'
assert.strictEqual(declaration.init.arguments.length, 1);
assert.strictEqual(declaration.init.arguments[0].name, "foo");
});
});
describe("functions", function () {
function marksCorrectly(marked, varName) {
// marked should be a VariableDeclarator
n.VariableDeclarator.assert(marked);
// using our variable name
assert.strictEqual(marked.id.name, varName);
assertMarkCall(marked.init);
}
function assertMarkCall(node) {
// assigning a call expression to regeneratorRuntime.mark()
n.CallExpression.assert(node);
assert.strictEqual(node.callee.property.name, "m");
// with said call expression marked as a pure function
assert.strictEqual(node.leadingComments[0].value, "#__PURE__");
}
describe("function declarations", function () {
it("should work with a single function", async function () {
var ast = recast.parse("function* foo(){};", {
parser: require("@babel/parser"),
});
// get our declarations
const declaration = (await transform(ast)).program.body[2];
n.VariableDeclaration.assert(declaration);
const declarations = declaration.declarations;
// verify our declaration is marked correctly
marksCorrectly(declarations[0], "_marked");
// and has our function name as its first argument
assert.strictEqual(declarations[0].init.arguments[0].name, "foo");
});
it("should work with multiple functions", async function () {
var ast = recast.parse(
["function* foo() {};", "function* bar() {};"].join("\n"),
{
parser: require("@babel/parser"),
},
);
// get our declarations
const declaration = (await transform(ast)).program.body[2];
n.VariableDeclaration.assert(declaration);
const declarations = declaration.declarations;
// verify our declarations are marked correctly and have our function name
// as their first argument
marksCorrectly(declarations[0], "_marked");
n.Identifier.assert(declarations[0].init.arguments[0]);
assert.strictEqual(declarations[0].init.arguments[0].name, "foo");
marksCorrectly(declarations[1], "_marked2");
n.Identifier.assert(declarations[1].init.arguments[0]);
assert.strictEqual(declarations[1].init.arguments[0].name, "bar");
});
});
describe("function expressions", function () {
it("should work with a named function", async function () {
var ast = recast.parse("var a = function* foo(){};", {
parser: require("@babel/parser"),
});
// get our declarations
const declaration = (await transform(ast)).program.body[2];
n.VariableDeclaration.assert(declaration);
const declarator = declaration.declarations[0];
// verify our declaration is marked correctly
marksCorrectly(declarator, "a");
// and that our first argument is our original function expression
n.FunctionExpression.assert(declarator.init.arguments[0]);
assert.strictEqual(declarator.init.arguments[0].id.name, "foo");
});
it("should work with an anonymous function", async function () {
var ast = recast.parse("var a = function* (){};", {
parser: require("@babel/parser"),
});
// get our declarations
const declaration = (await transform(ast)).program.body[2];
n.VariableDeclaration.assert(declaration);
const declarator = declaration.declarations[0];
// verify our declaration is marked correctly
marksCorrectly(declarator, "a");
// and that our first argument is our original function expression
n.FunctionExpression.assert(declarator.init.arguments[0]);
assert.strictEqual(declarator.init.arguments[0].id.name, "_callee");
});
});
describe("class methods", function () {
it("should be correctly wrapped", function () {
const input = `
class A {
*foo() {}
}
`;
// The regenerator preset also transpiles classes
const { ast } = require("@babel/core").transformSync(input, {
configFile: false,
ast: true,
plugins: [require("../../lib/index.js")],
});
const method = ast.program.body[2].body.body[0];
n.ClassMethod.assert(method);
const return_ = method.body.body[0];
n.ReturnStatement.assert(return_);
n.CallExpression.assert(return_.argument);
assertMarkCall(return_.argument.callee);
/*
class A {
foo() {
return (
#__PURE__
regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}, _callee);
})()
);
}
}
*/
});
});
describe("variables hoisting", function () {
it("shouldn't throw about duplicate bindings", function () {
// https://github.com/babel/babel/issues/6923
const code = `
async function foo() {
(async function f(number) {
const tmp = number
})
}
`;
assert.doesNotThrow(function () {
require("@babel/core").transformSync(code, {
configFile: false,
plugins: [require("../../lib/index.js")],
});
});
});
it("should register hoisted variable bindings", function () {
// https://github.com/babel/babel/issues/10193
const code = `
const START = 1;
import { someAction } from 'actions';
function* foo() { const someAction = bar; }
`;
const compiled = require("@babel/core").transformSync(code, {
configFile: false,
plugins: [
require("../../lib/index.js"),
require("@babel/plugin-transform-modules-commonjs"),
],
}).code;
const startIndex = compiled.indexOf("START");
assert.strictEqual(compiled.indexOf("throw", startIndex), -1);
assert.strictEqual(compiled.indexOf("read-only", startIndex), -1);
});
});
});
describe("ast serialization", function () {
function getAST() {
return require("@babel/core").transformSync(
`function* foo() {
arguments;
}`,
{
ast: true,
configFile: false,
plugins: [require("../../lib/index.js")],
},
).ast;
}
it("produces an ast that is JSON serializable", function () {
assert.doesNotThrow(function () {
JSON.stringify(getAST());
});
});
it("produces an ast that is serializable with v8's serializer", function () {
assert.doesNotThrow(function () {
v8.serialize(getAST());
});
});
});