siesta-lite
Version:
Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers
286 lines (238 loc) • 11 kB
HTML
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The source code</title>
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
<style type="text/css">
.highlight { display: block; background-color: #ddd; }
</style>
<script type="text/javascript">
function highlight() {
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
}
</script>
</head>
<body onload="prettyPrint(); highlight();">
<pre class="prettyprint lang-js">/*
Siesta 5.6.1
Copyright(c) 2009-2022 Bryntum AB
https://bryntum.com/contact
https://bryntum.com/products/siesta/license
*/
<span id='Siesta-Test-Action-Wait'>/**
</span>
@class Siesta.Test.Action.Wait
@extends Siesta.Test.Action
This action can be included in the `t.chain` call with "wait" or "delay" shortcuts:
t.chain(
{
action : 'wait', // or "delay"
delay : 1000 // 1 second
}
)
Alternatively, for convenience, this action can be included in the chain using "waitFor" config (the "action" property can be omitted):
t.chain(
{
waitFor : 'selector', // or any other waitFor* method name
args : [ '.x-grid-row' ] // an array of arguments for the specified method
}
)
t.chain(
{
waitFor : 'rowsVisible', // or any other waitFor* method name
args : [ grid ] // an array of arguments for the specified method
}
)
t.chain(
{
waitFor : 'waitForRowsVisible', // full method name is also ok
args : grid // a single value will be converted to array automatically
}
)
In the latter case, this action will perform a call to the one of the `waitFor*` methods of the test instance.
The name of the method is computed by prepending the uppercased value of `waitFor` config with the string "waitFor"
(unless it doesn't already start with "waitFor").
The arguments for method call can be provided as the "args" array. Any non-array value for "args" will be converted to an array with one element.
* **Note**, that this action will provide a `callback`, `scope`, and `timeout` arguments for `waitFor*` methods - you should not specify them.
As a special case, the value of `waitFor` config can be a Number or Function - that will trigger the call to {@link Siesta.Test#waitFor} method with provided value:
t.chain(
{
waitFor : 500
},
// same as
{
waitFor : '',
args : [ 500 ]
},
{
waitFor : function () { return document.body.className.match(/someClass/) }
}
)
*/
Class('Siesta.Test.Action.Wait', {
isa : Siesta.Test.Action,
has : {
<span id='Siesta-Test-Action-Wait-cfg-delay'> /**
</span> * @cfg {Number} delay
*
* A number of milliseconds to wait before continuing.
*/
delay : 1000,
<span id='Siesta-Test-Action-Wait-cfg-timeout'> /**
</span> * @cfg {Number} timeout
*
* The maximum amount of time to wait for the condition to be fulfilled. Defaults to the {@link Siesta.Test.ExtJS#waitForTimeout} value.
*/
timeout : null,
<span id='Siesta-Test-Action-Wait-cfg-interval'> /**
</span> * @cfg {Number} interval
*
* The interval between the checks for condition. Default value is 100ms.
*/
interval : null,
<span id='Siesta-Test-Action-Wait-cfg-args'> /**
</span> * @cfg {Array/Function} args
*
* The array of arguments to pass to waitForXXX method. You should omit the 3 last parameters: callback, scope, timeout. Any non-array value will be converted to
* a single-value array. Can be also a function, returning either an array of a single value, which will be converted to array.
* Function will be called using test instance as a "this" scope.
* If you need to pass a function, as an argument, wrap in the array. Compare:
{
waitFor : 'SomeCondition',
// will be called when processing the action, should return an array of arguments
args : function () {}
}
{
waitFor : 'SomeCondition',
// won't be called, instead will be passed as 1st argument
args : [ function () {} ]
}
*
*/
args : Joose.I.Array,
<span id='Siesta-Test-Action-Wait-cfg-waitFor'> /**
</span> * @cfg {String} waitFor
*
* The name of the `waitFor` method to call. You can omit the leading "waitFor":
*
t.chain(
{
waitFor : 'selector',
...
},
// same as
{
waitFor : 'waitForSelector',
...
}
)
*
*/
waitFor : null,
<span id='Siesta-Test-Action-Wait-cfg-trigger'> /**
</span> * @cfg {Object/Function} trigger
*
* A config object for the action that should trigger the waiting condition. Can be also a regular function to execute.
* An action or function will be executed right *after* the waiting has started, to avoid the race conditions.
*
* To illustrate, imagine, when clicking on some button, new data package will be loaded and some event `dataloaded`
* will be fired. We want to wait for that event. Usually, you will write this as the following action steps, in the `chain` method:
*
t.chain(
{ click : '.someButton' },
{ waitFor : 'Event', args : [ someDataStorage, 'dataload' ] },
...
)
* However, imagine loading mechanism implements caching, and sometimes loading happens *synchronously*. In this case,
* the `dataload` event will be also fired synchronously, right during the "onclick" handler of the button. Then, we'll start
* waiting for that event (which has already been fired) and the `waitFor` action will fail.
*
* To avoid this race condition, we need to first start waiting for the event, and only then - perform a click:
*
t.chain(
function (next) {
t.waitForEvent(someDataStorage, 'dataload', next);
t.click('.someButton', function () {})
},
...
)
* or, using `trigger` config:
t.chain(
{
waitFor : 'Event',
args : [ someDataStorage, 'dataload' ],
trigger : { click : '.someButton' }
},
...
)
*/
trigger : null,
hasOwnAsyncFrame : true,
description : '' // used internally to have custom wait messages that don't produce noise in the UI (chain step automatically adds a t.pass with 'desc')
},
methods : {
process : function () {
var waitFor = this.waitFor;
var test = this.test
if (test.typeOf(waitFor) === 'Number' || test.typeOf(waitFor) === 'Function') {
// Caller supplied a function returning true when done waiting or
// a number of milliseconds to wait for.
this.args = [ waitFor ];
waitFor = '';
}
if (waitFor == null) {
this.args = [ this.delay ];
waitFor = '';
}
// special case for { waitForFn : function () {} }" - we consider the function here
// not a function which should return an array with arguments for the "waitFor" method
// (which is a usual behavior for { someMehthod : function () {} } ), but the `waitFor` checker function itself
if (test.typeOf(this.args) === "Function" && waitFor != 'waitForFn') {
this.args = this.args.call(test, this);
}
if (test.typeOf(this.args) !== "Array") {
this.args = [ this.args ];
}
// also allow full method names
waitFor = waitFor.replace(/^waitFor/, '')
var methodName = 'waitFor' + Joose.S.uppercaseFirst(waitFor);
if (!test[ methodName ]){
throw Siesta.Resource("Siesta.Test.Action.Wait", 'missingMethodText') + methodName;
}
// If using simple waitFor statement, use the object notation to be able to pass a description
// which gives better debugging help than "Waited too long for condition to be fulfilled".
if (methodName === 'waitFor') {
test.waitFor({
method : this.args[ 0 ],
callback : this.next,
scope : test,
timeout : this.timeout || test.waitForTimeout,
interval : this.interval,
description : this.description || this.desc || ''
});
} else {
test[ methodName ].apply(test, this.args.concat(this.next, test, this.timeout || test.waitForTimeout));
}
var trigger = this.trigger
if (trigger) {
if (test.typeOf(trigger) == 'Function')
trigger.call(test, test)
else {
if (!(trigger instanceof Siesta.Test.Action)) {
trigger.next = function () {}
trigger.test = this.test
trigger = Siesta.Test.ActionRegistry().create(trigger, test)
}
trigger.process()
}
}
}
}
});
Joose.A.each([ 'wait', 'waitFor', 'delay' ], function(name) {
Siesta.Test.ActionRegistry().registerAction(name, Siesta.Test.Action.Wait);
});</pre>
</body>
</html>