From 57e74a0ad54543004ce88671f62c467b32129792 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Sun, 5 May 2024 13:54:02 +0100 Subject: [PATCH] Extend the testcase widget to run tests --- core/modules/widgets/testcase.js | 50 ++++++++++++++++++- core/ui/TestCases/DefaultTemplate.tid | 23 ++++++++- core/ui/TestCases/DefaultTemplateSource.tid | 4 ++ .../tiddlers/widgets/TestCaseWidget.tid | 38 ++++++++++---- themes/tiddlywiki/vanilla/base.tid | 49 +++++++++++++++++- 5 files changed, 151 insertions(+), 13 deletions(-) diff --git a/core/modules/widgets/testcase.js b/core/modules/widgets/testcase.js index 1ebb1b7c1..fe80f2b63 100644 --- a/core/modules/widgets/testcase.js +++ b/core/modules/widgets/testcase.js @@ -79,8 +79,52 @@ 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); + // Render the test rendering if required + if(this.testcaseTestOutput && this.testcaseTestExpectedResult) { + var testcaseOutputContainer = $tw.fakeDocument.createElement("div"); + var testcaseOutputWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTestOutput,{ + document: $tw.fakeDocument, + parseAsInline: false, + parentWidget: this, + variables: { + currentTiddler: this.testcaseTestOutput + } + }); + testcaseOutputWidget.render(testcaseOutputContainer); + } + // Clear changes queue + this.testcaseWiki.clearTiddlerEventQueue(); + // Run the actions if provided + if(this.testcaseWiki.tiddlerExists(this.testcaseTestActions)) { + testcaseOutputWidget.invokeActionString(this.testcaseWiki.getTiddlerText(this.testcaseTestActions)); + testcaseOutputWidget.refresh(this.testcaseWiki.changedTiddlers,testcaseOutputContainer); + } + // Set up the test result variables + var testResult = "", + outputHTML = "", + expectedHTML = ""; + if(this.testcaseTestOutput && this.testcaseTestExpectedResult) { + outputHTML = testcaseOutputContainer.children[0].innerHTML; + expectedHTML = this.testcaseWiki.getTiddlerText(this.testcaseTestExpectedResult); + if(outputHTML === expectedHTML) { + testResult = "pass"; + } else { + testResult = "fail"; + } + this.setVariable("outputHTML",outputHTML); + this.setVariable("expectedHTML",expectedHTML); + this.setVariable("testResult",testResult); + } + // Don't display anything if testHideIfPass is "yes" and the tests have passed + if(this.testcaseHideIfPass === "yes" && testResult === "pass") { + return; + } // Render the page root template of the subwiki - var rootWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTemplate,{document: this.document, parseAsInline: false, parentWidget: this}); + var rootWidget = this.testcaseWiki.makeTranscludeWidget(this.testcaseTemplate,{ + document: this.document, + parseAsInline: false, + parentWidget: this + }); rootWidget.render(domNode); // Trap changes in the wiki and refresh the rendering this.testcaseWiki.addEventListener("change",function(changes) { @@ -93,6 +137,10 @@ Compute the internal state of the widget */ TestCaseWidget.prototype.execute = function() { this.testcaseTemplate = this.getAttribute("template","$:/core/ui/testcases/DefaultTemplate"); + this.testcaseTestOutput = this.getAttribute("testOutput"); + this.testcaseTestActions = this.getAttribute("testActions"); + this.testcaseTestExpectedResult = this.getAttribute("testExpectedResult"); + this.testcaseHideIfPass = this.getAttribute("testHideIfPass"); }; /* diff --git a/core/ui/TestCases/DefaultTemplate.tid b/core/ui/TestCases/DefaultTemplate.tid index 269661547..3240534c9 100644 --- a/core/ui/TestCases/DefaultTemplate.tid +++ b/core/ui/TestCases/DefaultTemplate.tid @@ -6,8 +6,27 @@ title: $:/core/ui/testcases/DefaultTemplate >
-

<$transclude tiddler="Description" mode="inline"/>

+

+ <%if [!match[]] %> + !match[fail]then[tc-testcase-result-icon-pass]] [match[fail]then[tc-testcase-result-icon-fail]] +[join[ ]] }}}> + <%if [!match[fail]] %> + {{$:/core/images/done-button}} + <%else%> + {{$:/core/images/close-button}} + <%endif%> + + <%endif%> + <$view tiddler="Description" mode="inline"/> +

+ <%if [match[fail]] %> +
+
+ TEST FAILED +
+ <$diff-text source=<> dest=<>/> +
+ <%endif%>
<$macrocall $name="tabs" tabsList="[all[tiddlers]sort[]] -[prefix] -Description -ExpectedResult -Output Output +[putfirst[]] -[has[plugin-type]]" state=<> default="Output" template="$:/core/ui/testcases/DefaultTemplate/Source"/> @@ -15,7 +34,7 @@ title: $:/core/ui/testcases/DefaultTemplate
- <$transclude tiddler="Output"/> + <$transclude $tiddler="Output" $mode="block"/>
diff --git a/core/ui/TestCases/DefaultTemplateSource.tid b/core/ui/TestCases/DefaultTemplateSource.tid index 88183d796..f6bda6171 100644 --- a/core/ui/TestCases/DefaultTemplateSource.tid +++ b/core/ui/TestCases/DefaultTemplateSource.tid @@ -1,6 +1,7 @@ title: $:/core/ui/testcases/DefaultTemplate/Source \whitespace trim +\procedure body() <$list filter="[fields[]] -text +[limit[1]]" variable="ignore"> @@ -18,3 +19,6 @@ title: $:/core/ui/testcases/DefaultTemplate/Source
<$edit class="tc-edit-texteditor" tiddler=<>/> +\end + +<$transclude $variable="body" $mode="inline"/> diff --git a/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid b/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid index 7dfb7640e..8ae7d46fd 100644 --- a/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid +++ b/editions/tw5.com/tiddlers/widgets/TestCaseWidget.tid @@ -9,24 +9,46 @@ type: text/vnd.tiddlywiki The testcase widget creates an independent subwiki loaded with the specified payload tiddlers and then renders a specified template from within the subwiki.The default template displays a split view with the source tiddlers on the left and the rendered tiddler titled `Output` on the right. It also displays the tiddler titled `Description` as the heading. This makes it possible to run independent tests that also serve as documentation examples. +The testcase widget can optionally also be used to run and verify test results within the subwiki. + +The testcase widget creates a lightweight TiddlyWiki environment with the following important limitations: + +* Output is rendered into a DIV, and so cannot be styled independently of the host wiki +* Any changes to the wiki made interactively by the user are volatile, and are lost when the testcase widget is refreshed +* Startup actions are not supported +* Only plugins available in the host wiki can be included in the testcase + +The [[Innerwiki Plugin]] offers the ability to embed a fully independent subwiki via an `