From f9df4f07416e0945d09398bae0b6d719a97a7194 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Thu, 23 May 2024 16:28:08 +0100 Subject: [PATCH 01/14] Plugin tests should only apply to core plugins Hi @pmario could you kindly try this? Fixes #8207 --- core/modules/utils/repository.js | 11 +++++++---- editions/test/tiddlers/tests/test-plugins.js | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/modules/utils/repository.js b/core/modules/utils/repository.js index 643f3f483..3e7cb664a 100644 --- a/core/modules/utils/repository.js +++ b/core/modules/utils/repository.js @@ -14,8 +14,11 @@ Utilities for working with the TiddlyWiki repository file structure /* Get an object containing all the plugins as a hashmap by title of the JSON representation of the plugin +Options: + +ignoreEnvironmentVariables: defaults to false */ -exports.getAllPlugins = function() { +exports.getAllPlugins = function(options) { var fs = require("fs"), path = require("path"), tiddlers = {}; @@ -39,9 +42,9 @@ exports.getAllPlugins = function() { } } }; - $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,$tw.config.pluginsEnvVar),collectPublisherPlugins); - $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,$tw.config.themesEnvVar),collectPublisherPlugins); - $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,$tw.config.languagesEnvVar),collectPlugins); + $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,options.ignoreEnvironmentVariables ? "" : $tw.config.pluginsEnvVar),collectPublisherPlugins); + $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,options.ignoreEnvironmentVariables ? "" : $tw.config.themesEnvVar),collectPublisherPlugins); + $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,options.ignoreEnvironmentVariables ? "" : $tw.config.languagesEnvVar),collectPlugins); return tiddlers; }; diff --git a/editions/test/tiddlers/tests/test-plugins.js b/editions/test/tiddlers/tests/test-plugins.js index 29ba4a829..663192a9c 100644 --- a/editions/test/tiddlers/tests/test-plugins.js +++ b/editions/test/tiddlers/tests/test-plugins.js @@ -17,7 +17,7 @@ if($tw.node) { describe("Plugin tests", function() { // Get all the plugins as a hashmap by title of a JSON string with the plugin content - var tiddlers = $tw.utils.getAllPlugins(); + var tiddlers = $tw.utils.getAllPlugins({ignoreEnvironmentVariables: true}); // console.log(JSON.stringify(Object.keys(tiddlers),null,4)); describe("every plugin should have the required standard fields", function() { var titles = Object.keys(tiddlers); From 970f829c83f296404d39c252348e09d4cd7a844b Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Thu, 23 May 2024 16:34:24 +0100 Subject: [PATCH 02/14] Fix bug in f9df4f07416e0945d09398bae0b6d719a97a7194 --- core/modules/utils/repository.js | 1 + 1 file changed, 1 insertion(+) diff --git a/core/modules/utils/repository.js b/core/modules/utils/repository.js index 3e7cb664a..be10d7928 100644 --- a/core/modules/utils/repository.js +++ b/core/modules/utils/repository.js @@ -19,6 +19,7 @@ Options: ignoreEnvironmentVariables: defaults to false */ exports.getAllPlugins = function(options) { + options = options || {}; var fs = require("fs"), path = require("path"), tiddlers = {}; From 18d23048daae971f62bd0c3f53224172f977790b Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Thu, 23 May 2024 16:47:28 +0100 Subject: [PATCH 03/14] Improve plugin test implementation --- boot/boot.js | 15 +++++++++------ core/modules/utils/repository.js | 6 +++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index d993499b6..dae5cb28e 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -2188,13 +2188,16 @@ Returns an array of search paths */ $tw.getLibraryItemSearchPaths = function(libraryPath,envVar) { var pluginPaths = [path.resolve($tw.boot.corePath,libraryPath)], + env; + if(envVar) { env = process.env[envVar]; - if(env) { - env.split(path.delimiter).map(function(item) { - if(item) { - pluginPaths.push(item); - } - }); + if(env) { + env.split(path.delimiter).map(function(item) { + if(item) { + pluginPaths.push(item); + } + }); + } } return pluginPaths; }; diff --git a/core/modules/utils/repository.js b/core/modules/utils/repository.js index be10d7928..3aeb4d25a 100644 --- a/core/modules/utils/repository.js +++ b/core/modules/utils/repository.js @@ -43,9 +43,9 @@ exports.getAllPlugins = function(options) { } } }; - $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,options.ignoreEnvironmentVariables ? "" : $tw.config.pluginsEnvVar),collectPublisherPlugins); - $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,options.ignoreEnvironmentVariables ? "" : $tw.config.themesEnvVar),collectPublisherPlugins); - $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,options.ignoreEnvironmentVariables ? "" : $tw.config.languagesEnvVar),collectPlugins); + $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.pluginsPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.pluginsEnvVar),collectPublisherPlugins); + $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.themesPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.themesEnvVar),collectPublisherPlugins); + $tw.utils.each($tw.getLibraryItemSearchPaths($tw.config.languagesPath,options.ignoreEnvironmentVariables ? undefined : $tw.config.languagesEnvVar),collectPlugins); return tiddlers; }; From 074d35c3889616ac4b447de568ffd83d6f20f304 Mon Sep 17 00:00:00 2001 From: Mario Pietsch Date: Thu, 23 May 2024 19:13:52 +0200 Subject: [PATCH 04/14] Make the linter happy (#8210) --- boot/boot.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index dae5cb28e..ea20c83fd 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -142,15 +142,15 @@ $tw.utils.each = function(object,callback) { var next,f,length; if(object) { if(Object.prototype.toString.call(object) == "[object Array]") { - for (f=0, length=object.length; f Date: Sat, 25 May 2024 05:56:19 -0400 Subject: [PATCH 05/14] More robust infinite recursion handling with custom exception (#7882) * Introduced preliminary idea for infinite recurse exception * Better handling of infinite recursion But it could be better still... * the TransclusionError is a proper error Moved the magic number to be on the error's class. Not sure if that's a great idea. * Fixed minor minor issue that came up in conflict The minor fix to the jasmine regexp that escaped a '+' somehow broke some random test. --- core/modules/utils/errors.js | 23 +++++++++++ core/modules/widgets/transclude.js | 25 ++++++++++- core/modules/widgets/widget.js | 9 +--- .../tests/data/transclude/Recursion.tid | 3 +- editions/test/tiddlers/tests/test-widget.js | 41 +++++++++++++++++++ 5 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 core/modules/utils/errors.js diff --git a/core/modules/utils/errors.js b/core/modules/utils/errors.js new file mode 100644 index 000000000..fac4b3fa7 --- /dev/null +++ b/core/modules/utils/errors.js @@ -0,0 +1,23 @@ +/*\ +title: $:/core/modules/utils/errors.js +type: application/javascript +module-type: utils + +Custom errors for TiddlyWiki. + +\*/ +(function(){ + +function TranscludeRecursionError() { + Error.apply(this,arguments); + this.signatures = Object.create(null); +}; + +/* Maximum permitted depth of the widget tree for recursion detection */ +TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH = 1000; + +TranscludeRecursionError.prototype = Object.create(Error); + +exports.TranscludeRecursionError = TranscludeRecursionError; + +})(); diff --git a/core/modules/widgets/transclude.js b/core/modules/widgets/transclude.js index d30ab1fa7..35b4941bd 100755 --- a/core/modules/widgets/transclude.js +++ b/core/modules/widgets/transclude.js @@ -30,7 +30,30 @@ TranscludeWidget.prototype.render = function(parent,nextSibling) { this.parentDomNode = parent; this.computeAttributes(); this.execute(); - this.renderChildren(parent,nextSibling); + try { + this.renderChildren(parent,nextSibling); + } catch(error) { + if(error instanceof $tw.utils.TranscludeRecursionError) { + // We were infinite looping. + // We need to try and abort as much of the loop as we can, so we will keep "throwing" upward until we find a transclusion that has a different signature. + // Hopefully that will land us just outside where the loop began. That's where we want to issue an error. + // Rendering widgets beneath this point may result in a freezing browser if they explode exponentially. + var transcludeSignature = this.getVariable("transclusion"); + if(this.getAncestorCount() > $tw.utils.TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH - 50) { + // For the first fifty transcludes we climb up, we simply collect signatures. + // We're assuming that those first 50 will likely include all transcludes involved in the loop. + error.signatures[transcludeSignature] = true; + } else if(!error.signatures[transcludeSignature]) { + // Now that we're past the first 50, let's look for the first signature that wasn't in the loop. That'll be where we print the error and resume rendering. + this.children = [this.makeChildWidget({type: "error", attributes: { + "$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")} + }})]; + this.renderChildren(parent,nextSibling); + return; + } + } + throw error; + } }; /* diff --git a/core/modules/widgets/widget.js b/core/modules/widgets/widget.js index 69f63a684..cb8e5e881 100755 --- a/core/modules/widgets/widget.js +++ b/core/modules/widgets/widget.js @@ -12,9 +12,6 @@ Widget base class /*global $tw: false */ "use strict"; -/* Maximum permitted depth of the widget tree for recursion detection */ -var MAX_WIDGET_TREE_DEPTH = 1000; - /* Create a widget object for a parse tree node parseTreeNode: reference to the parse tree node to be rendered @@ -494,10 +491,8 @@ Widget.prototype.makeChildWidgets = function(parseTreeNodes,options) { this.children = []; var self = this; // Check for too much recursion - if(this.getAncestorCount() > MAX_WIDGET_TREE_DEPTH) { - this.children.push(this.makeChildWidget({type: "error", attributes: { - "$message": {type: "string", value: $tw.language.getString("Error/RecursiveTransclusion")} - }})); + if(this.getAncestorCount() > $tw.utils.TranscludeRecursionError.MAX_WIDGET_TREE_DEPTH) { + throw new $tw.utils.TranscludeRecursionError(); } else { // Create set variable widgets for each variable $tw.utils.each(options.variables,function(value,name) { diff --git a/editions/test/tiddlers/tests/data/transclude/Recursion.tid b/editions/test/tiddlers/tests/data/transclude/Recursion.tid index d75e671eb..b834f3765 100644 --- a/editions/test/tiddlers/tests/data/transclude/Recursion.tid +++ b/editions/test/tiddlers/tests/data/transclude/Recursion.tid @@ -7,7 +7,8 @@ title: Output \whitespace trim <$transclude $tiddler="Output"/> + + title: ExpectedResult -

Recursive transclusion error in transclude widget

\ No newline at end of file +Recursive transclusion error in transclude widget \ No newline at end of file diff --git a/editions/test/tiddlers/tests/test-widget.js b/editions/test/tiddlers/tests/test-widget.js index 0d1351f31..1c7665a53 100755 --- a/editions/test/tiddlers/tests/test-widget.js +++ b/editions/test/tiddlers/tests/test-widget.js @@ -160,6 +160,47 @@ describe("Widget module", function() { expect(wrapper.innerHTML).toBe("Recursive transclusion error in transclude widget"); }); + it("should handle single-tiddler recursion with branching nodes", function() { + var wiki = new $tw.Wiki(); + // Add a tiddler + wiki.addTiddlers([ + {title: "TiddlerOne", text: "<$tiddler tiddler='TiddlerOne'><$transclude /> <$transclude />"}, + ]); + // Test parse tree + var parseTreeNode = {type: "widget", children: [ + {type: "transclude", attributes: { + "tiddler": {type: "string", value: "TiddlerOne"} + }} + ]}; + // Construct the widget node + var widgetNode = createWidgetNode(parseTreeNode,wiki); + // Render the widget node to the DOM + var wrapper = renderWidgetNode(widgetNode); + // Test the rendering + expect(wrapper.innerHTML).toBe("Recursive transclusion error in transclude widget Recursive transclusion error in transclude widget"); + }); + + it("should handle many-tiddler recursion with branching nodes", function() { + var wiki = new $tw.Wiki(); + // Add a tiddler + wiki.addTiddlers([ + {title: "TiddlerOne", text: "<$transclude tiddler='TiddlerTwo'/> <$transclude tiddler='TiddlerTwo'/>"}, + {title: "TiddlerTwo", text: "<$transclude tiddler='TiddlerOne'/>"} + ]); + // Test parse tree + var parseTreeNode = {type: "widget", children: [ + {type: "transclude", attributes: { + "tiddler": {type: "string", value: "TiddlerOne"} + }} + ]}; + // Construct the widget node + var widgetNode = createWidgetNode(parseTreeNode,wiki); + // Render the widget node to the DOM + var wrapper = renderWidgetNode(widgetNode); + // Test the rendering + expect(wrapper.innerHTML).toBe("Recursive transclusion error in transclude widget"); + }); + it("should deal with SVG elements", function() { var wiki = new $tw.Wiki(); // Construct the widget node From e3f9be995b27e8c362e0abaf570bbb8aeff3bd6f Mon Sep 17 00:00:00 2001 From: Bram Chen Date: Sat, 25 May 2024 19:12:19 +0800 Subject: [PATCH 06/14] Update chinese language files (#8204) * Add chinese description for field `stability` --- languages/zh-Hans/Fields.multids | 1 + languages/zh-Hant/Fields.multids | 1 + 2 files changed, 2 insertions(+) diff --git a/languages/zh-Hans/Fields.multids b/languages/zh-Hans/Fields.multids index b406a56ad..50a37b325 100644 --- a/languages/zh-Hans/Fields.multids +++ b/languages/zh-Hans/Fields.multids @@ -30,6 +30,7 @@ name: 具可读性的插件条目的名称 parent-plugin: 对于一个插件,指定其为哪个插件的子插件 plugin-priority: 插件条目的优先级数值 plugin-type: 插件条目的类型 +stability: 插件的开发状态:已弃用、实验性、稳定或旧版 released: TiddlyWiki 的发布日期 revision: 条目存放于服务器中的修订版本 source: 条目的网址 diff --git a/languages/zh-Hant/Fields.multids b/languages/zh-Hant/Fields.multids index a41e8b65e..74e5383a5 100644 --- a/languages/zh-Hant/Fields.multids +++ b/languages/zh-Hant/Fields.multids @@ -30,6 +30,7 @@ name: 具可讀性的套件條目的名稱 parent-plugin: 對於一個插件,指定其為哪個插件的子插件 plugin-priority: 套件條目的優先級數值 plugin-type: 套件條目的類型 +stability: 插件的開發狀態:已棄用、實驗性、穩定或舊版 released: TiddlyWiki 的釋出日期 revision: 條目存放於伺服器中的修訂版本 source: 條目的網址 From a463783283179db449a6d2950aea736e1ca1493c Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Sun, 26 May 2024 09:56:25 -0500 Subject: [PATCH 07/14] Fix/sjcl variable (#8099) * refactor: use files to add prefix * fix: always use $tw.sjcl * refactor: move sjcl to lib/sjcl * fix: require sjcl in lib/ * refactor: move sjcl.js back into /boot --- boot/sjcl.js.meta | 3 --- boot/tiddlywiki.files | 35 +++++++++++++++++++++++++++++++++++ core/modules/utils/utils.js | 2 +- 3 files changed, 36 insertions(+), 4 deletions(-) delete mode 100644 boot/sjcl.js.meta create mode 100644 boot/tiddlywiki.files diff --git a/boot/sjcl.js.meta b/boot/sjcl.js.meta deleted file mode 100644 index f32b4df93..000000000 --- a/boot/sjcl.js.meta +++ /dev/null @@ -1,3 +0,0 @@ -title: $:/library/sjcl.js -type: application/javascript -library: yes diff --git a/boot/tiddlywiki.files b/boot/tiddlywiki.files new file mode 100644 index 000000000..5e9c3d393 --- /dev/null +++ b/boot/tiddlywiki.files @@ -0,0 +1,35 @@ +{ + "tiddlers": [ + { + "file": "sjcl.js", + "fields": { + "title": "$:/library/sjcl.js", + "type": "application/javascript", + "library": "yes" + }, + "prefix": "(function(define) {\n", + "suffix": "\n})(function (_,defined){window.sjcl = defined()})\n" + }, + { + "file": "boot.js", + "fields": { + "title": "$:/boot/boot.js", + "type": "application/javascript" + } + }, + { + "file": "bootprefix.js", + "fields": { + "title": "$:/boot/bootprefix.js", + "type": "application/javascript" + } + }, + { + "file": "boot.css.tid", + "fields": { + "title": "$:/boot/boot.css", + "type": "text/css" + } + } + ] +} \ No newline at end of file diff --git a/core/modules/utils/utils.js b/core/modules/utils/utils.js index 42b3bd05c..878f83fbb 100644 --- a/core/modules/utils/utils.js +++ b/core/modules/utils/utils.js @@ -825,7 +825,7 @@ options.length .. number of characters returned defaults to 64 */ exports.sha256 = function(str, options) { options = options || {} - return sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(str)).substr(0,options.length || 64); + return $tw.sjcl.codec.hex.fromBits($tw.sjcl.hash.sha256.hash(str)).substr(0,options.length || 64); } /* From dbe912ba5d6b51e542abd8a94db0d49cc7eee04e Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Mon, 27 May 2024 06:45:29 -0500 Subject: [PATCH 08/14] Fix boot.css bug from #8099 (#8214) --- boot/{boot.css.tid => boot.css} | 3 --- boot/tiddlywiki.files | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) rename boot/{boot.css.tid => boot.css} (96%) diff --git a/boot/boot.css.tid b/boot/boot.css similarity index 96% rename from boot/boot.css.tid rename to boot/boot.css index 27c8884cd..c0d15f1e3 100644 --- a/boot/boot.css.tid +++ b/boot/boot.css @@ -1,6 +1,3 @@ -title: $:/boot/boot.css -type: text/css - /* Basic styles used before we boot up the parsing engine */ diff --git a/boot/tiddlywiki.files b/boot/tiddlywiki.files index 5e9c3d393..38ab5adde 100644 --- a/boot/tiddlywiki.files +++ b/boot/tiddlywiki.files @@ -25,7 +25,7 @@ } }, { - "file": "boot.css.tid", + "file": "boot.css", "fields": { "title": "$:/boot/boot.css", "type": "text/css" From 2312cd33015d4d1aa930e8e60572d0b2f710a31a Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Tue, 28 May 2024 13:17:35 +0100 Subject: [PATCH 09/14] Improve wording for failing test See https://talk.tiddlywiki.org/t/introducing-the-testcase-widget/9847/11 --- .../tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editions/tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid index bd9126e03..5524a9852 100644 --- a/editions/tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid +++ b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/FailingTest.tid @@ -5,7 +5,7 @@ description: An example of a failing test title: Narrative -This test case intentionally fails to show how failures are displayed. +This test case intentionally fails (in order to show how failures are displayed) + title: Output From b5bd4c96734bc76fe5380b05fd45d401ac602004 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Tue, 28 May 2024 13:22:44 +0100 Subject: [PATCH 10/14] Fix testcase heading link destination --- core/ui/TestCaseTemplate.tid | 1 + core/ui/TestCases/DefaultTemplate.tid | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/ui/TestCaseTemplate.tid b/core/ui/TestCaseTemplate.tid index 74b6ab27d..9871a2904 100644 --- a/core/ui/TestCaseTemplate.tid +++ b/core/ui/TestCaseTemplate.tid @@ -5,6 +5,7 @@ title: $:/core/ui/TestCaseTemplate <$let linkTarget="yes" displayFormat={{!!display-format}} + testcaseTiddler=<> > <$testcase testOutput="Output" diff --git a/core/ui/TestCases/DefaultTemplate.tid b/core/ui/TestCases/DefaultTemplate.tid index 679620969..0e4692ebf 100644 --- a/core/ui/TestCases/DefaultTemplate.tid +++ b/core/ui/TestCases/DefaultTemplate.tid @@ -15,7 +15,7 @@ title: $:/core/ui/testcases/DefaultTemplate

- <$genesis $type={{{ [!match[]then[$link]else[div]] }}}> + <$genesis $type={{{ [!match[]then[$link]else[div]] }}} to=<>> <%if [!match[]] %> !match[fail]then[tc-test-case-result-icon-pass]] [match[fail]then[tc-test-case-result-icon-fail]] +[join[ ]] }}}> <%if [!match[fail]] %> From 613ee13294ce01d9098c647329d4b6fdc1caeba6 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Tue, 28 May 2024 13:37:50 +0100 Subject: [PATCH 11/14] Testcase docs: add note about description field overwriting Description payload tiddler --- editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid | 3 +-- editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid b/editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid index ff84d6800..cf42c67d7 100644 --- a/editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid +++ b/editions/tw5.com/tiddlers/concepts/TestCaseTiddlers.tid @@ -23,5 +23,4 @@ Some payload tiddlers are set aside for special purposes: |''Narrative'' |Narrative description of the test, intended to explain the purpose and operation of the test | |''Output'' |The tiddler that produces the test output | |''~ExpectedResult'' |HTML of expected result of rendering the ''Output'' tiddler | - - +|''Description'' |Set to the text of the <<.field description>> field | diff --git a/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid b/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid index a73403890..608a964d6 100644 --- a/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid +++ b/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid @@ -75,7 +75,7 @@ The test case wiki will inherit variables that are visible to the <<.wid testcas A custom template can be specified for special purposes. For example, the provided template $:/core/ui/testcases/RawJSONTemplate just displays the payload tiddlers in JSON, which can be used for debugging purposes. -! Test Czase Template Variables +! Test Case Template Variables The <<.wid testcase>> widget makes the following variables available within the rendered template: From 9756b79683d157ce1ee87ddaec0d273edc754ce7 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Tue, 28 May 2024 14:30:59 +0100 Subject: [PATCH 12/14] Fix currentTiddler in testcase renderings See https://github.com/Jermolene/TiddlyWiki5/commit/eb4e9d86ac02a0d29e63ab600a4fc93bf8f2f360#r142368175 --- core/ui/TestCases/DefaultTemplate.tid | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/ui/TestCases/DefaultTemplate.tid b/core/ui/TestCases/DefaultTemplate.tid index 0e4692ebf..3a68253e8 100644 --- a/core/ui/TestCases/DefaultTemplate.tid +++ b/core/ui/TestCases/DefaultTemplate.tid @@ -55,7 +55,9 @@ title: $:/core/ui/testcases/DefaultTemplate
<$view tiddler="Output" format="plainwikified" mode="block"/>
<%else%> <$linkcatcher actions=<>> - <$transclude $tiddler="Output" $mode="block"/> + <$tiddler tiddler="Output"> + <$transclude $tiddler="Output" $mode="block"/> + <%endif%>

From 1b6e8e1a7930115a0a9c90d4d03fb6c1b135484e Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Wed, 29 May 2024 08:28:34 +0100 Subject: [PATCH 13/14] Testcase widget should only run tests if expected results are specified Fixes #8218 --- core/modules/widgets/testcase.js | 9 +++++++-- .../testcases/TestCaseWidget/NoExpectedResults.tid | 12 ++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 editions/tw5.com/tiddlers/testcases/TestCaseWidget/NoExpectedResults.tid diff --git a/core/modules/widgets/testcase.js b/core/modules/widgets/testcase.js index abb8f03f6..e80bbcaa3 100644 --- a/core/modules/widgets/testcase.js +++ b/core/modules/widgets/testcase.js @@ -77,8 +77,13 @@ TestCaseWidget.prototype.render = function(parent,nextSibling) { this.setVariable("transclusion",$tw.utils.hashString(jsonPayload)); // Generate a `payloadTiddlers` variable that contains the payload in JSON format this.setVariable("payloadTiddlers",jsonPayload); + // Only run the tests if the testcase output and expected results were specified, and those tiddlers actually exist in the wiki + var shouldRunTests = false; + if(this.testcaseTestOutput && this.testcaseWiki.tiddlerExists(this.testcaseTestOutput) && this.testcaseTestExpectedResult && this.testcaseWiki.tiddlerExists(this.testcaseTestExpectedResult)) { + shouldRunTests = true; + } // Render the test rendering if required - if(this.testcaseTestOutput && this.testcaseTestExpectedResult) { + if(shouldRunTests) { var testcaseOutputContainer = $tw.fakeDocument.createElement("div"); var testcaseOutputWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTestOutput,{ document: $tw.fakeDocument, @@ -101,7 +106,7 @@ TestCaseWidget.prototype.render = function(parent,nextSibling) { var testResult = "", outputHTML = "", expectedHTML = ""; - if(this.testcaseTestOutput && this.testcaseTestExpectedResult) { + if(shouldRunTests) { outputHTML = testcaseOutputContainer.children[0].innerHTML; expectedHTML = this.testcaseWiki.getTiddlerText(this.testcaseTestExpectedResult); if(outputHTML === expectedHTML) { diff --git a/editions/tw5.com/tiddlers/testcases/TestCaseWidget/NoExpectedResults.tid b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/NoExpectedResults.tid new file mode 100644 index 000000000..a4dcee462 --- /dev/null +++ b/editions/tw5.com/tiddlers/testcases/TestCaseWidget/NoExpectedResults.tid @@ -0,0 +1,12 @@ +title: TestCases/TestCaseWidget/NoExpectedResults +type: text/vnd.tiddlywiki-multiple +tags: [[$:/tags/wiki-test-spec]] +description: A testcase that does not specify expected results + +title: Narrative + +This testcase will display without the pass/fail icons because it does not include an `ExpectedResults` tiddler, and so will only be rendered, and not be executed as a test ++ +title: Output + +This is the output From 4274e8fd7fd7440cd92037b537843d5bd27981d6 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Wed, 29 May 2024 08:36:52 +0100 Subject: [PATCH 14/14] Fix tests broken in 1b6e8e1a7930115a0a9c90d4d03fb6c1b135484e --- .../jasmine/run-wiki-based-tests.js | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js b/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js index e22fe7378..90d4768e4 100644 --- a/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js +++ b/plugins/tiddlywiki/jasmine/run-wiki-based-tests.js @@ -34,23 +34,22 @@ describe("Wiki-based tests", function() { if(!wiki.tiddlerExists("Output")) { throw "Missing 'Output' tiddler"; } - if(!wiki.tiddlerExists("ExpectedResult")) { - throw "Missing 'ExpectedResult' tiddler"; + if(wiki.tiddlerExists("ExpectedResult")) { + // Construct the widget node + var text = "{{Output}}\n\n"; + var widgetNode = createWidgetNode(parseText(text,wiki),wiki); + // Render the widget node to the DOM + var wrapper = renderWidgetNode(widgetNode); + // Clear changes queue + wiki.clearTiddlerEventQueue(); + // Run the actions if provided + if(wiki.tiddlerExists("Actions")) { + widgetNode.invokeActionString(wiki.getTiddlerText("Actions")); + refreshWidgetNode(widgetNode,wrapper); + } + // Test the rendering + expect(wrapper.innerHTML).toBe(wiki.getTiddlerText("ExpectedResult")); } - // Construct the widget node - var text = "{{Output}}\n\n"; - var widgetNode = createWidgetNode(parseText(text,wiki),wiki); - // Render the widget node to the DOM - var wrapper = renderWidgetNode(widgetNode); - // Clear changes queue - wiki.clearTiddlerEventQueue(); - // Run the actions if provided - if(wiki.tiddlerExists("Actions")) { - widgetNode.invokeActionString(wiki.getTiddlerText("Actions")); - refreshWidgetNode(widgetNode,wrapper); - } - // Test the rendering - expect(wrapper.innerHTML).toBe(wiki.getTiddlerText("ExpectedResult")); }); });