@ -278,7 +278,7 @@ class Empty: public Command {
QString description ( ) const {
return
" "
" \n \n "
" \n \n -- \n \n "
" Empty lines are allowed " ;
}
QString command ( ) const {
@ -306,7 +306,7 @@ class Comment: public Command {
QString description ( ) const {
return
" # comment "
" \n \n "
" \n \n -- \n \n "
" Comments are lines that start with # " ;
}
QString command ( ) const {
@ -383,7 +383,7 @@ class Screenshot: public Command {
QString description ( ) const {
return
tag ( ) + " <filename-base> "
" \n \n "
" \n \n -- \n \n "
" Create a PNG screenshot of the actual web page and store it in the "
" file <filename-base>.png. If not already opened, a browser window "
" will pop up to take the screenshot. " ;
@ -450,6 +450,7 @@ class Script: public QObject {
void logging ( QString ) ;
void progress ( QString , int , int , int ) ;
public :
typedef std : : map < QString , std : : shared_ptr < Command > > Prototypes ;
typedef std : : pair < QString , QStringList > Signal ;
enum ClickType {
REAL_MOUSE_CLICK ,
@ -500,57 +501,79 @@ class Script: public QObject {
}
QString syntax ( ) const {
return
" Script syntax is a text file that consists of list of commands. Each "
" Script syntax is a text file that consists of a list of commands. Each "
" command starts at the begin of a new line. Empty lines are allowed. "
" Lines that start with \" # \" are treated as comments. "
" \n \n "
" Subcommands are indented. The first indented line defines the level of "
" indentation. All following lines must be indented by the same level. "
" indentation. All following lines must be indented at least by the same level. "
" \n \n "
" Note: When a selector is required as parameter, then the selector "
" is a CSS selector. "
" \n \n "
" Thanks to the filter script doxygen-webtester.sed, you cab use the "
" Thanks to the filter script doxygen-webtester.sed, you can use the "
" comments for producing doxygen documenation. Just start comments with "
" \" ## \" to import them to doxygen. This script is automatically configured, "
" when you use the autotools bootstrap from: \n "
" https://dev.marc.waeckerlin.org/redmine/projects /bootstrap-build-environment " ;
" https://mrw.sh/development /bootstrap-build-environment " ;
}
/// set workdir
void path ( QString path ) {
_path = ( path . size ( ) ? path : " . " ) + QDir : : separator ( ) ;
}
/// get workdir
QString path ( ) {
QString path ( ) const {
return _path ;
}
/// get all command prototypes
const Prototypes & prototypes ( ) const {
return _prototypes ;
}
QString commands ( Formatting f = PLAIN ) const {
QString cmds ;
for ( auto it ( _prototypes . begin ( ) ) ; it ! = _prototypes . end ( ) ; + + it )
switch ( f ) {
case PLAIN : {
switch ( f ) {
case PLAIN : {
for ( auto it ( _prototypes . begin ( ) ) ; it ! = _prototypes . end ( ) ; + + it )
cmds + = " \n \n \n COMMAND: " + it - > first + " \n \n " + it - > second - > description ( ) ;
} break ;
case HTML : {
cmds + = " <h1> " + it - > first + " </h1><p> "
+ it - > second - > description ( )
. replace ( " & " , " & " )
. replace ( " < " , " < " )
. replace ( " > " , " > " )
. replace ( QRegularExpression ( " <([^ ]+)> " ) ,
" <i> \\ 1</i> " )
. replace ( QRegularExpression ( " ( \n [^ ][^ \n ]*)( \n +-) " ) ,
" \\ 1<ul> \\ 2 " )
. replace ( QRegularExpression ( " ( \n +-[^ \n ]* \n )([^ ]) " ) ,
" \\ 1</ul> \\ 2 " )
. replace ( QRegularExpression ( " \n +- ([^ \n ]*)(</ul>)? " ) ,
" <li> \\ 1</li> \\ 2 " )
. replace ( " </li> \n " , " </li> " )
. replace ( " \n " , " \n " )
. replace ( " \n \n " , " </p><p> " )
. replace ( " \n " , " <br/> " )
+ " </p> " ;
} break ;
} break ;
case HTML : {
auto format = [ ] ( QString s ) {
return s
. replace ( " & " , " & " )
. replace ( " < " , " < " )
. replace ( " > " , " > " )
. replace ( QRegularExpression ( " <([-_A-Za-z0-9]+)> " ) , " <i> \\ 1</i> " )
. replace ( QRegularExpression ( " ( \n [^ ][^ \n ]*)( \n +-) " ) , " \\ 1<ul> \\ 2 " )
. replace ( QRegularExpression ( " ( \n +-[^ \n ]* \n )([^ ]) " ) , " \\ 1</ul> \\ 2 " )
. replace ( QRegularExpression ( " \n +- ([^ \n ]*)(</ul>)? " ) , " <li> \\ 1</li> \\ 2 " )
. replace ( " </li> \n " , " </li> " )
. replace ( " \n " , " \n " )
. replace ( " \n \n " , " </p><p> " )
. replace ( " \n " , " <br/> " )
. replace ( QRegularExpression ( " (http(s)?://[-/^a-z0-9.]+) " ) , " <a href= \" \\ 1 \" > \\ 1</a> " ) ;
} ;
cmds = " <style>div#table-of-contents {border: 2px solid black; background-color: red; width: 100%; column-width: 5em;}</style> "
" <h1>Contents</h1><ul> "
" <li id= \" top-syntax-description \" ><a href= \" #syntax-description \" >Syntax</a></li> "
" <li id= \" top-command-list \" ><a href= \" #command-list \" >Commands</a><ul> " ;
for ( auto [ name , command ] : _prototypes )
cmds + = " <li id= \" top- " + name + " \" ><a href= \" # " + name + " \" > " + name + " </a></li> " ;
cmds + = " </ul></li></ul> "
" <h1 id= \" syntax-description \" ><a href= \" #top-syntax-description \" >Syntax</a></h1> "
+ format ( syntax ( ) ) +
" <h1 id= \" command-list \" ><a href= \" #top-command-list \" >Commands</a></h1> " ;
for ( auto [ name , command ] : _prototypes ) {
QStringList doc ( command - > description ( ) . split ( " \n \n -- \n \n " ) ) ;
assert ( doc . size ( ) = = 2 ) ; // description does not match expected format
QString usage ( doc . takeFirst ( ) ) ;
QString description ( doc . takeFirst ( ) ) ;
cmds + = " <h2 id= \" " + name + " \" ><a href= \" #top- " + name + " \" > " + name + " </a></h2><h3>Usage</h3><p> "
+ format ( usage )
+ " </p><h3>Description</h3><p> "
+ format ( description )
+ " </p> " ;
}
} break ;
}
return cmds . trimmed ( ) ;
}
@ -1155,7 +1178,6 @@ class Script: public QObject {
QString username ;
QString password ;
} ;
typedef std : : map < QString , std : : shared_ptr < Command > > Prototypes ;
typedef std : : vector < std : : shared_ptr < Command > > Commands ;
Prototypes _prototypes ;
Commands _script ;
@ -1205,7 +1227,7 @@ class Do: public Command {
QString description ( ) const {
return
tag ( ) + " [<selector>] \n <javascript-line1> \n <javascript-line2> "
" \n \n "
" \n \n -- \n \n "
" Execute JavaScript on a CSS selected object. The object is the first "
" object in the DOM tree that matches the given CSS selector. You can "
" refere to the selected object within the scripy by \" this \" . The "
@ -1248,7 +1270,7 @@ class Load: public Command {
QString description ( ) const {
return
tag ( ) + " <url> "
" \n \n "
" \n \n -- \n \n "
" Load an URL, the URL is given as parameter in full syntax. " ;
}
QString command ( ) const {
@ -1277,7 +1299,7 @@ class Expect: public Command {
QString description ( ) const {
return
tag ( ) + " <signal> [<parameter>] "
" \n \n "
" \n \n -- \n \n "
" Expect a signal. Signals are emitted by webkit and may contain "
" parameter. If a parameter is given in the script, then the parameter "
" must match exactly. If no parameter is given, then the signal must "
@ -1346,7 +1368,7 @@ class Open: public Command {
QString description ( ) const {
return
tag ( ) +
" \n \n "
" \n \n -- \n \n "
" Open the browser window, so you can follow the test steps visually. " ;
}
QString command ( ) const {
@ -1372,7 +1394,7 @@ class Sleep: public Command {
QString description ( ) const {
return
tag ( ) + " <seconds> "
" \n \n "
" \n \n -- \n \n "
" Sleep for a certain amount of seconds. This helps, if you must wait "
" for some javascript actions, i.e. AJAX or slow pages, and the "
" excpeted signals are not sufficient. " ;
@ -1410,7 +1432,7 @@ class Exit: public Command {
QString description ( ) const {
return
tag ( ) +
" \n \n "
" \n \n -- \n \n "
" Successfully terminate script immediately. The following commands "
" are not executed. This helps when you debug your scripts and you "
" want the script stop at a certain point for investigations. " ;
@ -1437,7 +1459,7 @@ class IgnoreTo: public Command {
QString description ( ) const {
return
tag ( ) + " <label> "
" \n \n "
" \n \n -- \n \n "
" Ignore all following commands up to a given label. The following "
" commands are not executed until the given label appears in the "
" script. This helps when you debug your scripts and you "
@ -1470,7 +1492,7 @@ class Label: public Command {
QString description ( ) const {
return
tag ( ) + " <label> "
" \n \n "
" \n \n -- \n \n "
" This marks the label refered by command \" ignoreto \" . " ;
}
QString command ( ) const {
@ -1500,7 +1522,7 @@ class Upload: public Command {
QString description ( ) const {
return
tag ( ) + " <selector> -> <filename> "
" \n \n "
" \n \n -- \n \n "
" Presses the specified file upload button and passes a given file "
" name. The command requires a CSS selector followed by a filename. "
" The first object that matches the selector is used. " ;
@ -1554,7 +1576,7 @@ class Exists: public Command {
QString description ( ) const {
return
tag ( ) + " <selector> -> <text> "
" \n \n "
" \n \n -- \n \n "
" Assert that a certain text exists in the selected object, or if no "
" text is given, assert that the specified object exists. The object "
" is given by a CSS selector. All matching objects are search for the "
@ -1610,7 +1632,7 @@ class Not: public Command {
QString description ( ) const {
return
tag ( ) + " <selector> -> <text> "
" \n \n "
" \n \n -- \n \n "
" Assert that a certain text does not exists in the selected object, "
" or if no text is given, assert that the specified object does not "
" exists. The object is given by a CSS selector. All matching objects "
@ -1659,7 +1681,7 @@ class Execute: public Command {
QString description ( ) const {
return
tag ( ) + " <command> \n <line1> \n <line2> \n <...> "
" \n \n "
" \n \n -- \n \n "
" Execute <command>. The command can have space separated arguments. "
" Following lines that are intended by at least "
" one space are streamed into the command. This way, you can e.g. "
@ -1726,7 +1748,7 @@ class Download: public Command {
return
tag ( ) + " <filename> \n "
" <command-to-start-download> "
" \n \n "
" \n \n -- \n \n "
" Set download file before loading a download link or clicking on a "
" download button. The next line must be exactly one command that "
" initiates the download. \n \n "
@ -1807,7 +1829,7 @@ class Click: public Command {
QString description ( ) const {
return
tag ( ) + " [<clicktype>] <selector> "
" \n \n "
" \n \n -- \n \n "
" Click on the specified element. Either you explicitely specify a click "
" type, such as <realmouse> or <javascript>, or the previously set or "
" the default clicktype is used. " ;
@ -1861,10 +1883,10 @@ class Set: public Command {
}
QString description ( ) const {
return
tag ( ) + " <variable>=<value> \n " +
tag ( ) + " <variable>=<value> \n \n " +
tag ( ) + " <variable> \n "
" <command> "
" \n \n "
" \n \n -- \n \n "
" Sets the value of a variable either to a constant, or to the output "
" of a command. A command should be a command that produces an "
" output, such as <do>, which returns the result of JavaScript or "
@ -1920,7 +1942,7 @@ class UnSet: public Command {
QString description ( ) const {
return
tag ( ) + " <variable> "
" \n \n "
" \n \n -- \n \n "
" Undo the setting of a variable. The opposite of «set». " ;
}
QString command ( ) const {
@ -1949,7 +1971,7 @@ class Timeout: public Command {
QString description ( ) const {
return
tag ( ) + " <seconds> "
" \n \n "
" \n \n -- \n \n "
" Set the timeout in seconds (defaults to 10). " ;
}
QString command ( ) const {
@ -1982,7 +2004,7 @@ class CaCertificate: public Command {
QString description ( ) const {
return
tag ( ) + " <filename.pem> "
" \n \n "
" \n \n -- \n \n "
" Load a CA certificate that will be accepted on SSL connections. " ;
}
QString command ( ) const {
@ -2018,7 +2040,7 @@ class ClientCertificate: public Command {
QString description ( ) const {
return
tag ( ) + " <certfile.pem> <keyfile.pem> <keypassword> "
" \n \n "
" \n \n -- \n \n "
" Load a client certificate to authenticate on SSL connections. "
" The password for the keyfile should not contain spaces. "
" Create the two files from a PKCS#12 file using OpenSSL: \n "
@ -2078,7 +2100,7 @@ class ClickType: public Command {
QString description ( ) const {
return
tag ( ) + " <type> "
" \n \n "
" \n \n -- \n \n "
" Set how mouseclicks should be mapped. The best solution depends on "
" your problem. Normally it is good to call \" click() \" on the element "
" using javascript. But with complex javascript infected websites, it "
@ -2122,9 +2144,9 @@ class SetValue: public Command {
}
QString description ( ) const {
return
tag ( ) + " <selector> -> '<value>' \n " +
tag ( ) + " <selector> -> '<value>' \n \n " +
tag ( ) + " <selector> -> '<value1>', '<value2>', <...> "
" \n \n "
" \n \n -- \n \n "
" Set the selected element to a given value. It is mostly the same as "
" the following constuct, except that options in a select are evaluated "
" correctly: \n \n "
@ -2191,7 +2213,7 @@ class Function: public CommandContainer {
" <command1> \n "
" <command2> \n "
" <...> "
" \n \n "
" \n \n -- \n \n "
" Define a function with arguments. The arguments are treated like "
" local variables. In a sequence of scripts within the same testrun, "
" functions are inherited from all followin scripts, so you can first "
@ -2241,7 +2263,7 @@ class Call: public Command {
QString description ( ) const {
return
tag ( ) + " <name> ['<arg1>', '<arg2>', ...] "
" \n \n "
" \n \n -- \n \n "
" Calls a function. The number of arguments must be exactly the same "
" as in the function definition. \n \n "
" If you quote the values, then quote all values with the same "
@ -2296,7 +2318,7 @@ class If: public CommandContainer {
" <command3> \n "
" <command4> \n "
" <...> \n "
" \n \n "
" \n \n -- \n \n "
" Execute commands conditionally. "
" The first variant compares a variable to a value. "
" The comparision <cmp> can be = ! . ^ ~ < >, "
@ -2408,7 +2430,7 @@ class While: public CommandContainer {
" <command1> \n "
" <command2> \n "
" <...> \n "
" \n \n "
" \n \n -- \n \n "
" Repeats commands conditionally. "
" The first variant compares a variable to a value. "
" The comparision <cmp> can be = ! . ^ ~ < >, "
@ -2501,7 +2523,7 @@ class TestSuite: public Command {
QString description ( ) const {
return
tag ( ) + " <name> "
" \n \n "
" \n \n -- \n \n "
" Start a testsuite and give it a name. " ;
}
QString command ( ) const {
@ -2530,7 +2552,7 @@ class TestCase: public Command {
QString description ( ) const {
return
tag ( ) + " <name> "
" \n \n "
" \n \n -- \n \n "
" Start a testcase and give it a name. " ;
}
QString command ( ) const {
@ -2558,10 +2580,10 @@ class Check: public Command {
}
QString description ( ) const {
return
tag ( ) + " <value1> <cmp> <value2> \n " +
tag ( ) + " <value1> <cmp> <value2> \n \n " +
tag ( ) + " <value1> <cmp> \n "
" <command> "
" \n \n "
" \n \n -- \n \n "
" Compares two values (you can use variables) or compares a value to the "
" result of a command. The command should be a command that produces an "
" output, such as <do>, which returns the result of JavaScript or "
@ -2644,7 +2666,7 @@ class For: public CommandContainer {
" <command1> \n "
" <command2> \n "
" <...> "
" \n \n "
" \n \n -- \n \n "
" Executes the given commands with the variable set to the specifier values, "
" repeated once per given value. The variable is treated like a local variale "
" in the loop. \n \n "
@ -2696,7 +2718,7 @@ class Echo: public Command {
QString description ( ) const {
return
tag ( ) + " <text> "
" \n \n "
" \n \n -- \n \n "
" Echoes a text to the log. " ;
}
QString command ( ) const {
@ -2725,7 +2747,7 @@ class OfflineStoragePath: public Command {
QString description ( ) const {
return
tag ( ) + " <path> "
" \n \n "
" \n \n -- \n \n "
" Set offline storage path. Defaults to /tmp. " ;
}
QString command ( ) const {
@ -2758,7 +2780,7 @@ class ClearCookies: public Command {
QString description ( ) const {
return
tag ( ) + " <url> "
" \n \n "
" \n \n -- \n \n "
" Clear all cookies of given URL <url>, or of the current URL if no "
" <url> is specified. " ;
}
@ -2794,7 +2816,7 @@ class Include: public CommandContainer {
QString description ( ) const {
return
tag ( ) + " <filename> "
" \n \n "
" \n \n -- \n \n "
" Include a test script. " ;
}
QString command ( ) const {
@ -2861,7 +2883,7 @@ class Case: public Command {
" <command> \n "
" <command> \n "
" <...> \n "
" \n \n "
" \n \n -- \n \n "
" Execute commands conditionally depending on a variable. "
" It is equivalent to neested if-else-if commands. "
" The first variant compares a variable to a value. "
@ -2981,7 +3003,7 @@ class Fail: public Command {
QString description ( ) const {
return
tag ( ) + " <text> "
" \n \n "
" \n \n -- \n \n "
" Fail with error text. " ;
}
QString command ( ) const {
@ -3012,7 +3034,7 @@ class Auth: public Command {
tag ( ) + " <realm> <username> <password> "
" \n \n " +
tag ( ) + " <realm> "
" \n \n "
" \n \n -- \n \n "
" Set basic authentication credentials for <realm> to "
" <username> and <password>. If no realm is given, "
" the credentials for the given realm are removed. " ;
@ -3054,7 +3076,7 @@ class Ignore: public Command {
QString description ( ) const {
return
tag ( ) + " <signal1> <signal2> <...> "
" \n \n "
" \n \n -- \n \n "
" Ignores a specific signal. It will not be placed in the queue "
" and any expect for this signal is always true. You can call "
" ignore with a space separated list of signal names. You cannot "
@ -3086,7 +3108,7 @@ class UnIgnore: public Command {
QString description ( ) const {
return
tag ( ) + " <signal1> <signal2> <...> "
" \n \n "
" \n \n -- \n \n "
" Undo ignoring a specific signal. It will be placed in the queue "
" and any expect this signal checks the queue. You can call "
" unignore with a space separated list of signal names. You cannot "
@ -3119,7 +3141,7 @@ class : public Command {
QString description ( ) const {
return
tag ( ) +
" \n \n "
" \n \n -- \n \n "
" " ;
}
QString command ( ) const {