From 8ead7e0624c839798a57afaa8c2aa6397b1c0749 Mon Sep 17 00:00:00 2001 From: Cameron Fischer Date: Sun, 20 Nov 2022 12:54:18 -0500 Subject: [PATCH] Jasmine command (#6944) --- bin/test.sh | 1 + editions/test/tiddlywiki.info | 3 +- plugins/tiddlywiki/jasmine/command.js | 33 ++++++++++++++++ plugins/tiddlywiki/jasmine/help.tid | 24 ++++++++++++ plugins/tiddlywiki/jasmine/jasmine-plugin.js | 40 +++++++++++--------- plugins/tiddlywiki/jasmine/readme.tid | 32 +++++++++++++++- plugins/tiddlywiki/jasmine/startup.js | 37 ++++++++++++++++++ 7 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 plugins/tiddlywiki/jasmine/command.js create mode 100644 plugins/tiddlywiki/jasmine/help.tid create mode 100644 plugins/tiddlywiki/jasmine/startup.js diff --git a/bin/test.sh b/bin/test.sh index 2de66b1fd3..61c7b71434 100755 --- a/bin/test.sh +++ b/bin/test.sh @@ -9,6 +9,7 @@ node ./tiddlywiki.js \ --verbose \ --version \ --rendertiddler $:/core/save/all test.html text/plain \ + --test \ || exit 1 echo To run the tests in a browser, open "editions/test/output/test.html" diff --git a/editions/test/tiddlywiki.info b/editions/test/tiddlywiki.info index c53b289ceb..afb9c0514c 100644 --- a/editions/test/tiddlywiki.info +++ b/editions/test/tiddlywiki.info @@ -9,6 +9,7 @@ ], "build": { "index": [ - "--rendertiddler","$:/core/save/all","test.html","text/plain"] + "--rendertiddler","$:/core/save/all","test.html","text/plain", + "--test"] } } \ No newline at end of file diff --git a/plugins/tiddlywiki/jasmine/command.js b/plugins/tiddlywiki/jasmine/command.js new file mode 100644 index 0000000000..fe7e623345 --- /dev/null +++ b/plugins/tiddlywiki/jasmine/command.js @@ -0,0 +1,33 @@ +/*\ +title: $:/plugins/tiddlywiki/jasmine/command.js +type: application/javascript +module-type: command + +The command which executes jasmine on the command line for TiddlyWiki5 + +\*/ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var jasmine = require("./jasmine-plugin.js"); + +exports.info = { + name: "test", + synchronous: false, + namedParameterMode: true +}; + +var Command = function(params,commander,callback) { + this.params = params; + this.commander = commander; + this.callback = callback; +}; + +Command.prototype.execute = function() { + var specFilter = this.params.spec; + jasmine.runTests(this.callback,specFilter); +}; + +exports.Command = Command; diff --git a/plugins/tiddlywiki/jasmine/help.tid b/plugins/tiddlywiki/jasmine/help.tid new file mode 100644 index 0000000000..a0580741b1 --- /dev/null +++ b/plugins/tiddlywiki/jasmine/help.tid @@ -0,0 +1,24 @@ +title: $:/language/Help/test +description: Run the jasmine test suite + +This runs all of the tests in tiddlers tagged with `$:/tags/test-spec`. + +``` +--test [spec=] +``` + +''spec'' - optional regular expression to run only specific suites or tests. It will be matched against the full name of every test to see whether to run it. The full name of a test is its assigned name prepended with the names of all containing suites. For instance, to run only the following test: + +``` +describe("Framework") { it("handles edgecases") { ... } } +``` + +You might use a specFilter like `"^Framework handles edgecases$"` to match the full name exactly, or more simply `"edgecases"`, though this might run other tests with "edgecases" in their name. You could also run all tests in that suite with `"^Framework"`. + +If any tests fail or are skipped, all following commands are ignored. If you have any commands which must be executed regardless of test results, execute them first. + +A common usage is to run the tests on the console after creating a Tiddlywiki file which will run the tests on the browser. + +``` +tiddlywiki --rendertiddler $:/core/save/all test.html text/plain --test +``` diff --git a/plugins/tiddlywiki/jasmine/jasmine-plugin.js b/plugins/tiddlywiki/jasmine/jasmine-plugin.js index 3377ebfbdc..3ec7998a2c 100644 --- a/plugins/tiddlywiki/jasmine/jasmine-plugin.js +++ b/plugins/tiddlywiki/jasmine/jasmine-plugin.js @@ -1,7 +1,7 @@ /*\ title: $:/plugins/tiddlywiki/jasmine/jasmine-plugin.js type: application/javascript -module-type: startup +module-type: library The main module of the Jasmine test plugin for TiddlyWiki5 @@ -13,19 +13,14 @@ The main module of the Jasmine test plugin for TiddlyWiki5 "use strict"; var TEST_TIDDLER_FILTER = "[all[tiddlers+shadows]type[application/javascript]tag[$:/tags/test-spec]]"; +var TESTS_DONE = false; -exports.name = "jasmine"; -// Ensure this startup module is executed in the right order. -// In Node.js, Jasmine calls `process.exit()` with a non-zero exit code if there's -// any failed tests. Because of that, we want to make sure all critical -// startup modules are run before this one. -// * The "commands" module handles the --rendertiddler command-line flag, -// which is typically given in order to export an HTML file that can be opened with -// a browser to run tests. -exports.after = $tw.node ? ["commands"] : []; +exports.testsWereRun = function() { + return TESTS_DONE; +}; /* -Startup function for running tests +function for running tests Below, paths like jasmine-core/jasmine.js refer to files in the 'jasmine-core' npm package, whose repository is https://github.com/jasmine/jasmine. @@ -34,7 +29,8 @@ repository is https://github.com/jasmine/jasmine-npm. They're all locally checked into the `./files` directory. */ -exports.startup = function() { + +exports.runTests = function(callback,specFilter) { // Set up a shared context object. var context = { console: console, @@ -63,6 +59,10 @@ exports.startup = function() { // is executed, so we use the `context` object instead. context.global = $tw.browser ? window : context; + // We set this early rather than at the end for simplicity. The browser + // and node.js environments don't end the same way. + TESTS_DONE = true; + function evalInContext(title) { var code = $tw.wiki.getTiddlerText(title,""); var _exports = {}; @@ -123,7 +123,15 @@ exports.startup = function() { path: "$:/plugins/tiddlywiki/jasmine/jasmine-core/jasmine-core" }; // 'jasmine/jasmine.js' references `process.exit`, among other properties - context.process = process; + // It will call 'exit' after it's done, which gives us an + // opportunity to resynchronize and finish any following commands. + context.process = Object.create(process); + context.process.exit = function(code) { + // If jasmine's exit code is non-zero, tests failed. Abort any + // further commands. If they're important, they could have come + // before the testing suite. + callback(code ? "Tests failed with code " + code : undefined); + }; var NodeJasmine = evalInContext("$:/plugins/tiddlywiki/jasmine/jasmine/jasmine.js"); nodeJasmineWrapper = new NodeJasmine({jasmineCore: jasmineCore}); @@ -135,13 +143,11 @@ exports.startup = function() { context = $tw.utils.extend({},jasmineInterface,context); // Iterate through all the test modules var tests = $tw.wiki.filterTiddlers(TEST_TIDDLER_FILTER); - $tw.utils.each(tests,function(title) { - evalInContext(title); - }); + $tw.utils.each(tests,evalInContext); // In a browser environment, jasmine-core/boot.js calls `execute()` for us. // In Node.js, we call it manually. if(!$tw.browser) { - nodeJasmineWrapper.execute(); + nodeJasmineWrapper.execute(null,specFilter); } }; diff --git a/plugins/tiddlywiki/jasmine/readme.tid b/plugins/tiddlywiki/jasmine/readme.tid index 3411d3cb03..878a756d34 100644 --- a/plugins/tiddlywiki/jasmine/readme.tid +++ b/plugins/tiddlywiki/jasmine/readme.tid @@ -1,5 +1,35 @@ title: $:/plugins/tiddlywiki/jasmine/readme -This plugin provides a framework for running tests in the browser and under Node.js. It is based on [[Jasmine|https://jasmine.github.io/]] test framework. +This plugin provides a framework for running tests in the browser and under Node.js. It is based on [[Jasmine|https://jasmine.github.io/]] test framework. On Tiddlywiki, it runs tests in all javascript tiddlers tagged with <>. [[Source code|https://github.com/Jermolene/TiddlyWiki5/blob/master/plugins/tiddlywiki/jasmine]] + +!! Usage on Node.js + +On the command line, type `tiddlywiki --test`. + +Alternatively, you can set up a build task for jasmine by including the following in your tiddlywiki.info file: + +``` +{ + ... + "build": { + ... + "test": ["--test"] + } +} +``` + +You could then run tests by typing `tiddlywiki --build test` or just `tiddlywiki --build`. The advantage to this is it allows you to include other commands to run as well. See `tiddlywiki --help test` for more information. + +This will run the tests and produce a test file in your output directory. + +``` + "test": [ + "--test", + "--rendertiddler","$:/core/save/all","test.html","text/plain"] +``` + +!! Usage on a browser + +Once you've constructed a Tiddlywiki file using a command like the one above, you can run the tests simply by opening it. Tests run automatically, and the results will be at the bottom of the window. diff --git a/plugins/tiddlywiki/jasmine/startup.js b/plugins/tiddlywiki/jasmine/startup.js new file mode 100644 index 0000000000..46f9ef4705 --- /dev/null +++ b/plugins/tiddlywiki/jasmine/startup.js @@ -0,0 +1,37 @@ +/*\ +title: $:/plugins/tiddlywiki/jasmine/startup.js +type: application/javascript +module-type: startup + +The main module of the Jasmine test plugin for TiddlyWiki5 + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: true */ +"use strict"; + +var jasmine = require("./jasmine-plugin.js"); + +exports.name = "jasmine"; + +if($tw.browser) { + // Jasmine is run automatically on the browser, so always add it here. + exports.startup = jasmine.runTests; +} else { + // However, if we're on node.js, the tests are explciitly run with the + // --test command. This didn't used to be the case, so if they're + // not, we'll issue a small notice to cue users in to the change + // BTW, this notice probably won't be needed forever. It was installed + // Sept 2022. If it's been four years, this notice can probably come out. + exports.startup = function() { + if(!jasmine.testsWereRun()) { + process.stdout.write("Jasmine: no \"--test\" command given, so skipping tests\n"); + } + } + // We make this check after the commands are run. + exports.after = ["commands"]; +} + +})();