-
Notifications
You must be signed in to change notification settings - Fork 2
Home
(NOTE: currently only a RAW copy of internal wiki. Will be updated asap.)
BBSeeker is a tool which allows searching bobril/bobwai components by their component ID, virtual DOM data or element attributes and returns their corresponding HTML element, data or attribuzes. It was created to allow QA Engineers to test Quadient Cloud solution.
BBSeeker is distributed as typescript, javascript, Node.js package or NET Core C# code.
It was implemented by Přemysl Šulc and is being used by Quadient componentarists. For more info about distribution, support nad features please contact Přemysl Šulc.
If needed, all sources needed for the Node.Js package build are present in the BBSeeker repository https://github.com/bobril/bb-seeker/tree/master/BBSeeker/src/BBSeeker/ts/npmPackages/BBSeekerExtension.
see section Usage in browser: BBSeeker - Chrome plugin
Bobril component ID is the same for all components of the same type (i.e. in a way it is similar to CSS classes). Bobril ID is usually found inside "component" object inside bobril object in a Bobril virtual DOM.
The recommended tool for inspecting Bobril virtual DOM is Clouseau made by V. Kleštinec. It is available as a free Chrome extension from the Chrome Web Store.
Or you can clone sources from https://github.com/klesta490/bobril-clouseau and add it as developer extension.
Usage is simple:
- Install the extension.
- Hit F12 to open Dev tools.
- Use "select an element in the page" tool to select any component.
- Open Bobril tab (made available by the instaleld extension) and expand component node.
Only component root node has a component ID. In some cases some older or custom made components do not have a Bobril ID.
ID of component created by merging two other components (eg. by using b.createDerivedComponent) consists of their IDs joined with slash. Since slash is level separator at search expressions it cannot be used as a part of id so BBSeeker replaces it with dash.
Example:
ComponentBase has id "base" and we are creating component SpecificComponent derived from definition having id "specific" and from ComponentBase. ID of SpecificComponent will be "base/specific" and for BBSeeker it is searchable as a "base-specific".
Main part of the tool is written in TypeScript and compiled to JavaScript. Raw and minified JavaScript is included in js folder inside BBSeeker package.
- Firstly, you have to add BBSeeker to the browser:
- It can be run directly in the browser console (copy&paste&Enter).
- Other ways include saving it as a js snippet to a browser (e.g. snippets in Google Chrome) which allows easier debugging.
- Newly added third option is to use BBSeeker AutoRunner extension for Google Chrome which will auto-inject BBSeeker to webpages based on Bobril (rule for injection is "window.b != undefined").
- Then you can call BBSeeker search function with a custom search expression parameter, e.g.:
BBSeeker.findElements(".bobwai--app-header-button/div[text=DASHBOARD]");
If you get "BBSeeker is not defined" error when calling the script, just rerun it (step 1) - make sure you are on Inspire Cloud pages (or any other bobril based application).
If "Spy translations" option is active, some functions with numbers may not work properly. E.g. bobwai--spinner component does not work correctly with decimal number. To confirm the bug try to deactivate the option first or confirm it in another browser.
Usage in a C# test project is very straightforward. BBSeeker package includes class WebDriverExtensions which extends Selenium IWebDriver with a few new methods. These methods serve as interfaces to inject and call BBSeeker script inside the webdriver.
To use the extension methods just add "using BBSeeker;" directive at the beginning of your test class, i.e. methods can be called like:
driver.FindElement(".bobwai--app-header-button/div[text=DASHBOARD]");c#Available Methods:true//Activates/deactivates indication of which texts can be translated. After activation the texts which can be translated are trapped between "[" and "]".
void spyTranslations(this IWebDriver driver, bool enable)
//Returns a list of IWebElements matching the "bbSeekerSearchExpression". ReadOnlyCollection FindElements(this IWebDriver driver, string bbSeekerSearchExpression);
//Waits up to a default timeout for elements to be available (returns as soon as the first match is found). //Throws TimeoutException if timeout is reached and nothing is found. ReadOnlyCollection FindElementsWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression)
//Waits up to a default timeout for elements to be available (returns as soon as the first match is found). //This variant uses custom timeout. //Throws TimeoutException if timeout is reached and nothing is found. ReadOnlyCollection FindElementsWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, uint timeout)
//Returns a single element matching the search expression or null if nothing is found. //Throws ApplicationException if multiple matches are present. IWebElement FindElement(this IWebDriver driver, string bbSeekerSearchExpression)
//Returns a single element matching the search expression. //Throws ApplicationException if multiple matches are present. //Throws TimeoutException if default timeout is reached. IWebElement FindElementWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression)
//Returns a single element matching the search expression. //Throws ApplicationException if multiple matches are present. //Throws TimeoutException if custom timeout is reached. IWebElement FindElementWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, uint timeout)
//Waits until element is not present on a page. //Throws TimeoutException if default timeout is reached. void WaitUntilElementIsNotPresent(this IWebDriver driver, string bbSeekerSearchExpression)
//Waits until element is not present on a page. //Throws TimeoutException if custom timeout is reached. void WaitUntilElementIsNotPresent(this IWebDriver driver, string bbSeekerSearchExpression, uint timeout)
//For given attribute name returns list of it's values. Size of the attribute list does match the size of matching collection of elements. //If element does not contain such attribute, null is returned instead. List GetAttributeList(this IWebDriver driver, string bbSeekerSearchExpression, string attributeName)
//For given data property name returns list of it's values. Size of the data list does match the size of matching collection of elements. //Will work for simple data types only. //If element does not contain such data, null is returned instead. List GetDataList(this IWebDriver driver, string bbSeekerSearchExpression, string attributeName)
//For given attribute name returns list of it's values. Size of the attribute list does match the size of matching collection of elements. //If element does not contain such attribute, null is returned instead. //Uses default BBSeeker timeout. List GetAttributeListWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string attributeName)
//For given attribute name returns list of it's values. Size of the attribute list does match the size of matching collection of elements. //If element does not contain such attribute, null is returned instead. //Uses custom timeout. List GetAttributeListWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string attributeName, uint timeout)
//For given data property name returns list of it's values. Size of the data list does match the size of matching collection of elements. //Will work for simple data types only. //If element does not contain such data, null is returned instead. //Uses default BBSeeker timeout. List GetDataListWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string dataName)
//For given data property name returns list of it's values. Size of the data list does match the size of matching collection of elements. //Will work for simple data types only. //If element does not contain such data, null is returned instead. //Uses custom timeout. List GetDataListWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string dataName, uint timeout)
//Returns a single attribute value matching the search expression and attribute name or null if nothing is found. //Throws ApplicationException if multiple matches are present. string GetAttribute(this IWebDriver driver, string bbSeekerSearchExpression, string attributeName)
//Returns a single data value matching the search expression and data property name or null if nothing is found. Will work for simple data types only. //Throws ApplicationException if multiple matches are present. string GetData(this IWebDriver driver, string bbSeekerSearchExpression, string dataName)
//Returns a single attribute value matching the search expression and attribute name or null if nothing is found. //Throws ApplicationException if multiple matches are present. //Uses default BBSeeker timeout. string GetAttributeWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string attributeName)
//Returns a single attribute value matching the search expression and attribute name or null if nothing is found. //Throws ApplicationException if multiple matches are present. //Uses custom timeout. string GetAttributeWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string attributeName, uint timeout)
//Returns a single data value matching the search expression and data property name or null if nothing is found. Will work for simple data types only. //Throws ApplicationException if multiple matches are present. //Uses default BBSeeker timeout. string GetDataWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string dataName)
//Returns a single data value matching the search expression and data property name or null if nothing is found. Will work for simple data types only. //Throws ApplicationException if multiple matches are present. //Uses custom timeout. string GetDataWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string dataName, uint timeout)
//Finds element matching the expression, extracts value of a property in ctx and returns it. string GetCtx(string bbSeekerSearchExpression, string ctxPropertyName)
//Finds all elements matching the expression, extracts context property value and returns it in a list. List GetCtxList(string bbSeekerSearchExpression, string ctxPropertyName)
//Finds element matching the expression, extracts value of a property in ctx and returns it. string GetCtxWithTimeout(string bbSeekerSearchExpression, string ctxPropertyName, uint timeout)
//Finds all elements matching the expression, extracts context property value and returns it in a list. List GetCtxListWithTimeout(string bbSeekerSearchExpression, string ctxPropertyName, uint timeout)
// [since 2.3.1] experimental feature, requires compatible bobwai component, more info: Lukáš Najman //Finds element matching the expression and attempts to extract value of ctx.fileInput property as instance of IWebElement. IWebElement GetFileInput(string bbSeekerSearchExpression, string ctxPropertyName)
// [since 2.3.1] experimental feature, requires compatible bobwai component, more info: Lukáš Najman //Finds all elements matching the expression, extracts cxt.fileInput property value as IWebElement and returns it in a list. List GetFileInputList(string bbSeekerSearchExpression, string ctxPropertyName)
// [since 2.3.1] experimental feature, requires compatible bobwai component, more info: Lukáš Najman //Finds element matching the expression and attempts to extract value of ctx.fileInput property as instance of IWebElement. IWebElement FileInputWithTimeout(string bbSeekerSearchExpression, string ctxPropertyName, uint timeout)
// [since 2.3.1] experimental feature, requires compatible bobwai component, more info: Lukáš Najman //Finds all elements matching the expression, extracts cxt.fileInput property value as IWebElement and returns it in a list. List FileInputListWithTimeout(string bbSeekerSearchExpression, string ctxPropertyName, uint timeout)
// [since 2.4.1] Finds element matching the expression, extracts property value and returns it. string GetProperty(this IWebDriver driver, string bbSeekerSearchExpression, string propertyPat
// [since 2.4.1] Finds element matching the expression, extracts property value and returns it. string GetPropertyWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string propertyPath)
// [since 2.4.1] Finds all elements matching the expression, extracts property value and returns it in a list. List GetPropertyList(this IWebDriver driver, string bbSeekerSearchExpression, string propertyPath)
// [since 2.4.1] Finds all elements matching the expression, extracts property value and returns it in a list. List GetPropertyListWithTimeout(this IWebDriver driver, string bbSeekerSearchExpression, string propertyPath, uint timeout)
// [since 1.7.1] Returns position of the last click in the browser viewport. // REQUIRES that any BBSeeker search method is executed before this so that BBSeeker is injected (only clicks after BBSeeker injection are detected). public static Point GetLastClickPosition(this IWebDriver driver) ]]></ac:plain-text-body></ac:structured-macro>
C# methods use minified script version by default (chrome driver had issues with raw version). If needed BBSeeker can be instructed to use raw version by setting: BBSeekerScript.UseMinified = false;
Ability to select custom search root was added in BBSeeker 1.6.0. All above mentioned methods now accept HTML element as custom root for search (i.e. only DOM of this element will be searched for results). Custom root can be specified as the last optional parameter of these methods.
This means you can for example find popup DIV in the first search and then reuse the found element as the root in the following queries to find inputs, buttons and other elements inside the said popup.
BBSeeker search expressions consist of a several parts and can be chained to form parent => child search sequence.
Tag or Bobril ID is mandatory part of an expression on each level. For example you have to use "input" tag if you want input elements on a page or ".bobwai--app-header-button" if you want elements with Bobril ID "bobwai--app-header-button".
Since version 1.7.0 there is also possibility to search by Bobril "key" property using '#' character in the expression syntax.
- You can also use "*" character as a mask. Mask will match any tag so it can be useful in some scenarios (e.g. any tag matching some filter inside a parent element).
- Tag and ID can be combined on the same level if needed, see next section.
Mask can't be used for Bobril ID so div.* will not work.
Character "." is a mandatory prefix for Bobril ID (since 1.3.0) and also serves as a separator between HTML tag and Bobril ID, e.g.:
div.bobwai--app-header-button = any "div" tag with Bobril ID "bobwai--app-header-button".
Tag is in this case optional and can be usually ommited so simply ".bobwai--app-header-button" would return the same result.
Character "#" is a mandatory prefix for Bobril "key" property matching (since 1.7.0) and also serves as a separator between HTML tag and Bobril "key", e.g.:
div#your-key = any "div" tag with Bobril "key" property value "your-key".
Search by key also supports substring search using mask character "*" which is equivalent to 0-N characters, e.g.:
#*aaa*bbb*ccc = any element with Bobril "key" containing "aaa" substring followed by "bbb" and which is ending with "ccc", so for example "myaaakeybbbsearchccc" will match.
Character "/" serves as a level separator between parent and child element, e.g.:
.bobwai--table/tbody = means "tbody" element inside element with Bobril ID "bobwai--table".
Character "~" means that searched child does not have to be a direct child, i.e. searched element is somewhere inside a tree where parent is a root element, e.g.:
.bobwai--l-field/~input = means input "somewhere" inside parent element with Bobril ID "bobwai--l-field".
Character "^" selects a parent of an element. It has to be used alone instead of a tag/Bobril ID and does not support any filtering, e.g.:
.bobwai--l-field/^/^ = means parent of a parent of the element with Bobril ID "bobwai--l-field".
Since 2.4.2 there is also an option to combine parent selector with a standard selector. This results in BBSeeker attempting to find the nearest parent that match the specified standard selector, e.g.:
.bobwai--label[$content=Companies]/^.bobwai--l-field/~.bobwai–combobox = should find label with "Companies" content, then select the nearest parent bobwai--l-field parent, and from there select a nested child combobox.
Parent selector combined with standard selector to find the nearest matching parent should work in most of the cases since it is internally using the same code to match the parent as the rest of the BBSeeker.
But the feature was not extensively tested since the amount of possible combinations is too large. Please report any bugs or unexpected behaviour to Hynek Hladik (I will try to either fix the issue or add it as a limitation here).
Allows to select sibling selection.
Supported since 1.6.1This functionality was added in BBSeeker version 1.6.1
Selector ">>" allows selection of the next sibling of the current element, e.g.:
.bobwai--l-field/>> = sibling directly following the element with Bobril ID "bobwai--l-field".
You can also specify custom offset counted from the position of the current element, i.e. 0 is current element, 1 is the first sibling, 2 is the second sibling, etc.:
.bobwai--l-field/>3> = means the third sibling of the element with Bobril ID "bobwai--l-field".
Selector "<<" allows selection of the previous sibling of the current element, e.g.:
.bobwai--l-field/<< = sibling directly preceding the element with Bobril ID "bobwai--l-field".
You can also specify custom offset counted from the position of the current element, i.e. 0 is current element, 1 is the previous sibling, 2 is a sibling preceding the previous sibling, etc.:
.bobwai--l-field/<2< = means the second sibling before the element with Bobril ID "bobwai--l-field".
Custom offsetCustom offset does support only positive integers. Zero, negative numbers, non-integers, etc. will result either in empty results or errors.
Filters can be added directly behind tag (if Bobril ID is not used) or behind Bobril ID as a pair of square brackets "[...]" where "..." are one of the filter types. Filter is applied on a level where it is declared, e.g.
.bobwai--l-field[0]/~input = means "input" elements inside the first "bobwai--l-field".
Simply a number in a square brackets, e.g div[2]. It is applied after all matches from the current level are returned, i.e. array is trimmed to a single value specified by an index.
You can also select the last element by using "last()" instead of an index, e.g. div[last()] if you want last div, or div[last()-1] if you want second div from the end.
Number prefixed by ":" in a square brackets, e.g tr/td[:2] will return every 3rd cell from each row on the page.
Unlike "Index Filter", child index filter can be combined with other filters on the same search expression level.
When combining child index filter with other filters, it is very IMPORTANT to keep in mind that context of the filter is related to resultset of the used filters, e.g.:
table/~td[@textContent~Text]and[:0] will return the first cell with text "Text" from each table.
You can also use "last()" keyword and It's "last()-x" variant where "x" is offset from the last element, e.g.:
table/~tr/td[:last()] will return the last cell from each row from of any table,
table/~tr/td[:last()-2] will return the 3rd cell from the end from each row of any table.
String comparison - can be used for text children, element attributes and bobril data (see sections ):
- "=" is strict (i.e. exact) match operator, e.g. div[text=DASHBOARD] will match any div with a text child "DASHBOARD".
- "~" is non-strict (i.e. contains) operator, e.g. div[text~DASHBOARD] will match any div with a text child having substring "DASHBOARD".
- "*=" is "starts with" operator, e.g. div[text*=DASHBOARD] will match any div with a text child starting with substring "DASHBOARD".
- "^=" is "ends with" operator, e.g. div[text^=DASHBOARD] will match any div with a text child ending with substring "DASHBOARD".
String comparison limitations:
- String comparison is case-sensitive only.
Filter starting with string "text=" immediately followed by matched text is a strict variant requiring exact match, e.g.:
.bobwai--app-header/~div[text=DASHBOARD] = any "div" with text "DASHBOARD" somewhere inside "bobwai--app-header".
Filter starting with string "text~" immediately followed by matched text is a contains variant which matches substring, e.g.:
div[text~USER] = any "div" whose text contains substring "USER".
Filter starting with "@" character followed by an attribute name "=" character and attribute value, e.g.:
input[@placeholder=Current Password] = any input with "placeholder" attribute and atribute value "Current Password".
Filter starting with "$" character followed by a data variable name "=" character and variable value, e.g.:
.bobwai--sidebar-item-collapsible[$isExpanded=true] = any component with Bobril ID ".bobwai--sidebar-item-collapsible" and data variable named "isExpanded" with value "true" (sample below).
Since BBSeeker 1.3.5 you can join two or more filters using "and", e.g.
div[text~Hello]and[text~World!] = any divs which contain text with substrings "Hello" and "World".
Filter combination with Index filter is not supportedMost of the filters can be combined, exception is an index filter which is unsupported at this time.