Rename test-app -> test and test --full-app

Our old "unit" test mode didn't really enforce "unit-ness" and was perfectly capable of running integration test. So it was confusing to call the two modes unit and integration test modes.

Instead, we call them "test mode" and "full app test mode", run with `meteor test` and `meteor test --full-app`.

The rules for test files were also simplified -- simply *.test[s].* for test mode, and *.app-test[s].* for full app tests. `tests/` directories are simply ignored again.
This commit is contained in:
Tom Coleman
2016-02-26 22:01:06 +11:00
parent 0cee429c7f
commit ab5ab15768
9 changed files with 76 additions and 117 deletions

View File

@@ -160,7 +160,7 @@
### Testing
* Packages can now be marked as `testOnly` to only run as part of app
testing with `meteor test-app`. This is achieved by setting
testing with `meteor test`. This is achieved by setting
`testOnly: true` to `Package.describe`.

View File

@@ -1421,7 +1421,7 @@ main.registerCommand({
});
///////////////////////////////////////////////////////////////////////////////
// test-app and test-packages
// test and test-packages
///////////////////////////////////////////////////////////////////////////////
testCommandOptions = {
@@ -1479,20 +1479,19 @@ testCommandOptions = {
'exclude': { type: String },
// one of the following must be true
'test-app': { type: Boolean, 'default': false },
'test': { type: Boolean, 'default': false },
'test-packages': { type: Boolean, 'default': false },
// For 'test-packages': Run in unit test or integration test mode
'unit': { type: Boolean, 'default': false },
'integration': { type: Boolean, 'default': false }
// For 'test-packages': Run in "full app" mode
'full-app': { type: Boolean, 'default': false }
}
};
main.registerCommand(_.extend({
name: 'test-app',
name: 'test',
requiresApp: true
}, testCommandOptions), function (options) {
options['test-app'] = true;
options['test'] = true;
return doTestCommand(options);
});
@@ -1590,7 +1589,7 @@ function doTestCommand(options) {
}
// Use the driver package if running `meteor test-packages`. For
// `meteor test-app`, the driver package is expected to already
// `meteor test`, the driver package is expected to already
// have been added to the app.
packagesToAdd.unshift(global.testCommandMetadata.driverPackage);
@@ -1612,24 +1611,16 @@ function doTestCommand(options) {
// the project for build hits errors, we don't lose them on
// projectContext.reset.
projectContext.projectConstraintsFile.writeIfModified();
} else if (options["test-app"]) {
} else if (options["test"]) {
if (!options['driver-package']) {
throw new Error("You must specify a driver package with --driver-package");
}
global.testCommandMetadata.driverPackage = options['driver-package'];
// Default to `--integration`
if (!options.unit && !options.integration) {
options.integration = true;
}
if (options.unit && options.integration) {
throw new Error("Can't pass both --unit and --integration");
}
global.testCommandMetadata.isUnitTest = options.unit;
global.testCommandMetadata.isIntegrationTest = options.integration;
global.testCommandMetadata.isAppTest = options['full-app'];
global.testCommandMetadata.isTest = !global.testCommandMetadata.isAppTest;
projectContextOptions.projectDir = options.appDir;
projectContextOptions.projectLocalDir = files.pathJoin(testRunnerAppDir, '.meteor', 'local');
@@ -1664,7 +1655,7 @@ function doTestCommand(options) {
projectContext.initializeCatalog();
});
} else {
throw new Error("Unexpected: neither test-packages nor test-app");
throw new Error("Unexpected: neither test-packages nor test");
}
// The rest of the projectContext preparation process will happen inside the
@@ -1761,10 +1752,10 @@ var runTestAppForPackages = function (projectContext, options) {
};
if (options["test-packages"]) {
buildOptions.buildMode = buildOptions.minifyMode;
} else if (options["test-app"]) {
} else if (options["test"]) {
buildOptions.buildMode = "test";
} else {
throw new Error("Neither test-packages nor test-app in options");
throw new Error("Neither test-packages nor test in options");
}
if (options.deploy) {

View File

@@ -536,27 +536,25 @@ Options:
--verbose Print all output from builds logs.
--no-lint Don't run linters used by the tested packages on every
test app rebuild.
>>> test-app
>>> test
Test the application
Usage: meteor test-app --driver-package <driver> [options]
meteor test-app --driver-package <driver> --unit [options]
meteor test-app --driver-package <driver> --integration [options]
Usage: meteor test --driver-package <driver> [options]
meteor test --full-app --driver-package <driver> [options]
Runs tests against the application, either in *unit* or *integration*
(the default) test mode. meteor test-app will start a special app based on
a test driver (specified with --driver-package -- read more about driver
packages at http://guide.meteor.com/testing.html#driver-packages)
which handles the task of running tests and displaying the results in the
browser when you visit it.
Runs tests against the application.
Will start a special app based on a test driver (specified with
--driver-package -- read more about driver packages at
http://guide.meteor.com/testing.html#driver-packages) which handles the
task of running tests and displaying the results in the browser when you
visit it.
In unit test mode, no files in your application are eagerly loaded, aside
from test files (in you tests/ directory or named test[s].* or *.test[s].*).
In normal test mode, no files in your application are eagerly loaded, aside
from test files (files named *.test[s].* placed anywhere in your application).
You can import your app's modules from within your tests and test them in
isolation.
In integration test mode, your app is loaded as usual, and then made hidden,
In "full app" test mode, your app is loaded as usual, and then made hidden,
and your tests can inspect and effect the running state. Test files are
loaded similarly to unit test mode.
loaded similarly to unit test mode, but must be called *.app-test[s].*.
Open the test dashboard in your browser to run the tests and see the
results. By default the URL is localhost:3000 but that can be changed

View File

@@ -1,47 +0,0 @@
import _ from 'underscore';
import { pathSep } from '../fs/files';
export const TEST_FILENAME_REGEXPS = [
// "*.test.*" or "*.tests.*"
/\.tests?./,
// "test.*" or "tests.*"
/^tests?./
];
// Specific filename paths for unit or integration tests.
// Note that imporatantly they both pass the TEST_FILENAME_REGEXPS above
export const UNIT_TEST_FILENAME_REGEXPS = [
// "*.unit.test.*" or "*.unit.tests.*"
/\.unit\.tests?./,
];
export const INTEGRATION_TEST_FILENAME_REGEXPS = [
// "*.integration.test.*" or "*.integration.tests.*"
/\.integration\.tests?./,
];
export const TEST_DIRNAME_REGEXPS = [
// a directory exactly named "tests"
/^tests\/$/
];
// Given a path to a file in an app (relative to the app root
// directory), is this file a test file?
export function isTestFilePath(path) {
const splitPath = path.split(pathSep);
// Does any path of the path other than the filename match one of
// the test dirname forms?
const inTestsDir = _.any(
_.initial(splitPath),
dirname => _.any(
TEST_DIRNAME_REGEXPS,
regexp => regexp.test(dirname)));
// Does the filename match one of the test filename forms?
const isTestFilename = _.any(
TEST_FILENAME_REGEXPS,
regexp => regexp.test(_.last(splitPath)));
return inTestsDir || isTestFilename;
}

View File

@@ -14,7 +14,7 @@ import Fiber from 'fibers';
import {sourceMapLength} from '../utils/utils.js';
import ImportScanner from './import-scanner.js';
import { isTestFilePath } from './app-test-files.js';
import { isTestFilePath } from './test-files.js';
// This file implements the new compiler plugins added in Meteor 1.2, which are
// registered with the Plugin.registerCompiler API.
@@ -385,7 +385,7 @@ class ResourceSlot {
// it is contained by an imports directory. Note that any files
// contained by a node_modules directory will already have been
// marked lazy in PackageSource#_inferFileOptions. Same for
// non-test files if running unit tests (`meteor test-app --unit`)
// non-test files if running (non-full-app) tests (`meteor test`)
if (!this.packageSourceBatch.useMeteorInstall) {
return false;
}
@@ -394,8 +394,8 @@ class ResourceSlot {
const isInImports = splitPath.indexOf("imports") >= 0;
if (global.testCommandMetadata &&
(global.testCommandMetadata.isUnitTest ||
global.testCommandMetadata.isIntegrationTest)) {
(global.testCommandMetadata.isTest ||
global.testCommandMetadata.isAppTest)) {
// test files should always be included, if we're running app
// tests.
return isInImports && !isTestFilePath(this.inputResource.path);

View File

@@ -974,7 +974,7 @@ export var fullLink = Profile("linker.fullLink", function (inputFiles, {
var prelinkedFiles = module.getPrelinkedFiles();
// are we running `meteor test-app` or `meteor test-packages`?
// are we running `meteor test` or `meteor test-packages`?
// Include a short code snippet that sets `Meteor.isTest` and calls
// `runTests`.
if (global.testCommandMetadata) {
@@ -1073,16 +1073,15 @@ export var fullLink = Profile("linker.fullLink", function (inputFiles, {
function getTestPreamble() {
const testDriverPackageName = global.testCommandMetadata.driverPackage;
let setMeteorIntegrationOrUnitTest = "";
if (global.testCommandMetadata.isUnitTest) {
setMeteorIntegrationOrUnitTest = "Package.meteor.Meteor.isUnitTest = true;";
} else if (global.testCommandMetadata.isIntegrationTest) {
setMeteorIntegrationOrUnitTest = "Package.meteor.Meteor.isIntegrationTest = true;";
let setMeteorTest = "";
if (global.testCommandMetadata.isTest) {
setMeteorTest = "Package.meteor.Meteor.isTest = true;";
} else if (global.testCommandMetadata.isAppTest) {
setMeteorTest = "Package.meteor.Meteor.isAppTest = true;";
}
return `\
Package.meteor.Meteor.isTest = true;
${setMeteorIntegrationOrUnitTest}
${setMeteorTest}
if (Package.meteor.Meteor.isClient) {
Package.meteor.Meteor.startup(function() {

View File

@@ -19,10 +19,8 @@ import SourceArch from './source-arch.js';
import {
TEST_FILENAME_REGEXPS,
UNIT_TEST_FILENAME_REGEXPS,
INTEGRATION_TEST_FILENAME_REGEXPS,
TEST_DIRNAME_REGEXPS,
isTestFilePath } from './app-test-files.js';
APP_TEST_FILENAME_REGEXPS,
isTestFilePath } from './test-files.js';
// XXX: This is a medium-term hack, to avoid having the user set a package name
// & test-name in package.describe. We will change this in the new control file
@@ -318,7 +316,7 @@ var PackageSource = function () {
self.prodOnly = false;
// A package marked testOnly is ONLY picked up by the bundler as
// part of the `meteor test-app` command.
// part of the `meteor test` command.
self.testOnly = false;
// If this is set, we will take the currently running git checkout and bundle
@@ -533,7 +531,7 @@ _.extend(PackageSource.prototype, {
* @param {Boolean} options.prodOnly A package with this flag set to true
* will ONLY be bundled into production builds.
* @param {Boolean} options.testOnly A package with this flag set to true
* will ONLY be bundled as part of `meteor test-app`.
* will ONLY be bundled as part of `meteor test`.
*/
describe: function (options) {
_.each(options, function (value, key) {
@@ -591,7 +589,7 @@ _.extend(PackageSource.prototype, {
// when set to true, they cause a package's code to be
// only included (i.e. linked into the bundle) in dev
// mode, prod mode (`meteor --production`) or app tests
// (`meteor test-app`), and excluded otherwise.
// (`meteor test`), and excluded otherwise.
//
// Notes:
//
@@ -1349,9 +1347,9 @@ _.extend(PackageSource.prototype, {
fileOptions.transpile = false;
}
// If running in unit test mode (`meteor test-app --unit`), all
// If running in test mode (`meteor test`), all
// files other than test files should be loaded lazily
if (global.testCommandMetadata && global.testCommandMetadata.isUnitTest) {
if (global.testCommandMetadata && global.testCommandMetadata.isTest) {
if (!isTestFilePath(relPath)) {
fileOptions.lazy = true;
}
@@ -1393,12 +1391,11 @@ _.extend(PackageSource.prototype, {
// Unless we're running tests, ignore all test filenames and if we are, ignore the
// type of file we *aren't* running
if (!global.testCommandMetadata) {
if (!global.testCommandMetadata || global.testCommandMetadata.isTest) {
Array.prototype.push.apply(sourceReadOptions.exclude, APP_TEST_FILENAME_REGEXPS);
}
if (!global.testCommandMetadata || global.testCommandMetadata.isAppTest) {
Array.prototype.push.apply(sourceReadOptions.exclude, TEST_FILENAME_REGEXPS);
} else if (global.testCommandMetadata.isUnitTest) {
Array.prototype.push.apply(sourceReadOptions.exclude, INTEGRATION_TEST_FILENAME_REGEXPS);
} else if (global.testCommandMetadata.isIntegrationTest) {
Array.prototype.push.apply(sourceReadOptions.exclude, UNIT_TEST_FILENAME_REGEXPS);
}
// Read top-level source files, excluding control files that were not
@@ -1418,14 +1415,11 @@ _.extend(PackageSource.prototype, {
const anyLevelExcludes = [
/^node_modules\/$/,
/^tests\/$/,
arch === "os" ? /^client\/$/ : /^server\/$/,
...sourceReadOptions.exclude,
];
if (!global.testCommandMetadata) {
Array.prototype.push.apply(anyLevelExcludes, TEST_DIRNAME_REGEXPS);
}
const topLevelExcludes = isApp ? [
...anyLevelExcludes,
/^packages\/$/,

View File

@@ -0,0 +1,24 @@
import _ from 'underscore';
import { pathSep } from '../fs/files';
// We have two things "tests" and "app-tests".
export const TEST_FILENAME_REGEXPS = [
// "*.unit.test.*" or "*.tests.*"
/\.tests?./,
];
export const APP_TEST_FILENAME_REGEXPS = [
// "*.integration.test.*" or "*.app-tests.*"
/\.app-tests?./,
];
// Given a path to a file in an app (relative to the app root
// directory), is this file a test file?
export function isTestFilePath(path) {
const splitPath = path.split(pathSep);
// Does the filename match one of the test filename forms?
return _.any(
[...TEST_FILENAME_REGEXPS, ...APP_TEST_FILENAME_REGEXPS],
regexp => regexp.test(_.last(splitPath)));
}

View File

@@ -86,7 +86,7 @@ _.extend(ProjectContext.prototype, {
options.explicitlyAddedLocalPackageDirs;
// Used to override the directory that Meteor's build process
// writes to; used by `meteor test-app` so that you can test your
// writes to; used by `meteor test` so that you can test your
// app in parallel to writing it, with an isolated database.
self.projectLocalDir = options.projectLocalDir ||
files.pathJoin(self.projectDir, '.meteor', 'local');