mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
261 lines
10 KiB
JavaScript
261 lines
10 KiB
JavaScript
var _ = require('underscore');
|
|
var selftest = require('../selftest.js');
|
|
var files = require('../files.js');
|
|
|
|
var Sandbox = selftest.Sandbox;
|
|
|
|
var MONGO_LISTENING =
|
|
{ stdout: " [initandlisten] waiting for connections on port" };
|
|
|
|
function startRun(sandbox) {
|
|
var run = sandbox.run();
|
|
run.match("myapp");
|
|
run.match("proxy");
|
|
run.tellMongo(MONGO_LISTENING);
|
|
run.match("MongoDB");
|
|
return run;
|
|
};
|
|
|
|
// Tests the actual cache logic used by coffeescript and less.
|
|
selftest.define("compiler plugin caching - coffee/less", function () {
|
|
var s = new Sandbox({ fakeMongo: true });
|
|
|
|
// Create an app that uses coffeescript and less.
|
|
s.createApp("myapp", "coffee-and-less");
|
|
s.cd("myapp");
|
|
// Ask them to print out when they build a file (instead of using it from the
|
|
// cache) as well as when they load cache from disk.
|
|
s.set("METEOR_TEST_PRINT_CACHE_DEBUG", "t");
|
|
var run = startRun(s);
|
|
|
|
// First program built (server or web.browser) compiles everything.
|
|
run.match('Ran coffee.compile (#1) on: ' + JSON.stringify(
|
|
['/f1.coffee', '/f2.coffee', '/f3.coffee', '/packages/local-pack/p.coffee']
|
|
));
|
|
run.match('Ran less.render (#1) on: ' + JSON.stringify(
|
|
["/subdir/nested-root.main.less", "/top.main.less"]));
|
|
// Second program doesn't need to compile anything because compilation works
|
|
// the same on both programs. (Note that there is no less.render execution in
|
|
// the second program, because it has archMatching: 'web'. We'll see this
|
|
// more clearly when the next call later is "#2" --- we didn't miss a call!)
|
|
run.match("Ran coffee.compile (#2) on: []");
|
|
// App prints this:
|
|
run.match("Coffeescript X is 2 Y is 1 FromPackage is 4");
|
|
|
|
// Check that the CSS is what we expect.
|
|
var checkCSS = selftest.markStack(function (borderStyleMap) {
|
|
var builtBrowserProgramDir = files.pathJoin(
|
|
s.cwd, '.meteor', 'local', 'build', 'programs', 'web.browser');
|
|
var cssFile = _.find(
|
|
files.readdir(
|
|
files.pathJoin(s.cwd, '.meteor/local/build/programs/web.browser')),
|
|
function (path) {
|
|
return path.match(/\.css$/);
|
|
}
|
|
);
|
|
selftest.expectTrue(cssFile);
|
|
var actual = s.read(
|
|
files.pathJoin('.meteor/local/build/programs/web.browser', cssFile));
|
|
actual = actual.replace(/\s+/g, ' '); // simplify whitespace
|
|
var expected = _.map(borderStyleMap, function (style, className) {
|
|
return '.' + className + " { border-style: " + style + "; }";
|
|
}).join(' ');
|
|
selftest.expectEqual(actual, expected);
|
|
});
|
|
var expectedBorderStyles = {
|
|
el0: "dashed", el1: "dotted", el2: "solid", el3: "groove", el4: "ridge"};
|
|
checkCSS(expectedBorderStyles);
|
|
|
|
s.write("f2.coffee", "share.Y = 'Y is 3'\n");
|
|
// Only recompiles f2.
|
|
run.match('Ran coffee.compile (#3) on: ["/f2.coffee"]');
|
|
run.match('Ran less.render (#2) on: []');
|
|
// And other program doesn't even need to do f2.
|
|
run.match("Ran coffee.compile (#4) on: []");
|
|
// Program prints this:
|
|
run.match("Coffeescript X is 2 Y is 3 FromPackage is 4");
|
|
|
|
// Force a rebuild of the local package without actually changing the
|
|
// coffeescript file in it. This should not require us to coffee.compile
|
|
// anything (for either program).
|
|
s.append("packages/local-pack/package.js", "\n// foo\n");
|
|
run.match("Ran coffee.compile (#5) on: []");
|
|
run.match('Ran less.render (#3) on: []');
|
|
run.match("Ran coffee.compile (#6) on: []");
|
|
run.match("Coffeescript X is 2 Y is 3 FromPackage is 4");
|
|
|
|
// But writing to the actual source file in the local package should
|
|
// recompile.
|
|
s.write("packages/local-pack/p.coffee", "FromPackage = 'FromPackage is 5'");
|
|
run.match('Ran coffee.compile (#7) on: ["/packages/local-pack/p.coffee"]');
|
|
run.match('Ran less.render (#4) on: []');
|
|
run.match('Ran coffee.compile (#8) on: []');
|
|
run.match("Coffeescript X is 2 Y is 3 FromPackage is 5");
|
|
|
|
// Writing to a single less file only re-renders the root that depends on it.
|
|
s.write('packages/local-pack/p.less', '@el4-style: inset;\n');
|
|
expectedBorderStyles.el4 = 'inset';
|
|
run.match('Ran coffee.compile (#9) on: []');
|
|
run.match('Ran less.render (#5) on: ["/top.main.less"]');
|
|
// Note that since this was a client-only change, we're smart enough to not
|
|
// rebuild the server at all. So the next coffee.compile will be #10.
|
|
run.match("Client modified -- refreshing");
|
|
checkCSS(expectedBorderStyles);
|
|
|
|
// This works for changing a root too.
|
|
s.write('subdir/nested-root.main.less', '.el0 { border-style: double; }\n');
|
|
expectedBorderStyles.el0 = 'double';
|
|
// Only #10, not #11, because client-only changes don't rebuild the server!
|
|
run.match('Ran coffee.compile (#10) on: []');
|
|
run.match('Ran less.render (#6) on: ["/subdir/nested-root.main.less"]');
|
|
run.match("Client modified -- refreshing");
|
|
checkCSS(expectedBorderStyles);
|
|
|
|
// Adding a new root works too.
|
|
s.write('yet-another-root.main.less', '.el6 { border-style: solid; }\n');
|
|
expectedBorderStyles.el6 = 'solid';
|
|
run.match('Ran coffee.compile (#11) on: []');
|
|
run.match('Ran less.render (#7) on: ["/yet-another-root.main.less"]');
|
|
run.match("Client modified -- refreshing");
|
|
checkCSS(expectedBorderStyles);
|
|
|
|
// We never should have loaded cache from disk, since we only made
|
|
// each compiler once and there was no cache.json at this point.
|
|
run.forbid('Loaded coffeescript cache');
|
|
run.forbid('Loaded less cache');
|
|
|
|
// Kill the run. Change one coffee file and one less file and re-run.
|
|
run.stop();
|
|
s.write("f2.coffee", "share.Y = 'Y is edited'\n");
|
|
s.write('packages/local-pack/p.less', '@el4-style: double;\n');
|
|
expectedBorderStyles.el4 = 'double';
|
|
run = startRun(s);
|
|
|
|
// This time there's a cache to load!
|
|
run.match('Loaded coffeescript cache');
|
|
run.match('Loaded less cache');
|
|
// And we only need to re-compiler the changed file, even though we restarted.
|
|
run.match('Ran coffee.compile (#1) on: ["/f2.coffee"]');
|
|
run.match('Ran less.render (#1) on: ["/top.main.less"]');
|
|
run.match('Ran coffee.compile (#2) on: []');
|
|
|
|
run.match('Coffeescript X is 2 Y is edited FromPackage is 5');
|
|
checkCSS(expectedBorderStyles);
|
|
|
|
s.write('bad-import.main.less', '@import "/foo/bad.less";\n');
|
|
run.match('Errors prevented startup');
|
|
run.match('bad-import.main.less:1: Unknown import: /foo/bad.less');
|
|
run.match('Waiting for file change');
|
|
|
|
run.stop();
|
|
});
|
|
|
|
// Tests that rebuilding a compiler plugin re-instantiates the source processor,
|
|
// but other changes don't.
|
|
selftest.define("compiler plugin caching - local plugin", function () {
|
|
var s = new Sandbox({ fakeMongo: true });
|
|
|
|
s.createApp("myapp", "local-compiler-plugin");
|
|
s.cd("myapp");
|
|
|
|
var run = startRun(s);
|
|
|
|
// The compiler gets used the first time...
|
|
run.match("PrintmeCompiler invocation 1");
|
|
// ... and the program runs the generated code.
|
|
run.match("PMC: Print out bar");
|
|
run.match("PMC: Print out foo");
|
|
|
|
s.write("quux.printme", "And print out quux");
|
|
// PrintmeCompiler gets reused.
|
|
run.match("PrintmeCompiler invocation 2");
|
|
// And the right output prints out
|
|
run.match("PMC: Print out bar");
|
|
run.match("PMC: Print out foo");
|
|
run.match("PMC: And print out quux");
|
|
|
|
// Restart meteor; see that the disk cache gets used.
|
|
run.stop();
|
|
run = startRun(s);
|
|
// Disk cache gets us up to 3.
|
|
run.match("PrintmeCompiler invocation 3");
|
|
// And the right output prints out
|
|
run.match("PMC: Print out bar");
|
|
run.match("PMC: Print out foo");
|
|
run.match("PMC: And print out quux");
|
|
|
|
// Edit the compiler itself.
|
|
s.write('packages/local-plugin/plugin.js',
|
|
s.read('packages/local-plugin/plugin.js').replace(/PMC/, 'pmc'));
|
|
// New PrintmeCompiler object, and empty disk cache dir.
|
|
run.match("PrintmeCompiler invocation 1");
|
|
// And the right output prints out (lower case now)
|
|
run.match("pmc: Print out bar");
|
|
run.match("pmc: Print out foo");
|
|
run.match("pmc: And print out quux");
|
|
|
|
run.stop();
|
|
});
|
|
|
|
// Test error on duplicate compiler plugins.
|
|
selftest.define("compiler plugins - duplicate extension", () => {
|
|
const s = new Sandbox({ fakeMongo: true });
|
|
|
|
s.createApp("myapp", "duplicate-compiler-extensions");
|
|
s.cd("myapp");
|
|
|
|
let run = startRun(s);
|
|
run.match('Errors prevented startup');
|
|
run.match('conflict: two packages');
|
|
run.match('trying to handle *.myext');
|
|
|
|
// Fix it by changing one extension.
|
|
s.write('packages/local-plugin/plugin.js',
|
|
s.read('packages/local-plugin/plugin.js').replace('myext', 'xext'));
|
|
run.match('Modified -- restarting');
|
|
|
|
run.stop();
|
|
});
|
|
|
|
// Test error when a source file no longer has an active plugin.
|
|
selftest.define("compiler plugins - inactive source", () => {
|
|
const s = new Sandbox({ fakeMongo: true });
|
|
|
|
// This app depends on the published package 'glasser:uses-sourcish', and
|
|
// contains a local package 'local-plugin'.
|
|
//
|
|
// glasser:uses-sourcish depends on local-plugin and contains a file
|
|
// 'foo.sourcish'. When glasser:uses-sourcish@0.0.1 was published, a local
|
|
// copy of 'local-plugin' had a plugin which called registerCompiler for the
|
|
// extension '*.sourcish', and so 'foo.sourcish' is in the published isopack
|
|
// as a source file. However, the copy of 'local-plugin' currently in the test
|
|
// app contains no plugins. So we hit this weird error.
|
|
s.createApp('myapp', 'uses-published-package-with-inactive-source');
|
|
s.cd('myapp');
|
|
|
|
let run = startRun(s);
|
|
run.match('Errors prevented startup');
|
|
run.match('no plugin found for foo.sourcish in glasser:use-sourcish');
|
|
run.match('none is now');
|
|
|
|
run.stop();
|
|
});
|
|
|
|
// Test error when the registerCompiler callback throws.
|
|
selftest.define("compiler plugins - compiler throws", () => {
|
|
const s = new Sandbox({ fakeMongo: true });
|
|
|
|
s.createApp('myapp', 'compiler-plugin-throws-on-instantiate');
|
|
s.cd('myapp');
|
|
|
|
const run = s.run('add', 'local-plugin');
|
|
run.matchErr('Errors while adding packages');
|
|
run.matchErr('While building package local-plugin');
|
|
// XXX This is wrong! The path on disk is packages/local-plugin/plugin.js, but
|
|
// at some point we switched to the servePath which is based on the *plugin*'s
|
|
// "package" name.
|
|
run.matchErr('packages/compilePrintme/plugin.js:5:1: Error in my ' +
|
|
'registerCompiler callback!');
|
|
run.expectExit(1);
|
|
});
|