Skip to content

Latest commit

 

History

History
125 lines (88 loc) · 14.6 KB

EnhancedSelenese.md

File metadata and controls

125 lines (88 loc) · 14.6 KB
title layout
(syntax)
default

{% include links %}

  • TOC {:toc}

Overview

When compared to ClassicSelenese, automation scripts with SeLite are shorter and clearer. [SelBlocks Global] enhances syntax of ClassicSelenese > Selenese parameters target and value. It allows those expressions to

  • conveniently access
    • stored variables through $storedVariableName notation and
    • any fields/subfields/methods on stored variables. E.g. $object-var-name.fieldXYZ, $object.method(...) or $array-var-name[index]
  • use Javascript within <>...<>

$storedVariableName notation

This syntax enables Selenese commands and structures that evaluate their parameter(s) as Javascript to access stored variables as $storedVariableName. It's for

  • Javascript within <>...<> (and its variations) and
  • [SelBlocks Global] structured commands that evaluate one or both of their parameters as Javascript. The commands and their parameters that support this are
  • target parameter of:
    • getEval (and its auto-generated variations as per {{navAutoGeneratedSeleneseCommands}}),
    • promise, storePromise
    • skipNext, gotoIf, if, elseIf, throw, catch, while, for, continue, break, return
  • value parameter of:
    • forEach, forIterator, forIterable, loadJsonVars, loadXmlVars
    • call - only on right side of function parameter assignments

See also [SelBlocks Global] > Accessing stored variables.

If you need to pass '$' (a dollar as a string constant) to any of the above Selenese commands, use String.fromCharCode(36).

Javascript within <>...<>

{:#javascript-within} This notation allows you to pass results of one or multiple Javascript expressions (each enclosed within a pair of <>...<>) to Selenese commands in their parameter (target or value). It evaluates any Javascript code in target or value that is between any pair of <>...<> (excluding the pair of <> itself).

This is similar to standard Selenese javascript{...} as per Selenium IDE > JavaScript Usage with Non-Script Parameters. However, javascript{...} must have no prefix/postfix - i.e. it must be the only content of a Selenese command's parameter (target or value). Hence, there can't be multiple occurrences of javascript{...} in the same Selenese parameter.

<>...<> without special prefix (cast to a string)

{:#without-special-prefix} This converts the evaluated result to a string. You can have any prefix or suffix around <>...<>. The whole Selenese parameter (target or value) is treated as a string. Results of Javascript codes from <>...<> are concatenated together with any prefix, interlacing strings and any suffix.

Variations of Javascript within <>...<> with special prefixes

Following are variations of <>...<> syntax. They all treat the string between the pair of <>...<> as a Javascript expression. However, they treat the result in a special way, or they apply extra transformation to it.

They all start with special characters =, <> or @ immediately in front of the opening pair of <>. Those characters =, <> and @ are only a part of the syntax; they are not included in the result that is passed to the Selenese command.

=<>...<> (with preserved type)

{:#with-preserved-type} If a Selenese parameter contains only one =<>...<> with no prefix and no suffix (not even a space), then its result is not treated as a string. [SelBlocks Global] preserves the type of result of Javascript expression within <>...<> and it passes the exact result as a Selenese parameter. That's useful if you want to pass a number, an object or an array (and it still works for strings). If there is any prefix or suffix, [SelBlocks Global] reports an error.

If a Selenese command supports (or requires) an object passed this way, then do not invoke that Selenese command with an extra parameter passed through @<>...<>.

\<>...<> (a string literal/constant in XPath)

{:#a-string-literalconstant-in-xpath}

<>...<> is like <>...<>, but it quotes and escapes its result as string literal/constant for XPath expression. You can have multiple occurrences of <>...<> in the same Selenese parameter, with any prefix/suffix and interlacing strings, and you can mix them with basic <>...<>.

Like <>...<> without prefix, <>...<> evaluates the enclosed part as Javascript expression. The result is treated as content of a string literal/constant for XPath. Then this escapes both apostrophes and/or quotation marks in it. It generates an XPath string sub-expression that may use XPath function concat(). (For details see quoteForXPath() in Selenium Core's online htmlutils.js or offline at {{chromeUrl}} chrome://selenium-ide/content/selenium-core/scripts/htmlutils.js).

Due to a bug in Selenium IDE, you need to put two backslashes in the edit field for that cell. Please vote for ThirdPartyIssues > Backslashes get reduced to half.

@<>...<> (an extra Selenese parameter)

{:#an-extra-selenese-parameter} By default, Selenium IDE allows to pass only two parameters to commands: target (usually a locator) and value. However, some SeLite commands (e.g. in [Exit Confirmation Checker]) need to receive extra one or two parameters. [SelBlocks Global] enhances syntax by allowing value of each standard Selenese parameter (target or value) to include one occurrence of @<>...<> containing a Javascript expression.

This notation extracts and completely removes that @<>...<> from the parameter. It concatenates the rest (any prefix merged with any suffix) for the string value (potentially empty) of that Selenese parameter (target or value). It transforms that value into a String object (rather than a string primitive). Then it evaluates the Javascript from within @<>...<> (the part that it extracted and removed). It stores the result as an extra (optional) field seLiteExtra on that String object (one made from any prefix and suffix). Then it passes the result String object to the called action as the actual value of the intended Selenese parameter (either target or value).

The Selenese command (i.e. a custom command or a custom override/intercept of standard Selenese) can access the result of Javascript through field seLiteExtra if it is set on the parameter. Using @<>...<> makes the command receive instance of String object rather than a primitive string. That will work with most use cases of primitive strings. Hence this mechanism is mostly forward compatible.

Compatibility with ClassicSelenese

<>...$storedVariableName...<> works. It translates to <>...storedVars.storedVariableName...<>. The javascript expression will be valid or invalid regardless of type of stored variable with name storedVariableName.

However, <>...${storedVariableName}...<> (as per ClassicSelenese > Stored variables) doesn't work. Side note: We don't want this second form anyway, because ${storedVariableName} works through brute string substitution. It could cause unexpected Javascript errors. E.g. when developing the script, ${variableName} could be a number. However, later it could become a non-numeric string. If there were no quotes/apostrophes around it, an the Javascript expression would expect a number, it would fail. Also, it would need extra handling of strings containing apostrophes/quotes. Indeed, ${storedVariableName} works in any prefix/suffix of <>...<> (as per standard Selenese).

Limitations

Same limitations apply as per ClassicSelenese > limitations of getEval and its derivatives.

Special rules on using =<>...<> or @<>...<>

{:#special-rules-on-using}

Passing (sub)string <> verbatim

To pass actual text <> to Selenium, generate it from an expression. For example, pass <>'<' + '>'<>. See SelBlocksGlobal/selenese-scripts/misc_case.html.

This applies to any target or value, whether they contain <>...<> or not. (Also in prefix or suffix of <>...<> or in Javascript within <>...<>). That includes contents of Javascript string literals (within '...' or "...") passed to classic getEval (and actions generated from it, as per {{navAutoGeneratedSeleneseCommands}}).

As a result, with [SelBlocks Global], any valid Selenese parameter can't contain an odd number of <> pairs.

For script maintainers and framework developers

A simple rule is: Don't pass =<>...<> or @<>...<> to getEval or to custom commands that evaluate values of their Selenese parameters (target or value) as Javascript expression(s), unless those commands are designed for it. The same applies to derivative commands like storeEval (as per {{navAutoGeneratedSeleneseCommands}}).

Alternatively, if you'd really like to pass the string value of this object as a parameter to command getEval (or storeEval...), which would then evaluate it as a Javascript expression (again), use <>...<> instead.

For developers of custom commands

If you develop Selenese commands that may be used with =<>...<> or @<>...<> then:

  1. Do not compare the values of standard Selenese parameters (target and value) using strict comparison operators === and !==. Also, don't depend on their typeof, which will be object rather than string if the passed parameter uses =<>...<> or @<>...<>... If you'd like to use strict comparison or typeof with such a parameter, transform it to a string (see rule #4 below).
  2. If the command doesn't need <>...<> syntax, the user shouldn't pass an object (i.e. =<>...<> with no prefix and no suffix, or @<>...<> with any prefix/postfix). If typeof(first_or_second_parameter_name)==='object' then make it fail. See Selenium.prototype.preprocessParameter and Selenium.prototype.getEval online in selblocks.js or offline at {{chromeUrl}} chrome://selite-selblocks-global/content/extensions/selblocks.js.
  3. If the command allows (or requires) a parameter to be an object (i.e. passed through =<>...<> with no prefix and no suffix), then prevent it to be passed through @<>...<> by mistake. If typeof first_or_second_parameter_name==='object' && 'seLiteExtra' in first_or_second_parameter_name then make it fail. See Selenium.prototype.doCall online in selblocks.js or offline at {{chromeUrl}} chrome://selite-selblocks-global/content/extensions/selblocks.js.
  4. If you implement a Selenese command that evaluates any of its parameters (target or value) as Javascript and you also want it to work with @<>...<>, then in the definition of the command
  • get field seLiteExtra from the parameter and store it for later use (if needed), e.g. var seLiteExtra=target.seLiteExtra;
  • transform the parameter to a primitive string, e.g. target=''+target; and only then pass it to eval().

(See also Mozilla's documentation of String object > Distinction between string primitives and String objects.)

Alternatives in classic Selenese

Selenium IDE supports access to stored variables via ${xyz} syntax. (Implementation note: it is handled by preprocessParameter().)

Alternatively, you may use shorthand javascript{...} - see Selenium IDE docs > JavaScript Usage with Non-Script Parameters. However, those Javascript expressions don't support classic ${storedVariableName} shorthand.

Also, you may call getEval as storeEval, which stores the evaluated result of target parameter in a Selenese stored variable that is named in value parameter. E.g. if value parameter is xyz, then you can access the result as ${xyz}. However, <>...<> syntax operates at level different than getEval. So, in general you can't just copy any expression between <>...<> and getEval (it works for some expressions, but not for others).

Without <>...<> you'd need either to

  • create more complex Javascript expressions and pass them through Selenese javascript{...}. They'd have to access stored variables via storedVars. Such expressions are more wordy and less intuitive.
  • pass the expression(s) through storeEval to save the result into a temporary variable. Then pass that stored variable as ${xyz} to the further command(s). That makes your script longer. The unnecessary variables make it less clear and more fragile.

Summary of accessing stored variables in Selenese

  • Use storedVars.variableName with getEval and related commands.
  • Only use $variableName with commands from [SelBlocks Global].
  • Use ${variableName} or <>$variableName<> with any other Selenese commands.
  • Keep javascript{...} for special purposes. See online Selenium Core reference > Parameter construction and Variables or offline at {{chromeUrl}} chrome://selenium-ide/content/selenium-core/reference.html#parameter-construction-and-variables. Use this notation with e.g. window.opener.resizeTo() and window.opener.innerWidth.