diff --git a/AngularJSLibrary/__init__.py b/AngularJSLibrary/__init__.py index 0bc329b..965b2e9 100644 --- a/AngularJSLibrary/__init__.py +++ b/AngularJSLibrary/__init__.py @@ -5,7 +5,10 @@ from selenium.common.exceptions import TimeoutException from SeleniumLibrary.locators import ElementFinder -from exceptions import AttributeError +try: + from exceptions import AttributeError +except ImportError: + pass import time js_wait_for_angularjs = """ @@ -26,7 +29,7 @@ var callback = function () {waiting = false;} var el = document.querySelector(arguments[0]); if (!el) { - throw new Error('Unable to find root selector using "' + + throw new Error('Unable to find root selector that is given by importing the library using "' + arguments[0] + '". Please refer to the AngularJS library documentation' + ' for more information on how to resolve this error.') @@ -166,7 +169,7 @@ def _sldriver(self): class AngularJSLibrary: ROBOT_LIBRARY_SCOPE = 'GLOBAL' - ROBOT_LIBRARY_VERSION = '0.0.10dev1' + ROBOT_LIBRARY_VERSION = '0.0.11dev1' def __init__(self, root_selector=None, @@ -179,9 +182,9 @@ def __init__(self, For more information please refer to the following documentation: - $rootElement - [https://docs.angularjs.org/api/ng/service/$rootElement|AngularJS API documentation] + $rootElement - [https://code.angularjs.org/snapshot-stable/docs/api/ng/service/$rootElement|AngularJS API documentation] - ngApp - [https://docs.angularjs.org/api/ng/directive/ngApp|AngularJS API documentation] + ngApp - [https://code.angularjs.org/snapshot-stable/docs/api/ng/directive/ngApp|AngularJS API documentation] Not Yet Implemented - ``implicit_angular_wait`` is the implicit timeout that AngularJS library waits for angular to finish rendering and waits for any outstanding $http calls. diff --git a/AngularJSLibrary/angular_wait.robot b/AngularJSLibrary/angular_wait.robot index 725fdd1..303bdca 100644 --- a/AngularJSLibrary/angular_wait.robot +++ b/AngularJSLibrary/angular_wait.robot @@ -1,118 +1,143 @@ *** Settings *** -Test Setup Go To http://${SERVER}/testapp/ng1/alt_root_index.html#/async +Suite Setup Go To Async Page and Wait +Test Setup Go To Async Page and Wait Resource ../resource.robot Library AngularJSLibrary +Documentation This test suite for validating the waiting for angular functionality +... Based off of protractor\spec\basic\synchronize_spec.js + *** Test Cases *** Waits For Http Calls [Documentation] `Wait For Angular` should delay for 2 seconds. - Wait For Angular Element Text Should Be binding=slowHttpStatus not started - Click Button css=[ng-click="slowHttp()"] Wait For Angular timeout=20sec + + Element Text Should Be binding=slowHttpStatus done + +Implicitly Waits For Http Calls + [Documentation] Second `Element Text Should Be` (done) should delay for 2 seconds. + Element Text Should Be binding=slowHttpStatus not started + Click Button css=[ng-click="slowHttp()"] Element Text Should Be binding=slowHttpStatus done +Implicitly Waits For Http Calls (without Binding locators) + [Documentation] Second `Element Text Should Be` (done) should delay for 2 seconds. + Element Text Should Be css=[ng-bind="slowHttpStatus"] not started + Click Button css=[ng-click="slowHttp()"] + Element Text Should Be css=[ng-bind="slowHttpStatus"] done + Waits For Long Javascript Execution [Documentation] This test will take variable amount of time but should not ... take more than about five seconds. - Wait For Angular Element Text Should Be binding=slowFunctionStatus not started - Click Button css=[ng-click="slowFunction()"] Wait For Angular + Element Text Should Be binding=slowFunctionStatus done +Implicitly Waits For Long Javascript Execution + [Documentation] This test will take variable amount of time but should not + ... take more than about five seconds. + + Element Text Should Be css=[ng-bind="slowFunctionStatus"] not started + Click Button css=[ng-click="slowFunction()"] + Element Text Should Be css=[ng-bind="slowFunctionStatus"] done + DOES NOT wait for timeout [Documentation] The `Wait For Angular` keyword should return immediately ... and not wait for a javascript timeout. - Wait For Angular Element Text Should Be binding=slowTimeoutStatus not started - Click Button css=[ng-click="slowTimeout()"] Wait For Angular + Element Text Should Be binding=slowTimeoutStatus pending... +Implicitly DOES NOT wait for timeout + [Documentation] The second `Element Text Should Be` keyword (pending...) + ... should return immediately and not wait for a javascript timeout. + Element Text Should Be css=[ng-bind="slowTimeoutStatus"] not started + Click Button css=[ng-click="slowTimeout()"] + Element Text Should Be css=[ng-bind="slowTimeoutStatus"] pending... + Waits For $timeout - [Documentation] Test should take around 4 seconds. - Wait For Angular + [Documentation] `Wait For Angular` should delay for 4 seconds. Element Text Should Be binding=slowAngularTimeoutStatus not started - Click Button css=[ng-click="slowAngularTimeout()"] Wait For Angular timeout=30sec + Element Text Should Be binding=slowAngularTimeoutStatus done +Implicitly Waits For $timeout + [Documentation] Second `Element Text Should Be` (done) should delay for 4 seconds. + Element Text Should Be css=[ng-bind="slowAngularTimeoutStatus"] not started + Click Button css=[ng-click="slowAngularTimeout()"] + Element Text Should Be css=[ng-bind="slowAngularTimeoutStatus"] done + Waits For $timeout Then A Promise - [Documentation] Test should take around 4 seconds. - Wait For Angular + [Documentation] `Wait For Angular` should delay for around 4 seconds. Element Text Should Be binding=slowAngularTimeoutPromiseStatus not started - Click Button css=[ng-click="slowAngularTimeoutPromise()"] Wait For Angular timeout=30sec + Element Text Should Be binding=slowAngularTimeoutPromiseStatus done +Implicitly Waits For $timeout Then A Promise + [Documentation] Second `Element Text Should Be` (done) should delay for around 4 seconds. + Element Text Should Be css=[ng-bind="slowAngularTimeoutPromiseStatus"] not started + Click Button css=[ng-click="slowAngularTimeoutPromise()"] + Element Text Should Be css=[ng-bind="slowAngularTimeoutPromiseStatus"] done + Waits For Long Http Call Then A Promise [Documentation] `Wait For Angular` should delay for 2 seconds. - Wait For Angular Element Text Should Be binding=slowHttpPromiseStatus not started - Click Button css=[ng-click="slowHttpPromise()"] Wait For Angular timeout=30sec + Element Text Should Be binding=slowHttpPromiseStatus done +Implicitly Waits For Long Http Call Then A Promise + [Documentation] Second `Element Text Should Be` (done) should delay for 2 seconds. + Element Text Should Be css=[ng-bind="slowHttpPromiseStatus"] not started + Click Button css=[ng-click="slowHttpPromise()"] + Element Text Should Be css=[ng-bind="slowHttpPromiseStatus"] done + Waits For Slow Routing Changes - Wait For Angular + [Documentation] `Wait For Angular` should delay for around 5 seconds. Element Text Should Be binding=routingChangeStatus not started - Click Button css=[ng-click="routingChange()"] Wait For Angular timeout=30sec + + Page Should Contain polling mechanism + +Implicitly Waits For Slow Routing Changes + [Documentation] Second `Element Text Should Be` (done) should delay for around 5 seconds. + Element Text Should Be binding=routingChangeStatus not started + Click Button css=[ng-click="routingChange()"] Page Should Contain polling mechanism Waits For Slow Ng-Include Templates To Load - Wait For Angular + [Documentation] `Wait For Angular` should delay for around 2 seconds. Element Text Should Be css=.included fast template contents - Click Button css=[ng-click="changeTemplateUrl()"] Wait For Angular timeout=30sec + Element Text Should Be css=.included slow template contents -Wait Times Out - Wait For Angular - Element Text Should Be binding=slowAngularTimeoutStatus not started - - Click Button css=[ng-click="slowAngularTimeout()"] - - Run Keyword And Expect Error * Wait For Angular timeout=1sec - -Log Pending Http Calls - Wait For Angular - Element Text Should Be binding=slowHttpPromiseStatus not started - - Click Button css=[ng-click="slowHttpPromise()"] - - Run Keyword And Expect Error * Wait For Angular timeout=1sec - -Implicit Wait For Angular On Timeout - Wait For Angular - - Click Button css=[ng-click="slowAngularTimeout()"] - - Click Button css=[ng-click="slowAngularTimeoutHideButton()"] - -Implicit Wait For Angular On Timeout With Promise - Wait For Angular - - Click Button css=[ng-click="slowAngularTimeoutPromise()"] - - Click Button css=[ng-click="slowAngularTimeoutPromiseHideButton()"] +Implicitly Waits For Slow Ng-Include Templates To Load + [Documentation] Second `Element Text Should Be` (done) should delay for around 2 seconds. + Element Text Should Be css=.included fast template contents + Click Button css=[ng-click="changeTemplateUrl()"] + Element Text Should Be css=.included slow template contents Toggle Implicit Wait For Angular Flag Element Should Not Be Visible css=[ng-click="slowAngularTimeoutHideButton()"] @@ -134,4 +159,9 @@ Toggle Implicit Wait For Angular Flag Click Button css=[ng-click="slowAngularTimeoutHideButton()"] - Element Should Not Be Visible css=[ng-click="slowAngularTimeoutHideButton()"] \ No newline at end of file + Element Should Not Be Visible css=[ng-click="slowAngularTimeoutHideButton()"] + +*** Keywords *** +Go To Async Page and Wait + Go To http://${SERVER}/testapp/ng1/alt_root_index.html#/async + Wait For Angular \ No newline at end of file diff --git a/AngularJSLibrary/demo_ngcdk_dialog.robot b/AngularJSLibrary/demo_ngcdk_dialog.robot new file mode 100644 index 0000000..59c8ba0 --- /dev/null +++ b/AngularJSLibrary/demo_ngcdk_dialog.robot @@ -0,0 +1,12 @@ +*** Settings *** +Library SeleniumLibrary +Library AngularJSLibrary root_selector=material-docs-app + +*** Test Cases *** +Add Favorite Animal To Dialog + Open Browser https://material.angular.io/cdk/dialog/examples Chrome + Input Text //input[@for='dialog-user-name'] Robot Framework + Click Button Pick one + Input Text //input[@for='favorite-animal'] Aibo + Click Button OK + Element Text Should Be //cdk-dialog-overview-example/ol/li[3] You chose: Aibo \ No newline at end of file diff --git a/AngularJSLibrary/demo_phonecat.robot b/AngularJSLibrary/demo_phonecat.robot new file mode 100644 index 0000000..8ce76eb --- /dev/null +++ b/AngularJSLibrary/demo_phonecat.robot @@ -0,0 +1,10 @@ +*** Settings *** +Library SeleniumLibrary +Library AngularJSLibrary root_selector=[ng-app] + +*** Test Cases *** +Search Through The Phone Catalog For Samsung Phones + Open Browser http://angular.github.io/angular-phonecat/step-14/app Chrome + Input Text //input Samsung + Click Link Samsung Galaxy Tab™ + Element Text Should Be css:phone-detail h1 Samsung Galaxy Tab™ \ No newline at end of file diff --git a/AngularJSLibrary/demo_waitforangular.robot b/AngularJSLibrary/demo_waitforangular.robot new file mode 100644 index 0000000..b799e84 --- /dev/null +++ b/AngularJSLibrary/demo_waitforangular.robot @@ -0,0 +1,13 @@ +*** Settings *** +Library SeleniumLibrary +Library AngularJSLibrary ignore_implicit_angular_wait=True + +*** Test Cases *** +Search Through The Phone Catalog For Samsung Phones + Open Browser http://angular.github.io/angular-phonecat/step-14/app Chrome + Wait For Angular + Input Text //input Samsung + Wait For Angular + Click Link Samsung Galaxy Tab™ + Wait For Angular + Element Text Should Be css:phone-detail h1 Samsung Galaxy Tab™ \ No newline at end of file diff --git a/AngularJSLibrary/test_angular2.robot b/AngularJSLibrary/test_angular2.robot index a6ca1a7..1a74669 100644 --- a/AngularJSLibrary/test_angular2.robot +++ b/AngularJSLibrary/test_angular2.robot @@ -1,5 +1,5 @@ *** Settings *** -Library Selenium2Library +Library SeleniumLibrary Library AngularJSLibrary *** Test Case *** diff --git a/AngularJSLibrary/testserver.py.patch b/AngularJSLibrary/testserver.py.patch index 35255fa..8aa66b0 100644 --- a/AngularJSLibrary/testserver.py.patch +++ b/AngularJSLibrary/testserver.py.patch @@ -1,23 +1,23 @@ diff --git a/atest/resources/testserver/testserver.py b/atest/resources/testserver/testserver.py -index 19e82ef..cf2abf1 100644 +index 565c650..8e3d82b 100644 --- a/atest/resources/testserver/testserver.py +++ b/atest/resources/testserver/testserver.py -@@ -5,6 +5,7 @@ from __future__ import print_function +@@ -3,6 +3,7 @@ import os import sys +from time import sleep - try: - from httplib import HTTPConnection - from BaseHTTPServer import HTTPServer -@@ -28,6 +29,36 @@ class StoppableHttpRequestHandler(SimpleHTTPRequestHandler): + + from http.client import HTTPConnection + from http.server import SimpleHTTPRequestHandler, HTTPServer +@@ -21,6 +22,36 @@ class StoppableHttpRequestHandler(SimpleHTTPRequestHandler): def do_POST(self): self.do_GET() + def do_GET(self): + """Response pages for Angular tests. + -+ Added by Edward Manlove - June 5, 2014 ++ Added by AngularJSLibrary + """ + if self.path.endswith('/fastcall'): + self.send_response(200) @@ -34,13 +34,13 @@ index 19e82ef..cf2abf1 100644 + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.end_headers() -+ self.wfile.write('fast template contents') ++ self.wfile.write(b'fast template contents') + elif self.path.endswith('/slowTemplateUrl'): + sleep(2) + self.send_response(200) + self.send_header('Content-type', 'text/html') + self.end_headers() -+ self.wfile.write('slow template contents') ++ self.wfile.write(b'slow template contents') + else: + SimpleHTTPRequestHandler.do_GET(self) + diff --git a/CHANGES.rst b/CHANGES.rst index f08c8d9..c3cf2e2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,18 +1,27 @@ Changelog ========= -0.0.10 (unreleased) +0.0.10 (2019-07-31) --------- Changes: -- Updated library documentation. +- Updated library and keyword documentation. [aaltat][emanlove] - Added error and informative message when unable to find root element or root component. [anthonyfromtheuk][HelioGuilherme66][emanlove] +- Modified for Python 3 compatibility + [emanlove] + - Documented discrepancy between the ``Set Ignore Implicit Angular Wait`` keyword argument and the equivalent import library argument. [HelioGuilherme66][aaltat][emanlove] +- Update for compatibility with SeleniumLibrary 4.0. + [aaltat][emanlove] + +- Fixed major issue with setup test environment under Windows documentation. + [emanlove] + 0.0.9 (2018-09-08) ------------------ Fixes: diff --git a/DEVELOPERS.rst b/DEVELOPERS.rst index b3a7cde..2df97c1 100644 --- a/DEVELOPERS.rst +++ b/DEVELOPERS.rst @@ -48,19 +48,19 @@ Steps to update keyword documentation Current Steps to Setup Development Environment and Run Tests ------------------------------------------------------------ -Here are the current (as of Aug. 3, 2018, selenium==3.14.0, robotframework-seleniumlibrary==3.2.0.dev1, protractor==5.4.0) instructions for setting up the development environment and running the tests +Here are the current (as of July 25, 2022, selenium==4.3.0, robotframework-seleniumlibrary==6.1.0.dev1, protractor==6.0.0) instructions for setting up the development environment and running the tests .. code:: bash - mkdir locator - cd locator/ + mkdir ng-test + cd ng-test/ git clone https://github.com/robotframework/SeleniumLibrary.git rf-sl - git clone https://github.com/Selenium2Library/robotframework-angularjs.git rf-ng + git clone https://github.com/MarketSquare/robotframework-angularjs.git rf-ng git clone https://github.com/angular/protractor.git ptor - virtualenv -p /usr/bin/python2.7 --no-site-packages cl-py27-env - source cl-py27-env/bin/activate - pip install robotframework robotstatuschecker mockito selenium + virtualenv -p /usr/bin/python3.9 cl-py39-env + source cl-py39-env/bin/activate + pip install robotframework robotstatuschecker mockito selenium requests pytest patch rf-sl/atest/resources/testserver/testserver.py rf-ng/AngularJSLibrary/testserver.py.patch diff --git a/LICENSE b/LICENSE index ea1006b..17a143e 100644 --- a/LICENSE +++ b/LICENSE @@ -206,11 +206,13 @@ AngularJSLibrary\ng-repeater.js: AngularJSLibrary\ng-repeater.min.js: AngularJSLibrary\__init__.py (certain javascript portions): +Various code examples (as noted in the documentation): The MIT License - Copyright (c) 2010-2015 Google, Inc. - + Copyright (c) 2010-2020 Google LLC. http://angularjs.org + Copyright (c) 2010-2022 Google LLC. http://angular.io/license + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights diff --git a/README.rst b/README.rst index d9e9926..d7f1023 100644 --- a/README.rst +++ b/README.rst @@ -1,18 +1,24 @@ AngularJSLibrary - robotframework-angularjs =========================================== -An AngularJS and Angular extension to Robotframework's SeleniumLibrary - -About the support for various Angular and Selenium Library versions -------------------------------------------------------------------- -As of AngularJSLibrary version 0.0.7 (31 March, 2018 release) only the SeleniumLibrary is supported (despite the name of the GITHUB group hosting the library). - -The AngularJSLibrary, despite the name including JS, supports both Angular 2.0+ (known as simply Angular) and Angular 1.0 (also known as Angular JS). - - -What is included ----------------- -AngularJSLibrary provides functionality in two key areas: angular specific **locator strategies** and **waiting**. Just as there are strategies provide by the SeleniumLibrary for locating elements by ID, CSS, or xPath, this library adds startegies for finding elements by binding, model, and repeater. The library also provides both an explicit keyword for waiting on angular and an implicit wait. - +An AngularJS and Angular extension to Robotframework's SeleniumLibrary. +AngularJSLibrary primarily provides functionality to deal with **waiting** and +thus timing issue when testing Angular based websites. The library does this by +providing first an implicit wait and, subsequently, an explicit keyword for +waiting on angular. + +About this library +------------------ +The AngularJSLibrary, despite the name including JS, supports testing against +both Angular 2.0+ (known as simply Angular) and Angular 1.0 (also known as +Angular JS). + +This library is considered mature and feature complete. Ongoing support is +provided through the Robot Framework community Slack. Thus it may appear +to be abandoned or neglected for which it is not. + +**Please carefully read through this README in its entirety**. It covers how +to configure and import the library into your test scripts, use and understand +its key functionality, as well as troubleshooting and debugging information. Installation ------------ @@ -29,52 +35,280 @@ Alternatively, to install from source: python setup.py install + +Identifying the Angular root element +------------------------------------ +Prior to importing the library, one must identify the Angular root element or root +component. For more information about + +Here are a few examples of Angular sites and their corresponding root elements or +components. The first example is from the `AngularJS.org PhoneCat tutorial `_. +The base html code is + +.. code:: html + + + + + + -Keyword Documentation ---------------------- -The keyword documentation can be found on the `Github project page `_. +
+
+
+ + + + +In the PhoneCat tutorial the html element with the ng-app attribute is the root +element. Thus for this website the root selector would be :code:`[ng-app]`. The +next example is the `Getting started with Angular tutorial `_ +on angular.io site. It's main html looks like + +.. code:: html + + + + + + + + + + + +Here the root component is the app-root element and thus the root selector for +this website would be :code:`app-root`. The last example is the `example tab of +the Dialog UI component `_ +within the Angular.io Component Dev Kit (CDK). + +.. code:: html + + + + + + + + + + + + +The root component for the Dialog component example page is the material-docs-app +element. The root selector will be :code:`material-docs-app`. +Now we will use the root selector when we import the library. Importing the library --------------------- -In order to use the keywords you have to include AngularJSLibrary in the settings section of your test or test suite. Note will will need to include the SeleniumLibrary **before** you import the AngularJSLibrary. +The proper name for importing the library is :code:`AngularJSLibrary`. You will +need to include the SeleniumLibrary **before** you import the AngularJSLibrary. +The first of two library options is `root_selector`. So using our first example, +the PhoneCat tutorial from AngularJS.org above, our import may look like, .. code:: robotframework *** Settings *** - Library SeleniumLibrary - Library AngularJSLibrary - ... + Library SeleniumLibrary + Library AngularJSLibrary root_selector=[ng-app] *** Test Cases *** - Go To localhost:8080 - Wait for Angular - ... + Search Through The Phone Catalog For Samsung Phones + Open Browser http://angular.github.io/angular-phonecat/step-14/app Chrome + Input Text //input Samsung + Click Link Samsung Galaxy Tab™ + Element Text Should Be css:phone-detail h1 Samsung Galaxy Tab™ + +As the default value for the root_selector argument is :code:`[ng-app]`, for +the PhoneCat tutorial we did not need to specify the root_selector and could +have written the Library import as -There are currently two library options: root_selector, ignore_implicit_angular_wait. root_selector allows the user to set the Angular root element (AngularJS) or root component (Angular). The default value is :code:`[ng-app]` and is a CSS selector; more specifically an attribute selector looking for an element with the attribute :code:`ng-app`. Starting in AngularJSLibrary version 0.0.10 if the root selector query fails an error is thrown noting the library is "[u]nable to find root selector ...". To resolve this issue one must discover the root element or component within the Angular appliction under test. +.. code:: robotframework + + *** Settings *** + Library SeleniumLibrary + Library AngularJSLibrary + + *** Test Cases *** + Search Through The Phone Catalog For Samsung Phones + Open Browser http://angular.github.io/angular-phonecat/step-14/app Chrome + Input Text //input Samsung + Click Link Samsung Galaxy Tab™ + Element Text Should Be css:phone-detail h1 Samsung Galaxy Tab™ -ignore_implicit_angular_wait is a flag which when set to True the AngularJS Library will not wait for Angular $timeouts nor $http calls to complete when finding elements by locator. As noted in the Protractor documentation "this should be used only when necessary, such as when a page continuously polls an API using $timeout." The default value is False. +*If you get an "Unable to find root selector ..." error* then you should re-check +your root_selector. Note that unlike locators used with the SeleniumLibrary the +root_selector **should not** contain the css locator prefix. +The second library option, ignore_implicit_angular_wait, is a flag which when +set to True the AngularJS Library will not wait for Angular $timeouts nor +$http calls to complete when finding elements by locator. The default value is +False. + +*If the application under test starts on a non angular page,* for example a +login page that is not angular which leads into an angular app, then one should +start with the implicit angular wait turned off. For example, + +.. code:: robotframework + + *** Settings *** + Library SeleniumLibrary + Library AngularJSLibrary ignore_implicit_angular_wait=True + + *** Test Cases *** + Login Into Non Angular Page + # ... Usage of the Waiting functionality ---------------------------------- -The AngularJS Library provides two types of waiting; a explicit keyword that one calls out or writes into their script and then an built-in implicit wait that automatically waits when using a locator strategy. Note currently the implicit wait is not invoked when using a web element as the locator. By default the implicit is turned on. This means as soon as you import the library you will have waiting enabled. - -You may turn off the implicit wait by either using the :code:`Set Ignore Implicit Angular Wait` keyword with an argument of :code:`${True}` or when importing the library. For some testing situations, for example the initial login page is non-angular, one may want to start without the implicit waiting enabled. +The AngularJS Library provides two types of waiting: a built-in implicit wait +that automatically waits when using a locator strategy and then an explicit +keyword that one calls out or writes into their script. In the tutorial and +examples above the scripts there aren't any expicit wait calls. Here instead +the script is relying on the implicit wait which by default is turned on. +This means as soon as you import the library you will have waiting enabled. -With the implicit wait functionality it is expected that most of the situations where waiting is needed will be handled "automatically" by this "hidden" implicit wait. Thus if one examined your test case they would not see many, if any, `Wait For Angular` keywords but instead would see actions keywords with no "waiting" keywords in between actions. There are though times when one needs to explicitly call out to wait for angular. For example when using a SeleniumLibrary keyword that does not use a locator strategy, like :code:`Alert Should Be Present` and :code:`Page should contain ...`, or if you use webelement. +This can be demostrated by importing the library with the implicit wait turned +off and using instead the library's explicit `Wait For Angular` keyword. +.. code:: robotframework -Usage of the Angular Specific Locator Stratergies -------------------------------------------------- -The new locator strategies include + *** Settings *** + Library SeleniumLibrary + Library AngularJSLibrary ignore_implicit_angular_wait=True + + *** Test Cases *** + Search Through The Phone Catalog For Samsung Phones + Open Browser http://angular.github.io/angular-phonecat/step-14/app Chrome + Wait For Angular + Input Text //input Samsung + Wait For Angular + Click Link Samsung Galaxy Tab™ + Wait For Angular + Element Text Should Be css:phone-detail h1 Samsung Galaxy Tab™ + +With the implicit wait functionality it is expected that most of the situations +where waiting is needed will be handled "automatically" by this "hidden" implicit +wait. Thus if one examined your test case they would not see many, if any, +`Wait For Angular` keywords but instead would see actions keywords with no +"waiting" keywords in between actions. There are times, though, when one needs to +explicitly call out to wait for angular. For example when using a SeleniumLibrary +keyword that does not use a locator strategy, like :code:`Alert Should Be Present` +and :code:`Page should contain`, or if you use webelement. + +In addition to the option to turn off the implicit wait on library import, you +may turn it off using the :code:`Set Ignore Implicit Angular Wait` keyword with +an argument of :code:`${True}`. + + +Understanding and verifying the angular waits +--------------------------------------------- +Although the waits seem like "Magic" they are not. Let's look into how the +waits are implimented and work to gain insight as to how they work. The waits, +both the implicit and explicit, poll what I call the "angular queue". +Technically it is checking that angular has "finished rendering and has no +outstanding $http or $timeout calls". It does this by checking the +`notifyWhenNoOutstandingRequests` function for AngularJS applications. For +Angular applications the library is checking the `isStable` function on the +Angular Testibility service. + +This can be seen within the log file by setting the loglevel to DEBUG or TRACE. +Rerunning the PhoneCat demo (:code:`robot --loglevel DEBUG demo_phonecat.robot`) +one should see in the log file -.. code:: +.. code:: robotframework - binding= - model= - repeater= + 20:01:04.658 INFO Typing text 'Samsung' into text field '//input'. + 20:01:04.658 DEBUG POST http://localhost:50271/session/f75e7aaf5a00c717ae5e4af34a6ce516540611dae4b7f6079ce1a753c308cde2/execute/sync {"script": "...snip..."]} + 20:01:04.661 DEBUG http://localhost:50271 "POST /session/f75e7aaf5a00c717ae5e4af34a6ce516540611dae4b7f6079ce1a753c308cde2/execute/sync HTTP/1.1" 200 14 + 20:01:04.661 DEBUG Remote response: status=200 | data={"value":true} | headers=HTTPHeaderDict({'Content-Length': '14', 'Content-Type': 'application/json; charset=utf-8', 'cache-control': 'no-cache'}) + 20:01:04.661 DEBUG Finished Request + +For space reasons I snipped out the core script on the POST execute/sync line. +One should see these lines repeated several times over. This is the polling the +library is doing to see if the application is ready to test. It will repeat +this query till either it returns true or it will repeat till the "give up" +timeout. If it gives up, it will silently and gracefully fail continuing onto +the actions it was waiting to perform. It is important for the user of this +library to see and understand, at a basic level, this functionality. As the +primary usage are these implicit, and thus hidden, waits it is key to see how +to check the library is operating properly and when it is waiting. + +*When using the AngularJS Library, if all waits timeout then the AngularJS +Library may not wait properly with that application under test.* This, +recalling all previously outlined information, is telling you that the +Angular app is constantly busy. This can happen depending on how the angular +application is designed. It may also affect only a portion of the application +so it is important to test out various parts of the application. + +Further debugging techniques +---------------------------- +In addition to using the AngularJS Library, one can use the Browser's DevTools +as a way to test out and demonstrate the core operation of the library against +an application. To be clear, this is not library code but similar Javascript +code which one uses outside of robot to exhibit, to a dev team for example, +what the library is seeing when it querys the application. When viewing the +application under test open the DevTools, preferably under Chrome, and on the +Console tab type the following, + +If the application is built with AngularJS or Angular 1.x then the script is + +.. code:: javascript + + var callback = function () {console.log('*')} + var el = document.querySelector('[ng-app]'); + var h = setInterval(function w4ng() { + console.log('.'); + try { + angular.element(el).injector().get('$browser'). + notifyWhenNoOutstandingRequests(callback); + } catch (err) { + console.log(err.message); + callback(err.message); + } + }, 10); + +For Angular v2+ then the script is + +.. code:: javascript + + var callback = function () {console.log('*')} + var el = document.querySelector('material-docs-app'); + var h = setInterval(function w4ng() { + console.log('.'); + try { + var readyToTest = window.getAngularTestability(el).isStable(); + } catch (err) { + console.log(err.message); + callback(err.message); + } + if (!readyToTest) { + callback() + } else { + console.log('.'); + } + }, 10); + +This will display a :code:`.` when "stable". Otherwise it will show a :code:`*` +when "busy". To shut down the javascript interval and stop this script type on +the console prompt :code:`clearInterval(h);`. [Chrome Browser is preferred +because repeated output within its DevTools console will be displayed as a +single line with a count versus a new line for each output making it much +easier to see and read.] I have personally used this myself both in developing +this library as well as demonstrating to various Angular developers how a +design/implementation is blocking testability. + +Additional Angular Specific Locator Strategies +------------------------------------------------- +**Note: It is no longer recommended to use these angular specific locator +strategies. Although functional, the SeleniumLibrary locator strategies are more +than sufficient and in most cases easier to use then these strategies. For backward +compatablity reasons these will be left in but it is strongly recommended not to +use.** +The library provides three new locator strategies, including ``binding``, +``model``, and ``repeater``. For example, you can look for an Angular ng-binding using @@ -112,7 +346,12 @@ Finally there is the strategy of find by repeat. This takes the general form of Getting Help ------------ -If you need help with AngularJSLibrary, SeleniumLibrary, or Robot Framework usage, please post to the `user group for Robot Framework `_. +If you need help with AngularJSLibrary, SeleniumLibrary, or Robot Framework usage, please reach out within the Robot Framework community `Slack `_. + + +Keyword Documentation +--------------------- +The keyword documentation can be found on the `Github project page `_. Testing @@ -126,3 +365,7 @@ References `SeleniumLibrary `_: Web testing library for Robot Framework `Protractor `_: E2E test framework for Angular apps + +`isStable reference `_ + +`Angular Testability service `_ diff --git a/docs/index.html b/docs/index.html index 1a69475..4220fdd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -5,7 +5,7 @@ - +