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

Refactor/reorg test driver to resurect browser testing. #1868

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions demo/expressServer.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
var express = require('express');
var http = require('http');
var serveIndex = require('serve-index');

Copy link
Collaborator

Choose a reason for hiding this comment

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

Does this need a copyright header?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

import {globPatterns} from '../test/modular/NodeTraceurTestRunner.js';

let express = require('express');
let http = require('http');
let serveIndex = require('serve-index');

function servePathAtPort(path, port) {
var app = express();
app.use(express.static(path)); // before directory to allow index.html to work
let app = express();
// serveIndex must precede static to allow index.html to work
app.use(serveIndex(path));
var server = http.createServer(app);
app.use(express.static(path));
// Expand the test list based on the file system.
app.get('/traceurService/testGlobs', function(req, res) {
let patterns = JSON.parse(req.query.patterns);
return globPatterns(patterns).then((files) => {
return res.send(files);
});
});
let server = http.createServer(app);
server.on('error', function(e) {
console.log('Port ' + port + ' did not work out');
console.log('Port ' + port + ' did not work out');
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe console.error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

});
server.listen.apply(server, [port]);
console.log('serving ' + path + ' at ' + port);
}

servePathAtPort(__dirname + '/..', 8099);
servePathAtPort(__dirname + '/..', 80);
servePathAtPort(System.dirname(__moduleName) + '/..', 8099);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a Node script, so __dirname should be available. (i.e., since require is available, so is __dirname). Better to use the "standard" version than the Traceur-specific one, I think.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Good point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd like to shoot for 100% self-hosting, so I'd like this file to be es6 also.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should experiment with the 'asynchronous import' loader ideas to see if anything reasonable can be done for __dirname.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure what you mean by "We should experiment with the 'asynchronous import' loader ideas"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

whatwg/loader#36
search for 'async import'. As far as I can tell, this is about correctly setting the referrer for import done by function call. That much is dealt with by node using a function wrapper that passes in a version of require() that knows the callers module path. That same wrapper in node sets the __dirName value for the module, so I'm extrapolating to imagine that the same solution would apply.

To be honest, I think such experimenting would be mostly for furn. I think node will just continue on with the require wrapper thing.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't want to hold you up based on this. Lets move on.

servePathAtPort(System.dirname(__moduleName) + '/..', 80);
11 changes: 8 additions & 3 deletions src/runtime/ModuleStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
var lines = this.func.toString().split('\n')

var evaled = [];
ex.stack.split('\n').some(function(frame) {
ex.stack.split('\n').some(function(frame, index) {
// End when we find ourselves on the stack.
if (frame.indexOf('UncoatedModuleInstantiator.getUncoatedModule') > 0)
return true;
Expand All @@ -146,13 +146,18 @@
if (m) {
var line = parseInt(m[2], 10);
evaled = evaled.concat(beforeLines(lines, line));
evaled.push(columnSpacing(m[3]) + '^');
// The first evaled frame should be the one from 'this.func'
if (index === 1) {
evaled.push(columnSpacing(m[3]) + '^ ' + this.url);
} else {
evaled.push(columnSpacing(m[3]) + '^');
}
evaled = evaled.concat(afterLines(lines, line));
evaled.push('= = = = = = = = =');
} else {
evaled.push(frame);
}
});
}.bind(this));
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can use an arrow function here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sorry, this is bootstrap code.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This file already uses destructuring so it is being compiled already.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

ex.stack = evaled.join('\n');
}

Expand Down
50 changes: 50 additions & 0 deletions test/modular/BrowserTraceurTestRunner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2015 Traceur Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* @fileoverview Configure mocha for Traceur testing. */
Copy link
Collaborator

Choose a reason for hiding this comment

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

/** for jsdoc

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


import {TraceurTestRunner} from './TraceurTestRunner.js';
import {webLoader} from '../../src/runtime/webLoader.js';

export class BrowserTraceurTestRunner extends TraceurTestRunner {

constructor(traceurTestOptions) {
super({
reporter: 'html',
ui: 'tdd',
importMetadata: {
traceurOptions: {
sourceMaps: 'inline'
}
}
}, traceurTestOptions);
}

expandPatterns() {
let url = './traceurService/testGlobs?patterns=';
url += encodeURIComponent(JSON.stringify(this.patterns_));
return new Promise((resolve, reject) => {
webLoader.load(url, (files) => {
resolve(JSON.parse(files).forEach((file) => this.addFile(file)));
}, (ex) => {
console.error(url + ' FAILED ', ex.stack || ex);
});
});
}

getOptions() {
return this.defaultOptions();
}

};
7 changes: 2 additions & 5 deletions test/modular/Mocha6.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@

/** @fileoverview Wrap Mocha in es6 layer */

var Mocha = require('mocha');
var path = require('path');
var Runner = require('mocha/lib/runner');
var reporters = require('mocha/lib/reporters');
import {Mocha, Runner, reporters} from './MochaDependencies.js';

export class Mocha6 extends Mocha {

Expand All @@ -43,7 +40,7 @@ export class Mocha6 extends Mocha {

importFiles() {
var promiseImports = this.files.map((file) => {
file = path.resolve(file).replace(/\\/g, '/');
file = './' + file.replace(/\\/g, '/');;
this.suite.emit('pre-require', global, file, this);
return System.import(file, {metadata: this.options.importMetadata}).
then(() => {
Expand Down
29 changes: 29 additions & 0 deletions test/modular/MochaDependencies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2015 Traceur Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/** @fileoverview Mocha dependencies from Node */

export var Mocha;
Copy link
Collaborator

Choose a reason for hiding this comment

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

var -> let

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

export var Runner;
export var reporters;

if (typeof window === 'undefined') {
Mocha = require('mocha');
Runner = require('mocha/lib/runner');
reporters = require('mocha/lib/reporters');
} else {
Mocha = window.Mocha;
Runner = Mocha.Runner;
reporters = Mocha.reporters;
}
96 changes: 96 additions & 0 deletions test/modular/NodeTraceurTestRunner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2015 Traceur Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/* @fileoverview Configure mocha for Traceur testing. */
Copy link
Collaborator

Choose a reason for hiding this comment

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

jsdoc

/**
 * @fileoverview ...
 */

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done


import {TraceurTestRunner} from './TraceurTestRunner.js';

export function globPatterns(patterns) {
// This require will cause a compile error if at file scope.
Copy link
Collaborator

Choose a reason for hiding this comment

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

if at file scope?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Module scope? I guess.

// TOOD async load the class.
let glob = require('glob');
return Promise.all(
patterns.map((pattern) => {
return new Promise((resolve, reject) => {
glob(pattern, {}, (err, files) => {
if (err) {
reject(err);
} else {
resolve(files);
}
});
});
})).then((arrayOfFiles) => {
let allFiles = [];
arrayOfFiles.forEach((files) => {
allFiles = allFiles.concat(files);
Copy link
Collaborator

Choose a reason for hiding this comment

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

allFiles.push(...files)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

});
return allFiles;
});;
Copy link
Collaborator

Choose a reason for hiding this comment

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

;;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

}

export class NodeTraceurTestRunner extends TraceurTestRunner {
constructor(traceurTestOptions) {
super({
ui: 'tdd',
ignoreLeaks: true,
importMetadata: {
traceurOptions: {
sourceMaps: 'memory',
require: true // Some unit tests use require()
}
}
}, traceurTestOptions);
}

// Reads process arguments, merges defaults options, returns options object.
getOptions() {
let {Command} = require('commander');
let testOptions = this.defaultOptions();
let commandLine =
new Command(process.argv[0] + ' ' + process.argv[1]);

Object.getOwnPropertyNames(testOptions).forEach((prop) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe Object.keys since we only want enumerable keys?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

commandLine[prop] = testOptions[prop];
});

commandLine.option('-?, --help', 'Show this help text', () => {
commandLine.help();
}).usage('[options] [files]')

// Selected mocha options supported.
commandLine.option('-g, --grep <pattern>', 'only run tests matching <pattern>').
option('-i, --invert', 'inverts --grep matches').
option('-b, --bail', 'bail after first test failure');

commandLine.command('only <file> [files...]').
description('only test these [files] ').action(
(file, files) => {
commandLine.patterns = [file];
if (files)
commandLine.patterns = commandLine.patterns.concat(files);
});

commandLine.parse(process.argv);

return commandLine;
}

expandPatterns() {
return globPatterns(this.patterns_).then((files) => {
files.forEach((file) => this.addFile(file));
});
}

};
86 changes: 20 additions & 66 deletions test/modular/TraceurTestRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,93 +15,47 @@
/* @fileoverview Configure mocha for Traceur testing. */

import {Mocha6} from './Mocha6.js';
let {Command} = require('commander');
let glob = require('glob');

export class TraceurTestRunner extends Mocha6 {
constructor(defaultOptions) {
super({
ui: 'tdd',
ignoreLeaks: true,
importMetadata: {
traceurOptions: {
sourceMaps: 'memory',
require: true // Some unit tests use require()
}
}
});
this.defaultOptions_ = defaultOptions;
constructor(mochaOptions, traceurTestOptions) {
super(mochaOptions);
this.defaultOptions_ = traceurTestOptions || {};
this.patterns_ = [];
}

// For derived classes to override.
defaultOptions() {
return this.defaultOptions_;
}

// Reads process arguments, merges defaults options, returns options object.
parseCommandLine() {
let testOptions = this.defaultOptions();
let commandLine =
new Command(process.argv[0] + ' ' + process.argv[1]);

Object.getOwnPropertyNames(testOptions).forEach((prop) => {
commandLine[prop] = testOptions[prop];
});

commandLine.option('-?, --help', 'Show this help text', () => {
commandLine.help();
}).usage('[options] [files]')

// Selected mocha options supported.
commandLine.option('-g, --grep <pattern>', 'only run tests matching <pattern>').
option('-i, --invert', 'inverts --grep matches').
option('-b, --bail', 'bail after first test failure');

commandLine.command('only <file> [files...]').
description('only test these [files] ').action(
(file, files) => {
commandLine.patterns = [file];
if (files)
commandLine.patterns = commandLine.patterns.concat(files);
});

commandLine.parse(process.argv);

return commandLine;
}

applyOptions(testOptions) {
applyOptions(patterns) {
// Apply the mocha options
var testOptions = this.getOptions();
if (testOptions.grep)
this.grep(new RegExp(testOptions.grep));
if (testOptions.invert)
this.invert();
if (testOptions.bail)
this.bail();

testOptions.patterns.forEach((pattern) => {
let files = glob.sync(pattern, {});
files.forEach((file) => this.addFile(file));
});
this.patterns_ = patterns;
}

run() {
let failed = 0;
super.run().then((runner) => {
runner.on('fail', (err) => {
failed++;
});
runner.on('end', () => {
process.exit(failed);
return this.expandPatterns().then(() => {
return super.run().then((runner) => {
return new Promise((resolve, reject) => {
runner.on('fail', (err) => {
failed++;
});
runner.on('end', () => {
resolve(failed);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this be if (failed) reject(...)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, we are counting failures and resolving to the number (for the old school return code). I changed the var name to number of failures.

});
runner.on('error', (ex) => {
reject(ex);
});
});
});
}, (ex) => {
console.log('Test setup FAILED ', ex.stack || ex);
process.exit(failed);
});
}

parseOptionsAndRun() {
this.applyOptions(this.parseCommandLine());
this.run();
}
};
8 changes: 7 additions & 1 deletion test/runUnitTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,10 @@

import {unitTestRunner} from './unit/unitTestRunner.js';

unitTestRunner.parseOptionsAndRun();
unitTestRunner.run().catch((ex) => {
if (typeof ex === 'number') {
Copy link
Collaborator

Choose a reason for hiding this comment

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

wrong indent

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

process.exit(ex);
}
console.log('unitTestRunner FAILED', ex.stack || ex);
process.exit(-1);
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

missing newline

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Loading