diff --git a/README.md b/README.md index df1861c3e8..3f6bb3216b 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ the app: ../meteor You'll then be able to read the docs locally in your browser at -`http://localhost:3000/` +`http://localhost:3000/`. Note that if you run Meteor from a git checkout, you cannot pin apps to specific Meteor releases or run using different Meteor releases using `--release`. diff --git a/docs/client/api.html b/docs/client/api.html index 94fced62fa..6636aab62c 100644 --- a/docs/client/api.html +++ b/docs/client/api.html @@ -2263,12 +2263,8 @@ This callback fires once and is the first callback to fire. Every `created` callback with a certain template instance object in `this`, you will eventually get a `destroyed` callback for the same object. -{{#note}} - The `created` callback is not currently very useful. In a later release, the - template instance object (or something like it) will be visible from helper - functions, and `created` will be a useful way to set up values that are read - from helpers. For now, you probably just want to use `rendered`. -{{/note}} +`created` is a useful way to set up values on template instance that are +read from template helpers using `Template.instance()`. {{> autoApiBox "Template#destroyed"}} diff --git a/docs/client/packages/showdown.html b/docs/client/packages/showdown.html index 26aa44a2b8..34e2b45e4e 100644 --- a/docs/client/packages/showdown.html +++ b/docs/client/packages/showdown.html @@ -5,13 +5,18 @@ This package lets you use Markdown in your templates. It's easy: just -put your markdown inside -{{#markdown}} ... {{/markdown}} +put your markdown inside `{{dstache}}#markdown}} ... {{dstache}}/markdown}}` tags. You can still use all of the usual Meteor template features inside a Markdown block, such as `{{dstache}}#each}}`, and you still get reactivity. - +Example: + +`{{dstache}}#markdown}}I am using __markdown__.{{dstache}}/markdown}}` + +outputs + +

I am using markdown.

{{/markdown}} diff --git a/packages/tinytest/tinytest.js b/packages/tinytest/tinytest.js index b4992a4075..1423f4c2bf 100644 --- a/packages/tinytest/tinytest.js +++ b/packages/tinytest/tinytest.js @@ -522,7 +522,7 @@ _.extend(TestRun.prototype, { }, stop_at_offset); // Wait for the test to complete or time out. future.wait(); - onComplete & onComplete(); + onComplete && onComplete(); }); } else { // client diff --git a/tools/commands.js b/tools/commands.js index 3386b1d9d7..d949ed4e79 100644 --- a/tools/commands.js +++ b/tools/commands.js @@ -152,6 +152,7 @@ var runCommandOptions = { 'raw-logs': { type: Boolean }, settings: { type: String }, program: { type: String }, + test: {type: Boolean, default: false}, verbose: { type: Boolean, short: "v" }, // With --once, meteor does not re-run the project if it crashes // and does not monitor for file changes. Intentionally @@ -312,6 +313,18 @@ function doRunCommand (options) { if (options['raw-logs']) runLog.setRawLogs(true); + // Velocity testing. Sets up a DDP connection to the app process and + // runs phantomjs. + // + // NOTE: this calls process.exit() when testing is done. + if (options['test']){ + var serverUrl = "http://" + (parsedHostPort.host || "localhost") + + ":" + parsedHostPort.port; + var velocity = require('./run-velocity.js'); + velocity.runVelocity(serverUrl); + } + + var runAll = require('./run-all.js'); return runAll.run(options.appDir, { proxyPort: parsedUrl.port, diff --git a/tools/help.txt b/tools/help.txt index 06d8fd8785..84add6c744 100644 --- a/tools/help.txt +++ b/tools/help.txt @@ -51,10 +51,11 @@ Options: --mobile-server=https://example.com:443). --production Simulate production mode. Minify and bundle CSS and JS files. --raw-logs Run without parsing logs from stdout and stderr. - --settings Set optional data for Meteor.settings on the server - --release Specify the release of Meteor to use - --program The program in the app to run (Advanced) + --settings Set optional data for Meteor.settings on the server. + --release Specify the release of Meteor to use. + --program The program in the app to run (Advanced). --verbose Print all output from builds logs. + --test [Experimental] Run Velocity tests using phantomjs and exit. >>> debug Run the project, but suspend the server process for debugging. diff --git a/tools/run-velocity.js b/tools/run-velocity.js new file mode 100644 index 0000000000..1c73d82861 --- /dev/null +++ b/tools/run-velocity.js @@ -0,0 +1,134 @@ +var Console = require('./console.js').Console; +var uniload = require('./uniload.js'); + +var phantomjs = require('phantomjs'); +var child_process = require('child_process'); +var _ = require('underscore'); + +// XXX this could really use a self-test! + +// XXX would be nice be nice if this didn't have to be in core. Perhaps +// at some point we'll have an API for packages to register commands in +// the tool. + +// 1. Establish a DDP connection to Meteor +// 2. Subscribe to the Velocity subscriptions that tell us +// which tests pass/fail and when all tests have completed. +// 3. Open the app server with PhantomJS to run client side tests. +// 4. Print the results and exit with the appropriate exit code. +var runVelocity = function (url) { + var unipackages = uniload.load({ + packages: [ 'ddp'] + }); + var DDP = unipackages.ddp.DDP; + + // XXX maybe a startup message so users know the tests are running. + + var ddpConnection = DDP.connect(url); + + var interval = setInterval(function () { + if (ddpConnection.status().status === "connected") { + clearInterval(interval); + + ddpConnection.subscribe("VelocityTestReports", { + onError: function () { + Console.stderr.write("failed to subscribe to VelocityTestReports " + + "subscription"); + // XXX tell user to add velocity:core + // XXX these also fire if the user turns on autopublish + }, onReady: function () { + this.connection.registerStore("velocityTestReports", { + update: function (msg) { + if (msg.msg === "added") { + var testDesc = msg.fields.framework + " : " + + msg.fields.ancestors.join(":") + " => " + msg.fields.name; + if (msg.fields.result === "passed") { + console.log("PASSED", testDesc); + } else if (msg.fields.result === "failed") { + console.error("FAILED", testDesc); + console.log(msg.fields.failureStackTrace); + } + } + } + }); + } + }); + + var reports = {}; + function updateReport(msg) { + var report = reports[msg.id]; + if (! report) { + reports[msg.id] = msg.fields; + } else { + _.extend(report, msg.fields); + } + } + var aggregateResult = null; + var isFinished = false; + ddpConnection.subscribe("VelocityAggregateReports", { + onError: function () { + Console.stderr.write("failed to subscribe to " + + "VelocityAggregateReports subscription"); + }, onReady: function () { + this.connection.registerStore("velocityAggregateReports", { + update: function (msg) { + if (msg.msg === "added" || msg.msg === "changed") { + updateReport(msg); + var report = reports[msg.id]; + + if (report.name === "aggregateResult") { + aggregateResult = report.result; + } + + if (report.name === "aggregateComplete" && + report.result === "completed") { + setTimeout(function () { + if (aggregateResult === "passed") { + console.log("TESTS RAN SUCCESSFULLY"); + // XXX XXX this is not great. We shouldn't be + // exiting from deep within code like this. Better + // would be to integrate with run --once, and + // signal the inner process to exit cleanly on + // test completion. + process.exit(0); + } + if (aggregateResult === "failed") { + console.log("FAILURE"); + process.exit(1); + } + }, 2000); + } + } + } + }); + } + }); + + function visitWithPhantom (url) { + var phantomScript = "require('webpage').create().open('" + url + "');"; + child_process.execFile( + '/bin/bash', + ['-c', + ("exec " + phantomjs.path + " /dev/stdin <<'END'\n" + + phantomScript + "END\n")]); + } + + ddpConnection.subscribe("VelocityMirrors", { + onError: function (err) { + Console.stderr.write("failed to subscribe to VelocityMirrors " + + "subscription", err); + }, onReady: function () { + this.connection.registerStore("velocityMirrors", { + update: function (msg) { + if (msg.msg === "added") { + visitWithPhantom(msg.fields.rootUrl); + } + } + }); + } + }); + } + }, 2000); +}; + +exports.runVelocity = runVelocity;