Extend the testcase widget to run tests
This commit is contained in:
parent
22ad43954e
commit
57e74a0ad5
|
@ -79,8 +79,52 @@ TestCaseWidget.prototype.render = function(parent,nextSibling) {
|
||||||
this.setVariable("transclusion",$tw.utils.hashString(jsonPayload));
|
this.setVariable("transclusion",$tw.utils.hashString(jsonPayload));
|
||||||
// Generate a `payloadTiddlers` variable that contains the payload in JSON format
|
// Generate a `payloadTiddlers` variable that contains the payload in JSON format
|
||||||
this.setVariable("payloadTiddlers",jsonPayload);
|
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
|
// 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);
|
rootWidget.render(domNode);
|
||||||
// Trap changes in the wiki and refresh the rendering
|
// Trap changes in the wiki and refresh the rendering
|
||||||
this.testcaseWiki.addEventListener("change",function(changes) {
|
this.testcaseWiki.addEventListener("change",function(changes) {
|
||||||
|
@ -93,6 +137,10 @@ Compute the internal state of the widget
|
||||||
*/
|
*/
|
||||||
TestCaseWidget.prototype.execute = function() {
|
TestCaseWidget.prototype.execute = function() {
|
||||||
this.testcaseTemplate = this.getAttribute("template","$:/core/ui/testcases/DefaultTemplate");
|
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");
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -6,8 +6,27 @@ title: $:/core/ui/testcases/DefaultTemplate
|
||||||
>
|
>
|
||||||
<div class="tc-testcase-wrapper">
|
<div class="tc-testcase-wrapper">
|
||||||
<div class="tc-testcase-header">
|
<div class="tc-testcase-header">
|
||||||
<h2><$transclude tiddler="Description" mode="inline"/></h2>
|
<h2>
|
||||||
|
<%if [<testResult>!match[]] %>
|
||||||
|
<span class={{{ tc-testcase-result-icon [<testResult>!match[fail]then[tc-testcase-result-icon-pass]] [<testResult>match[fail]then[tc-testcase-result-icon-fail]] +[join[ ]] }}}>
|
||||||
|
<%if [<testResult>!match[fail]] %>
|
||||||
|
{{$:/core/images/done-button}}
|
||||||
|
<%else%>
|
||||||
|
{{$:/core/images/close-button}}
|
||||||
|
<%endif%>
|
||||||
|
</span>
|
||||||
|
<%endif%>
|
||||||
|
<$view tiddler="Description" mode="inline"/>
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
<%if [<testResult>match[fail]] %>
|
||||||
|
<div class="tc-testcase-result-fail">
|
||||||
|
<div>
|
||||||
|
TEST FAILED
|
||||||
|
</div>
|
||||||
|
<$diff-text source=<<expectedHTML>> dest=<<outputHTML>>/>
|
||||||
|
</div>
|
||||||
|
<%endif%>
|
||||||
<div class="tc-testcase-panes">
|
<div class="tc-testcase-panes">
|
||||||
<div class="tc-testcase-source">
|
<div class="tc-testcase-source">
|
||||||
<$macrocall $name="tabs" tabsList="[all[tiddlers]sort[]] -[prefix<state>] -Description -ExpectedResult -Output Output +[putfirst[]] -[has[plugin-type]]" state=<<state>> default="Output" template="$:/core/ui/testcases/DefaultTemplate/Source"/>
|
<$macrocall $name="tabs" tabsList="[all[tiddlers]sort[]] -[prefix<state>] -Description -ExpectedResult -Output Output +[putfirst[]] -[has[plugin-type]]" state=<<state>> default="Output" template="$:/core/ui/testcases/DefaultTemplate/Source"/>
|
||||||
|
@ -15,7 +34,7 @@ title: $:/core/ui/testcases/DefaultTemplate
|
||||||
<div class="tc-testcase-divider">
|
<div class="tc-testcase-divider">
|
||||||
</div>
|
</div>
|
||||||
<div class="tc-testcase-output">
|
<div class="tc-testcase-output">
|
||||||
<$transclude tiddler="Output"/>
|
<$transclude $tiddler="Output" $mode="block"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
title: $:/core/ui/testcases/DefaultTemplate/Source
|
title: $:/core/ui/testcases/DefaultTemplate/Source
|
||||||
|
|
||||||
\whitespace trim
|
\whitespace trim
|
||||||
|
\procedure body()
|
||||||
<$list filter="[<currentTab>fields[]] -text +[limit[1]]" variable="ignore">
|
<$list filter="[<currentTab>fields[]] -text +[limit[1]]" variable="ignore">
|
||||||
<table class="tc-field-table">
|
<table class="tc-field-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -18,3 +19,6 @@ title: $:/core/ui/testcases/DefaultTemplate/Source
|
||||||
</table>
|
</table>
|
||||||
</$list>
|
</$list>
|
||||||
<$edit class="tc-edit-texteditor" tiddler=<<currentTab>>/>
|
<$edit class="tc-edit-texteditor" tiddler=<<currentTab>>/>
|
||||||
|
\end
|
||||||
|
|
||||||
|
<$transclude $variable="body" $mode="inline"/>
|
||||||
|
|
|
@ -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 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 `<iframe>` element, but without the testing related features of the testcase widget.
|
||||||
|
|
||||||
! Content and Attributes
|
! Content and Attributes
|
||||||
|
|
||||||
The content of the `<$testcase>` widget is not displayed but instead is scanned for <<.wlink DataWidget>> widgets that define the payload tiddlers to be included in the test case. The `$:/core` plugin is automatically included in the payload.
|
The content of the `<$testcase>` widget is not displayed but instead is scanned for <<.wlink DataWidget>> widgets that define the payload tiddlers to be included in the testcase.
|
||||||
|
|
||||||
|!Attribute |!Description |
|
|!Attribute |!Description |
|
||||||
|<<.attr template>> |Optional title of the template used to display the testcase (defaults to $:/core/ui/testcases/DefaultTemplate). Note that custom templates will need to be explicitly added to the payload |
|
|<<.attr template>> |Optional title of the template used to display the testcase (defaults to $:/core/ui/testcases/DefaultTemplate). Note that custom templates will need to be explicitly added to the payload |
|
||||||
|
|<<.attr testOutput>> |Optional title of the tiddler whose output should be subject to testing (note that both <<.attr testOutput>> and <<.attr testExpectedResult>> must be provided in order for testing to occur) |
|
||||||
|
|<<.attr testExpectedResult>> |Optional title of the tiddler whose content is the expected result of rendering the output tiddler (note that both <<.attr testOutput>> and <<.attr testExpectedResult>> must be provided in order for testing to occur) |
|
||||||
|
|<<.attr testActions>> |Optional title of the tiddler containing actions that should be executed before the test occurs |
|
||||||
|
|<<.attr testHideIfPass>> |If set to "yes", hides the testcase widget if the test passes |
|
||||||
|
|
||||||
! Payload Tiddlers
|
! Payload Tiddlers
|
||||||
|
|
||||||
The payload tiddlers are the tiddler values that are loaded into the subwiki that is created to run the tests. They are created via <<.wlink DataWidget>> widgets within the body of the `<$testcase>` widget.
|
The payload tiddlers are the tiddler values that are loaded into the subwiki that is created to run the tests. They are created via <<.wlink DataWidget>> widgets within the body of the `<$testcase>` widget. The `$:/core` plugin is automatically included in the payload.
|
||||||
|
|
||||||
! State Handling
|
! Testcase Template Variables
|
||||||
|
|
||||||
The `<$testcase>` widget sets the variable `transclusion` to a hash that reflects the names and values of all the payload tiddlers. This makes it easier for test case templates to create unique state tiddler titles using the [[qualify Macro]] or QualifyWidget.
|
The testcase widget makes the following variables available within the rendered template:
|
||||||
|
|
||||||
! Test Case Conventions
|
|!Variable |!Description |
|
||||||
|
|<<.var transclusion>> |A hash that reflects the names and values of all the payload tiddlers. This makes it easier for testcase templates to create unique state tiddler titles using the [[qualify Macro]] or QualifyWidget |
|
||||||
|
|<<.var payloadTiddlers>> |JSON array of payload tiddler fields |
|
||||||
|
|<<.var outputHTML>> |The actual output HTML if running tests |
|
||||||
|
|<<.var expectedHTML>> |The expected output HTML if running tests |
|
||||||
|
|<<.var testResult>> |The tests result if running tests (may be "pass" or "fail") |
|
||||||
|
|
||||||
The following conventions are used for test case tiddlers:
|
! Testcase Conventions
|
||||||
|
|
||||||
|
The following conventions are used for testcase tiddlers:
|
||||||
|
|
||||||
* `Description` contains a brief description of the test (rendered in inline mode)
|
* `Description` contains a brief description of the test (rendered in inline mode)
|
||||||
* `Output` contains the tiddler text to be rendered. It can also reference other tiddlers
|
* `Output` contains the tiddler text to be rendered. It can also reference other tiddlers
|
||||||
|
@ -35,9 +57,7 @@ The following conventions are used for test case tiddlers:
|
||||||
! Example
|
! Example
|
||||||
|
|
||||||
<$testcase>
|
<$testcase>
|
||||||
<$data $tiddler="$:/core/ui/testcases/DefaultTemplate"/>
|
<$data title="Description" text="Simple example of a testcase"/>
|
||||||
<$data $tiddler="$:/core/ui/testcases/DefaultTemplate/Source"/>
|
|
||||||
<$data title="Description" text="Simple example of a test case"/>
|
|
||||||
<$data title="Output" text="""<$testcase>
|
<$data title="Output" text="""<$testcase>
|
||||||
<$data title="Description" text="How to calculate 2 plus 2"/>
|
<$data title="Description" text="How to calculate 2 plus 2"/>
|
||||||
<$data title="Output" text="<$text text={{{ [[2]add[2]] }}}/>"/>
|
<$data title="Output" text="<$text text={{{ [[2]add[2]] }}}/>"/>
|
||||||
|
|
|
@ -3250,6 +3250,40 @@ span.tc-translink > a:first-child {
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tc-testcase-divider {
|
||||||
|
x-background-color: <<colour muted-foreground>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc-testcase-result-icon {
|
||||||
|
fill: #fff;
|
||||||
|
padding: 0.25em;
|
||||||
|
display: inline-block;
|
||||||
|
line-height: 0;
|
||||||
|
border-radius: 1em;
|
||||||
|
vertical-align: bottom;
|
||||||
|
margin-right: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc-testcase-result-icon-pass {
|
||||||
|
background-color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc-testcase-result-icon-fail {
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc-testcase-result-icon svg {
|
||||||
|
width: 0.5em;
|
||||||
|
height: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc-testcase-result-fail {
|
||||||
|
border: 1px solid <<colour foreground>>;
|
||||||
|
background-color: <<colour background>>;
|
||||||
|
margin: 1em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.tc-testcase-header > h2,
|
.tc-testcase-header > h2,
|
||||||
.tc-testcase-source > pre {
|
.tc-testcase-source > pre {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -3260,7 +3294,6 @@ span.tc-translink > a:first-child {
|
||||||
}
|
}
|
||||||
|
|
||||||
.tc-testcase-panes {
|
.tc-testcase-panes {
|
||||||
background: <<colour background>>;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
@ -3274,10 +3307,23 @@ span.tc-translink > a:first-child {
|
||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tc-testcase-source .tc-tab-content {
|
||||||
|
background: <<colour background>>;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.tc-testcase-source .tc-field-table {
|
.tc-testcase-source .tc-field-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tc-testcase-source table.tc-field-table {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc-tiddler-frame .tc-edit-texteditor {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.tc-testcase-divider {
|
.tc-testcase-divider {
|
||||||
flex: 0 0 2%;
|
flex: 0 0 2%;
|
||||||
}
|
}
|
||||||
|
@ -3287,6 +3333,7 @@ span.tc-translink > a:first-child {
|
||||||
}
|
}
|
||||||
|
|
||||||
.tc-testcase-output {
|
.tc-testcase-output {
|
||||||
|
background: <<colour background>>;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
border: 1px solid <<colour muted-foreground>>;
|
border: 1px solid <<colour muted-foreground>>;
|
||||||
flex: 1 0 49%;
|
flex: 1 0 49%;
|
||||||
|
|
Loading…
Reference in New Issue