Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Batch enumerateFiles into a single web request #23972

Merged
merged 2 commits into from
May 9, 2018

Conversation

rbuckton
Copy link
Member

@rbuckton rbuckton commented May 8, 2018

One of the things we added in the VFS PR was the ability to define multiple values for // @module: and // @target: in compiler tests, to eventually migrate over the project tests. Because this was happening during test discovery, running the tests in the browser would take some time before the test run could start.

This PR changes the behavior of enumerateTestFiles to list the available test files and determine multiple configurations in a single HTTP request, speeding up initial load time when using runtests-browser.

Fixes #23877

@rbuckton rbuckton requested review from a user and mhegazy May 8, 2018 20:24
Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it important that we parse the test configurations early on? Couldn't we wait to handle that until we're actually running the test (which may not happen if just running one test)?

public static getConfigurations(file: string): CompilerFileBasedTest {
// also see `parseCompilerTestConfigurations` in tests/webTestServer.ts
const content = Harness.IO.readFile(file);
const rootDir = file.indexOf("conformance") === -1 ? "tests/cases/compiler/" : ts.getDirectoryPath(file) + "/";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ts.contains useful here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ts.contains is for arrays. file is a string.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, ts.stringContains

const rootDir = file.indexOf("conformance") === -1 ? "tests/cases/compiler/" : ts.getDirectoryPath(file) + "/";
const payload = Harness.TestCaseParser.makeUnitsFromTest(content, file, rootDir);
const settings = Harness.TestCaseParser.extractCompilerSettings(content);
const scriptTargets = CompilerTest._split(settings.target);
Copy link

@ghost ghost May 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: _foo indicates an unused variable, why not split?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we chose to make _x indicate an unused variable, its also traditionally used to indicate a private member of a type.

if (scriptTarget) settings.target = scriptTarget;
if (moduleKind) settings.module = moduleKind;
configurations.push({ name, payload: { ...testCaseContent, settings } });
configurations.push({ name, settings });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the name is derived from the settings, why not compute it at its use?

this.tests.forEach(test => {
const file = typeof test === "string" ? test : test.file;
describe(file, () => {
let fn = ts.normalizeSlashes(file);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took me a minute to realize this meant fileName not function

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but in general I am just trying to preserve as much of the original source here as I can.

const file = typeof test === "string" ? test : test.file;
describe(file, () => {
let fn = ts.normalizeSlashes(file);
const justName = fn.replace(/^.*[\\\/]/, "");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ts.getBaseFileName?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly, but that source is unchanged from the original (aside from indentation).

if (justName && !justName.match(/fourslash\.ts$/i) && !justName.match(/\.d\.ts$/i)) {
it(this.testSuiteName + " test " + justName + " runs correctly", () => {
FourSlash.runFourSlashTest(this.basePath, this.testType, fn);
if (justName && !justName.match(/fourslash\.ts$/i) && !justName.match(/\.d\.ts$/i)) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we somehow got an empty name we don't run the test -- maybe this should be an assert instead of an if?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly, but that source is unchanged from the original (aside from indentation).

case "conformance":
case "compiler":
return listFiles(`tests/cases/${runner}`, /*serverDirname*/ undefined, /\.tsx?$/, { recursive: true }).map(parseCompilerTestConfigurations);
case "fourslash":
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For these other cases only the directory name varies -- could use a map or switch statement for just that, then return listFiles(dir, ...); unconditionally.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but the code becomes more complicated and much less readable that way.


let match: RegExpExecArray;
/* tslint:disable:no-null-keyword */
while ((match = optionRegex.exec(content)) !== null) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: prefer // tslint:disable-line no-null-keyword on this line, or // tslint:disable-next-line no-null-keyword on the previous line

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, that's unneeded since I've disabled that rule throughout the whole file.

@rbuckton
Copy link
Member Author

rbuckton commented May 9, 2018

Why is it important that we parse the test configurations early on? Couldn't we wait to handle that until we're actually running the test (which may not happen if just running one test)?

When you are performing combinatorial testing of a feature, you want to ensure each combination is tested in isolation. So if you write a test that uses // @target: es2015, es5, you effectively need a different test suite for es2015 and es5, which is what we've always done previously for the Projects test runner.

To know whether we need to have a single or multiple configurations we need to parse the test option comments at the top of the file. We cannot do this when the test starts since we need to properly set up the various test suites and tests using describe, before, and it early for Mocha's test discovery.

@rbuckton rbuckton merged commit 5af7e06 into master May 9, 2018
@rbuckton rbuckton deleted the batchTestConfigurationsForBrowser branch May 9, 2018 21:15
@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant