From 30b14572270d37da2d289865149f5217afe0e3dd Mon Sep 17 00:00:00 2001 From: Simon Meggle Date: Thu, 5 Oct 2023 12:44:42 +0200 Subject: [PATCH] added/updated test cases --- v2/data/google-imagesearch/config.json | 27 +++ v2/data/retry_rcc/windows.json | 2 +- v2/data/web-store-order-processor/.gitignore | 19 ++ v2/data/web-store-order-processor/LICENSE | 201 ++++++++++++++++++ v2/data/web-store-order-processor/README.md | 31 +++ v2/data/web-store-order-processor/conda.yaml | 18 ++ v2/data/web-store-order-processor/config.json | 27 +++ .../devdata/INTRODUCTION.md | 12 ++ .../devdata/env.json | 4 + .../libraries/INTRODUCTION.md | 3 + .../libraries/Orders.py | 26 +++ .../libraries/__init__.py | 0 v2/data/web-store-order-processor/robot.yaml | 23 ++ v2/data/web-store-order-processor/tasks.robot | 127 +++++++++++ 14 files changed, 519 insertions(+), 1 deletion(-) create mode 100644 v2/data/google-imagesearch/config.json create mode 100644 v2/data/web-store-order-processor/.gitignore create mode 100644 v2/data/web-store-order-processor/LICENSE create mode 100644 v2/data/web-store-order-processor/README.md create mode 100644 v2/data/web-store-order-processor/conda.yaml create mode 100644 v2/data/web-store-order-processor/config.json create mode 100644 v2/data/web-store-order-processor/devdata/INTRODUCTION.md create mode 100644 v2/data/web-store-order-processor/devdata/env.json create mode 100644 v2/data/web-store-order-processor/libraries/INTRODUCTION.md create mode 100644 v2/data/web-store-order-processor/libraries/Orders.py create mode 100644 v2/data/web-store-order-processor/libraries/__init__.py create mode 100644 v2/data/web-store-order-processor/robot.yaml create mode 100644 v2/data/web-store-order-processor/tasks.robot diff --git a/v2/data/google-imagesearch/config.json b/v2/data/google-imagesearch/config.json new file mode 100644 index 00000000..44d7f17f --- /dev/null +++ b/v2/data/google-imagesearch/config.json @@ -0,0 +1,27 @@ +{ + "working_directory": "C:\\tmp\\output", + "results_directory": "C:\\tmp\\results", + "suites": { + "googleimagesearch": { + "robot_framework_config": { + "robot_target": "C:\\rmk\\v2\\data\\google-imagesearch\\tasks.robot", + "variable_file": null, + "argument_file": null, + "retry_strategy": "Incremental" + }, + "execution_config": { + "n_retries_max": 1, + "execution_interval_seconds": 120, + "timeout": 110 + }, + "environment_config": { + "type": "Rcc", + "binary_path": "C:\\Users\\vagrant\\AppData\\Local\\Microsoft\\WindowsApps\\rcc.exe", + "robocorp_home_path": "C:\\tmp\\ROBOCORP_HOME", + "robot_yaml_path": "C:\\rmk\\v2\\data\\google-imagesearch\\robot.yaml", + "build_timeout": 600 + }, + "session_config": {"type": "Current"} + } + } +} diff --git a/v2/data/retry_rcc/windows.json b/v2/data/retry_rcc/windows.json index 98d48519..fb9f0f71 100644 --- a/v2/data/retry_rcc/windows.json +++ b/v2/data/retry_rcc/windows.json @@ -18,7 +18,7 @@ "type": "Rcc", "binary_path": "C:\\Users\\vagrant\\AppData\\Local\\Microsoft\\WindowsApps\\rcc.exe", "robot_yaml_path": "C:\\robotmk\\v2\\data\\retry_rcc\\robot.yaml", - "build_timeout": 120 + "build_timeout": 600 }, "session_config": {"type": "Current"} } diff --git a/v2/data/web-store-order-processor/.gitignore b/v2/data/web-store-order-processor/.gitignore new file mode 100644 index 00000000..0c64f58b --- /dev/null +++ b/v2/data/web-store-order-processor/.gitignore @@ -0,0 +1,19 @@ +output/ +venv/ +temp/ +.rpa/ +.idea/ +.ipynb_checkpoints/ +*/.ipynb_checkpoints/* +.virtual_documents/ +*/.virtual_documents/* +.vscode +.DS_Store +*.pyc +*.zip +*/work-items-out/* +testrun/* +.~lock* +*.pkl +Data.xlsx +playwright-log.txt diff --git a/v2/data/web-store-order-processor/LICENSE b/v2/data/web-store-order-processor/LICENSE new file mode 100644 index 00000000..377d3bf9 --- /dev/null +++ b/v2/data/web-store-order-processor/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 RoboCorp Oy + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/v2/data/web-store-order-processor/README.md b/v2/data/web-store-order-processor/README.md new file mode 100644 index 00000000..eb080500 --- /dev/null +++ b/v2/data/web-store-order-processor/README.md @@ -0,0 +1,31 @@ +# Playwright Browser version of Web store order processor example + +[Web store order processor example robot](https://github.com/robocorp/example-web-store-order-processor) but implemented with Playwright based Browser library. + +See https://robocorp.com/docs/development-guide/browser/playwright for an in-depth look into the library itself. + +Why use Playwright based Browser library? + +- Implicit retrying on Getters +- More concise API +- Execution speed through Context and Page abstractions, enabling multi-login and multi-tab automation without multiple browsers + +## Configure local vault + +See https://robocorp.com/docs/development-guide/variables-and-secrets/vault + +Paste this content in the vault file: + +```json +{ + "swaglabs": { + "username": "standard_user", + "password": "secret_sauce" + } +} +``` + +In `devdata/env.json`, edit the `RPA_SECRET_FILE` variable to point to the +`vault.json` file on your filesystem. On macOS / Linux, use normal file paths, +for example, `"/Users//vault.json"` or `"/home//vault.json"`. +On Windows 10, you need to escape the path, for example, `"C:\\Users\\User\\vault.json"`. diff --git a/v2/data/web-store-order-processor/conda.yaml b/v2/data/web-store-order-processor/conda.yaml new file mode 100644 index 00000000..709b175c --- /dev/null +++ b/v2/data/web-store-order-processor/conda.yaml @@ -0,0 +1,18 @@ +# For more details on the format and content: +# https://github.com/robocorp/rcc/blob/master/docs/recipes.md#what-is-in-condayaml +# Tip: Adding a link to the release notes of the packages helps maintenance and security. + +channels: + - conda-forge + +dependencies: + - python=3.10.12 # https://pyreadiness.org/3.10 + - pip=23.2.1 # https://pip.pypa.io/en/stable/news + - truststore=0.7.0 # https://github.com/sethmlarson/truststore/blob/main/CHANGELOG.md + - nodejs=18.17.1 # https://github.com/nodejs/node/blob/main/CHANGELOG.md + - pip: + - robotframework-browser==17.4.0 # https://github.com/MarketSquare/robotframework-browser/releases + - rpaframework==27.1.0 # https://rpaframework.org/releasenotes.html + +rccPostInstall: + - rfbrowser init # Initialize Playwright diff --git a/v2/data/web-store-order-processor/config.json b/v2/data/web-store-order-processor/config.json new file mode 100644 index 00000000..8835d134 --- /dev/null +++ b/v2/data/web-store-order-processor/config.json @@ -0,0 +1,27 @@ +{ + "working_directory": "C:\\tmp\\output", + "results_directory": "C:\\tmp\\results", + "suites": { + "webstore-playwright": { + "robot_framework_config": { + "robot_target": "C:\\rmk\\v2\\data\\web-store-order-processor\\tasks.robot", + "variable_file": null, + "argument_file": null, + "retry_strategy": "Incremental" + }, + "execution_config": { + "n_retries_max": 1, + "execution_interval_seconds": 120, + "timeout": 110 + }, + "environment_config": { + "type": "Rcc", + "binary_path": "C:\\Users\\vagrant\\AppData\\Local\\Microsoft\\WindowsApps\\rcc.exe", + "robocorp_home_path": "C:\\tmp\\ROBOCORP_HOME", + "robot_yaml_path": "C:\\rmk\\v2\\data\\web-store-order-processor\\robot.yaml", + "build_timeout": 600 + }, + "session_config": {"type": "Current"} + } + } +} diff --git a/v2/data/web-store-order-processor/devdata/INTRODUCTION.md b/v2/data/web-store-order-processor/devdata/INTRODUCTION.md new file mode 100644 index 00000000..15797db2 --- /dev/null +++ b/v2/data/web-store-order-processor/devdata/INTRODUCTION.md @@ -0,0 +1,12 @@ +# Devdata placeholder + +This directory should contain local development data. + +This data should not be used in actual Robocorp App run but can be +used when you are building and debugging your entrypoints and robots. + +## What to put here? + +- Local work item data +- Local environment variables (in JSON format) +- Local custom data files (\*.csv, etc.) diff --git a/v2/data/web-store-order-processor/devdata/env.json b/v2/data/web-store-order-processor/devdata/env.json new file mode 100644 index 00000000..e2e93048 --- /dev/null +++ b/v2/data/web-store-order-processor/devdata/env.json @@ -0,0 +1,4 @@ +{ + "RPA_SECRET_MANAGER": "RPA.Robocorp.Vault.FileSecrets", + "RPA_SECRET_FILE": "C:\\vault.json" +} diff --git a/v2/data/web-store-order-processor/libraries/INTRODUCTION.md b/v2/data/web-store-order-processor/libraries/INTRODUCTION.md new file mode 100644 index 00000000..6d21b973 --- /dev/null +++ b/v2/data/web-store-order-processor/libraries/INTRODUCTION.md @@ -0,0 +1,3 @@ +# Libraries + +Place your libraries in this directory. diff --git a/v2/data/web-store-order-processor/libraries/Orders.py b/v2/data/web-store-order-processor/libraries/Orders.py new file mode 100644 index 00000000..101ed5ac --- /dev/null +++ b/v2/data/web-store-order-processor/libraries/Orders.py @@ -0,0 +1,26 @@ +from RPA.Excel.Files import Files +from RPA.Tables import Tables + + +class Orders: + def get_orders(self, excel): + files = Files() + workbook = files.open_workbook(excel) + rows = workbook.read_worksheet(header=True) + + tables = Tables() + table = tables.create_table(rows) + tables.filter_empty_rows(table) + + orders = [] + for row in table: + first_name, last_name = row["Name"].split() + order = { + "item": row["Item"], + "zip": int(row["Zip"]), + "first_name": first_name, + "last_name": last_name + } + orders.append(order) + + return orders diff --git a/v2/data/web-store-order-processor/libraries/__init__.py b/v2/data/web-store-order-processor/libraries/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/v2/data/web-store-order-processor/robot.yaml b/v2/data/web-store-order-processor/robot.yaml new file mode 100644 index 00000000..da284483 --- /dev/null +++ b/v2/data/web-store-order-processor/robot.yaml @@ -0,0 +1,23 @@ +tasks: + Web store orders: + command: + - python + - -m + - robot + - --report + - NONE + - -d + - output + - --logtitle + - Task log + - tasks.robot + +condaConfigFile: conda.yaml +artifactsDir: output +ignoreFiles: + - .gitignore +PATH: + - . +PYTHONPATH: + - . + - libraries diff --git a/v2/data/web-store-order-processor/tasks.robot b/v2/data/web-store-order-processor/tasks.robot new file mode 100644 index 00000000..3ecffbea --- /dev/null +++ b/v2/data/web-store-order-processor/tasks.robot @@ -0,0 +1,127 @@ +*** Settings *** +Documentation Swag order robot. Places orders at https://www.saucedemo.com/ +... by processing a spreadsheet of orders and ordering the +... specified products using browser automation. Uses local or +... cloud vault for credentials. + +Library OperatingSystem +Library Orders +Library RPA.Browser.Playwright +Library RPA.HTTP +Library RPA.Robocorp.Vault + + +*** Variables *** +${EXCEL_FILE_NAME}= Data.xlsx +${EXCEL_FILE_URL}= https://github.com/robocorp/example-web-store-order-processor/raw/main/devdata/${EXCEL_FILE_NAME} +${SWAG_LABS_URL}= https://www.saucedemo.com + + +*** Tasks *** +Place orders + Process orders + + +*** Keywords *** +Process orders + Open Swag Labs + ${secret}= Get Secret swaglabs + Login ${secret}[username] ${secret}[password] + ${orders}= Collect orders + FOR ${order} IN @{orders} + Run Keyword And Continue On Failure Process order ${order} + END + [Teardown] Close Browser + +Submit Form + Click input[type=submit] + +Open Swag Labs + New Browser headless=False + New Page ${SWAG_LABS_URL} + +Login + [Arguments] ${user_name} ${password} + Fill Text id=user-name ${user_name} + Fill Secret id=password $password + Submit Form + Assert logged in + +Assert logged in + Wait For Elements State css=#inventory_container.inventory_container + Get Url == ${SWAG_LABS_URL}/inventory.html + +Collect orders + RPA.HTTP.Download ${EXCEL_FILE_URL} overwrite=True + ${orders}= Get Orders ${EXCEL_FILE_NAME} + RETURN ${orders} + +Process order + [Arguments] ${order} + Reset application state + Open products page + Assert cart is empty + Add product to cart ${order} + Open cart + Assert one product in cart ${order} + Checkout ${order} + Open products page + +Reset application state + Click css=.bm-burger-button button + Click id=reset_sidebar_link + +Open products page + Go To ${SWAG_LABS_URL}/inventory.html + +Assert cart is empty + Get Text css=.shopping_cart_link == ${EMPTY} + Get Element States css=.shopping_cart_badge != visible + +Add product to cart + [Arguments] ${order} + ${product_name}= Set Variable ${order["item"]} + ${locator}= + ... Set Variable + ... xpath=//div[@class="inventory_item" and descendant::div[contains(text(), "${product_name}")]] + ${add_to_cart_button}= Get Element ${locator} >> .btn_primary + Click ${add_to_cart_button} + Assert items in cart 1 + +Assert items in cart + [Arguments] ${quantity} + Get Text css=.shopping_cart_badge == ${quantity} + +Open cart + Click css=.shopping_cart_link + Assert cart page + +Assert cart page + Wait For Elements State id=cart_contents_container + Get Url == ${SWAG_LABS_URL}/cart.html + +Assert one product in cart + [Arguments] ${order} + Get Text css=.cart_quantity == 1 + Get Text css=.inventory_item_name == ${order["item"]} + +Checkout + [Arguments] ${order} + Click css=.checkout_button + Fill Text id=first-name ${order["first_name"]} + Fill Text id=last-name ${order["last_name"]} + Fill Text id=postal-code ${{ str(${order["zip"]} )}} + Submit Form + Click css=.btn_action + +Assert checkout information page + Wait For Elements State id=checkout_info_container + Get Url == ${SWAG_LABS_URL}/checkout-step-one.html + +Assert checkout confirmation page + Wait For Elements State id=checkout_summary_container + Get Url == ${SWAG_LABS_URL}/checkout-step-two.html + +Assert checkout complete page + Wait For Elements State id=checkout_complete_container + Get Url == ${SWAG_LABS_URL}/checkout-complete.html