From 4ee703bb5a25cd72325e8862a8828366ac6c5c53 Mon Sep 17 00:00:00 2001 From: sub0br Date: Wed, 12 Aug 2026 23:37:03 -0300 Subject: [PATCH 1/6] ci: add Allure reporting with history, GitHub Pages publish and email notification - Add allure-robotframework listener and generate results in CI - Publish Allure report (with history) to gh-pages on pushes to main - Upload Allure report as PR artifact and attach single-file report to email - Add contents: write permission needed for gh-pages deploy - Fix xunit.xml artifact path (results/xunit.xml) and .gitignore for allure dirs --- .github/workflows/robot-tests.yml | 110 +++++++++++++++++++++++++++++- .gitignore | 6 ++ requirements.txt | 3 +- 3 files changed, 115 insertions(+), 4 deletions(-) diff --git a/.github/workflows/robot-tests.yml b/.github/workflows/robot-tests.yml index 69abc2f..01bda40 100644 --- a/.github/workflows/robot-tests.yml +++ b/.github/workflows/robot-tests.yml @@ -10,7 +10,7 @@ on: # into `main` (GitHub only reads `schedule` triggers from the workflow # file version on the repo's default branch, not from feature branches). # schedule: - # - cron: '0 3 * * *' # 03:00 UTC = 00:00 (meia-noite) em Brasília + # - cron: '0 3 * * *' # 03:00 UTC = 00:00 (midnight) in Brasília workflow_dispatch: # allows manual trigger from the Actions tab inputs: tag: @@ -26,6 +26,11 @@ concurrency: group: robot-tests-${{ github.ref }} cancel-in-progress: true +# Needed by peaceiris/actions-gh-pages to push the Allure report +# to the gh-pages branch using the default GITHUB_TOKEN. +permissions: + contents: write + jobs: robot-tests: name: Run Robot Framework Suite @@ -82,6 +87,7 @@ jobs: - name: Run Robot Framework tests run: | robot \ + --listener allure_robotframework:allure-results \ --variable HEADLESS:True \ --include ${{ steps.tag.outputs.value }} \ --outputdir results \ @@ -96,6 +102,9 @@ jobs: # critical-path subset run on every PR; "regression" covers the # whole suite (every test carries it) and runs on merges to main # and the nightly schedule. + # --listener allure_robotframework writes the raw Allure data to + # allure-results/ (at the root of the workspace, outside results/), + # which is converted into the HTML report in the steps below. - name: Publish summary on GitHub Actions if: always() @@ -108,6 +117,10 @@ jobs: echo "for smoke/regression/critical/high/medium and ui) is" echo "available in the **robot-framework-results** artifact." fi + if [ "${{ github.ref }}" = "refs/heads/main" ]; then + echo "" + echo "Allure report (with history): https://tfernandes-qa.github.io/robotframework/" + fi } >> "$GITHUB_STEP_SUMMARY" - name: Upload artifacts (log.html, report.html, output.xml) @@ -123,5 +136,96 @@ jobs: uses: actions/upload-artifact@v4 with: name: robot-junit-report - path: xunit.xml - retention-days: 15 \ No newline at end of file + path: results/xunit.xml + retention-days: 15 + + # ---------- Allure ---------- + + # Retrieves the history of previous runs from the gh-pages branch. + # continue-on-error covers the first run, when the branch does not exist yet. + - name: Get Allure history + if: always() + continue-on-error: true + uses: actions/checkout@v4 + with: + ref: gh-pages + path: gh-pages + + - name: Generate Allure report with history + if: always() + uses: simple-elf/allure-report-action@v1.12 + with: + allure_results: allure-results + gh_pages: gh-pages + allure_report: allure-report + allure_history: allure-history + keep_reports: 20 + + # Publishes to GitHub Pages only on pushes to main (and manual runs on + # main), so that PRs with the "smoke" subset don't pollute the official + # trend/flaky-test history, which is fed only by the full suite. + - name: Deploy Allure report to GitHub Pages + if: always() && github.ref == 'refs/heads/main' && github.event_name != 'pull_request' + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: allure-history + + # On PRs, the Allure report is made available as a run artifact. + - name: Upload Allure report artifact (PRs) + if: always() && github.event_name == 'pull_request' + uses: actions/upload-artifact@v4 + with: + name: allure-report + path: allure-report/ + retention-days: 15 + + # ---------- Email with Allure report ---------- + + # The Allure CLI (via npm) generates the single-file version of the + # report: a self-contained index.html that's ideal as an email + # attachment. The Java required by the CLI is already installed on + # the ubuntu-latest runner. + - name: Install Allure CLI + if: always() + run: npm install -g allure-commandline + + - name: Generate single-file Allure report (email attachment) + if: always() + run: allure generate allure-results --single-file --clean -o allure-single + + - name: Send Allure report by email + if: always() + uses: dawidd6/action-send-mail@v4 + with: + server_address: ${{ secrets.MAIL_SERVER }} + server_port: 465 + secure: true + username: ${{ secrets.MAIL_USERNAME }} + password: ${{ secrets.MAIL_PASSWORD }} + from: Robot CI <${{ secrets.MAIL_USERNAME }}> + to: ${{ secrets.MAIL_TO }} + subject: >- + [${{ job.status == 'success' && 'PASS' || 'FAIL' }}] + Robot ${{ steps.tag.outputs.value }} — + ${{ github.repository }} run #${{ github.run_number }} + html_body: | +

Robot Framework — run result

+

+ Status: ${{ job.status }}
+ Suite: ${{ steps.tag.outputs.value }}
+ Event: ${{ github.event_name }}
+ Branch/ref: ${{ github.ref_name }}
+ Commit: ${{ github.sha }} +

+

+ Full Allure report attached (index.html — opens directly in the browser).
+ Run details: + + run #${{ github.run_number }} +
+ Published history (main): + tfernandes-qa.github.io/robotframework +

+ attachments: allure-single/index.html \ No newline at end of file diff --git a/.gitignore b/.gitignore index f77c0fb..715a404 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,9 @@ report.html output.xml playwright-log.txt browser/traces/ + +# Allure +allure-results/ +allure-report/ +allure-history/ +gh-pages/ \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 0536be4..7d81bdc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ robotframework robotframework-browser robotframework-requests -Faker==26.0.0 \ No newline at end of file +Faker==26.0.0 +allure-robotframework \ No newline at end of file From c79f4abbe70d6bb9455db67bf5a66d7750d5b7b4 Mon Sep 17 00:00:00 2001 From: sub0br Date: Wed, 12 Aug 2026 23:37:34 -0300 Subject: [PATCH 2/6] test: add admin authorization and duplicate-submission test cases - Verify admin cannot access user home unrestricted vs regular user redirect to login on invalid session - Verify regular user cannot access admin home page (known ServeRest issue) - Verify duplicated email/product name are rejected on creation - Verify double-clicking submit does not create duplicated users - Add supporting keywords/resources: products_api.resource, session invalidation, alert message assertion, double-click helper --- resources/api/products_api.resource | 42 +++++++++++ resources/api/users_api.resource | 21 ++++++ resources/pages/global_page.resource | 17 +++++ resources/pages/home_page.resource | 27 ++++++- resources/pages/login_page.resource | 9 +++ resources/pages/newUser_page.resource | 7 ++ tests/admin/admin.robot | 102 +++++++++++++++++++++++++- tests/login/login.robot | 50 ++++++++++++- 8 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 resources/api/products_api.resource diff --git a/resources/api/products_api.resource b/resources/api/products_api.resource new file mode 100644 index 0000000..7ee74e5 --- /dev/null +++ b/resources/api/products_api.resource @@ -0,0 +1,42 @@ +*** Settings *** +Documentation Support keywords that use the ServeRest API to prepare +... and clean up test data (products) used by the UI tests. +... Unlike the user routes, the product routes require an admin +... authorization token. +Library RequestsLibrary +Library Collections +Resource ../variables/global.resource + + +*** Keywords *** +Get Admin Auth Token + [Documentation] Logs in, via API, with the given admin credentials and + ... returns the authorization token required by the + ... product creation/deletion routes. + [Arguments] ${email} ${password} + ${body}= Create Dictionary email=${email} password=${password} + ${response}= POST ${API_BASE_URL}/login json=${body} expected_status=200 + ${token}= Set Variable ${response.json()}[authorization] + RETURN ${token} + +Create Product Via Api + [Documentation] Creates, via API, a product with the given fields, + ... using the given admin authorization token, and + ... returns the id of the created product. + [Arguments] ${name} ${price} ${description} ${quantity} ${admin_token} + ${body}= Create Dictionary + ... nome=${name} + ... preco=${price} + ... descricao=${description} + ... quantidade=${quantity} + ${headers}= Create Dictionary Authorization=${admin_token} + ${response}= POST ${API_BASE_URL}/produtos json=${body} headers=${headers} expected_status=201 + ${product_id}= Set Variable ${response.json()}[_id] + RETURN ${product_id} + +Delete Product Via Api + [Documentation] Removes, via API, the product created for the test, + ... using the given admin authorization token. + [Arguments] ${product_id} ${admin_token} + ${headers}= Create Dictionary Authorization=${admin_token} + DELETE ${API_BASE_URL}/produtos/${product_id} headers=${headers} expected_status=200 diff --git a/resources/api/users_api.resource b/resources/api/users_api.resource index 00180d5..43c9c91 100644 --- a/resources/api/users_api.resource +++ b/resources/api/users_api.resource @@ -41,3 +41,24 @@ Delete User Via Api ... the environment's test data clean. [Arguments] ${user_id} DELETE ${API_BASE_URL}/usuarios/${user_id} expected_status=200 + +Get Users By Email Via Api + [Documentation] Queries, via API, all users registered with the given + ... email, returning how many were found and the list of + ... matching user records. + [Arguments] ${email} + ${params}= Create Dictionary email=${email} + ${response}= GET ${API_BASE_URL}/usuarios params=${params} expected_status=200 + ${quantity}= Set Variable ${response.json()}[quantidade] + ${users}= Set Variable ${response.json()}[usuarios] + RETURN ${quantity} ${users} + +Delete All Users With Email Via Api + [Documentation] Removes, via API, every user registered with the given + ... email. Used to clean up after tests that intentionally + ... try to create duplicated users. + [Arguments] ${email} + ${quantity} ${users}= Get Users By Email Via Api ${email} + FOR ${user} IN @{users} + Delete User Via Api ${user}[_id] + END diff --git a/resources/pages/global_page.resource b/resources/pages/global_page.resource index d84e43e..339d11c 100644 --- a/resources/pages/global_page.resource +++ b/resources/pages/global_page.resource @@ -5,6 +5,7 @@ Resource ../variables/global.resource Resource ../../resources/api/users_api.resource *** Variables *** +${ALERT_MESSAGE} .alert-dismissible > span *** Keywords *** @@ -37,6 +38,22 @@ Cleanup Login Test Close Browser Delete User Via Api ${USER_ID} +Invalidate User Session Token + [Documentation] Clears the browser's local storage, invalidating the + ... logged in user's session token, to simulate an + ... expired or otherwise invalid session. + LocalStorage Clear + +Alert Message Should Be + [Documentation] Confirms that the alert message displayed on the + ... current page matches the expected one. Several forms + ... across the app (login, new user, new product, ...) + ... share this same generic dismissible alert component. + [Arguments] ${expected_message} + Wait For Elements State ${ALERT_MESSAGE} visible + ${actual_message}= Get Text ${ALERT_MESSAGE} + Should Be Equal As Strings ${actual_message} ${expected_message} + Generate Random User [Documentation] Return name, email and password using Faker (pt_BR) ${fake}= Evaluate faker.Faker('pt_BR') modules=faker diff --git a/resources/pages/home_page.resource b/resources/pages/home_page.resource index 39a06c2..84c732c 100644 --- a/resources/pages/home_page.resource +++ b/resources/pages/home_page.resource @@ -61,4 +61,29 @@ Click Listar Button On Listar Produtos Card Products Table Should Be Displayed [Documentation] Confirms that the products table is displayed on the page. - Wait For Elements State ${PRODUCTS_TABLE} visible \ No newline at end of file + Wait For Elements State ${PRODUCTS_TABLE} visible + +Navigate To Admin Home Page + [Documentation] Navigates directly to the admin home page URL, without + ... going through the login form. + Go To ${BASE_URL}/admin/home + +Navigate To Home Page + [Documentation] Navigates directly to the regular user home page URL, + ... without going through the login form. + Go To ${BASE_URL}/home + +Admin Page Should Not Be Displayed + [Documentation] Confirms that the admin home page is NOT accessible: + ... an admin-only element (the "Cadastrar Usuários" button) + ... must not be visible, and the current URL must not be + ... the admin home URL. + ... KNOWN ISSUE: as of this writing, the ServeRest + ... front-end does not enforce role-based access control — + ... any authenticated user (not only admins) can reach + ... /admin/home. This keyword documents the expected, + ... correct behavior, so it currently fails until that + ... authorization defect is fixed. + Wait For Elements State ${CREATE_USER_BUTTON} hidden timeout=5s + ${current_url}= Get Url + Should Not Be Equal As Strings ${current_url} ${BASE_URL}/admin/home \ No newline at end of file diff --git a/resources/pages/login_page.resource b/resources/pages/login_page.resource index 5cabf14..9310674 100644 --- a/resources/pages/login_page.resource +++ b/resources/pages/login_page.resource @@ -31,3 +31,12 @@ Login Error Message Should Be Wait For Elements State ${LOGIN_ERROR_MESSAGE} visible ${actual_message}= Get Text ${LOGIN_ERROR_MESSAGE} Should Be Equal As Strings ${actual_message} ${expected_message} + +Login Page Should Be Displayed + [Documentation] Confirms that the user was redirected to the login + ... page (e.g. after trying to access a protected page + ... with an expired or invalid session), by waiting for + ... the email field and checking the current URL. + Wait For Elements State ${EMAIL_INPUT} visible + ${current_url}= Get Url + Should Be Equal As Strings ${current_url} ${BASE_URL}/login diff --git a/resources/pages/newUser_page.resource b/resources/pages/newUser_page.resource index 6b1366b..9c6cc62 100644 --- a/resources/pages/newUser_page.resource +++ b/resources/pages/newUser_page.resource @@ -28,6 +28,13 @@ Click Cadastrar Button [Documentation] Clicks the "Cadastrar" button to submit the new user registration form. Click ${NEW_USER_CADASTRAR_BUTTON} +Double Click Cadastrar Button + [Documentation] Double-clicks the "Cadastrar" button on the new user + ... registration form (submitting it twice in rapid + ... succession), to verify the form does not create + ... duplicated users when submitted twice. + Click With Options ${NEW_USER_CADASTRAR_BUTTON} left clickCount=2 + User Should Be Created [Documentation] Confirms that the user was created successfully by ... checking for a success message on the screen. diff --git a/tests/admin/admin.robot b/tests/admin/admin.robot index 190dbeb..adf6b7b 100644 --- a/tests/admin/admin.robot +++ b/tests/admin/admin.robot @@ -5,6 +5,8 @@ Resource ../../resources/pages/login_page.resource Resource ../../resources/pages/home_page.resource Resource ../../resources/pages/newUser_page.resource Resource ../../resources/pages/newProduct_page.resource +Resource ../../resources/api/users_api.resource +Resource ../../resources/api/products_api.resource Test Setup Open Browser To Admin Page Test Teardown Cleanup Login Test @@ -43,6 +45,46 @@ Admin Wants To List All Products When the admin clicks on the "Listar" button on the Listar Produtos card Then the list of products should be displayed +Admin Can Access The Regular User Home Page + [Documentation] This test case verifies that an admin user, who holds + ... higher privileges, can also access the regular user's + ... home page (store) directly, without being blocked. + [Tags] admin login ui regression high + Given an admin user is logged in + When this admin user navigates directly to the regular home URL + Then the home page should be displayed + +Admin Cannot Create User With Duplicated Email + [Documentation] This test case verifies that the admin cannot create + ... a new user using an email that is already registered. + [Tags] admin ui regression high negative + [Teardown] Run Keywords Delete User Via Api ${DUPLICATE_USER_ID} + ... AND Cleanup Login Test + Given a user already exists with a known email + When the admin tries to create a new user with the same email + Then the message "Este email já está sendo usado" must appear + +Admin Cannot Create Product With Duplicated Name + [Documentation] This test case verifies that the admin cannot create + ... a new product using a name that is already registered. + [Tags] admin ui regression high negative + [Teardown] Run Keywords Delete Product Via Api ${DUPLICATE_PRODUCT_ID} ${ADMIN_TOKEN} + ... AND Cleanup Login Test + Given a product already exists with a known name + When the admin tries to create a new product with the same name + Then the message "Já existe produto com esse nome" must appear + +Double Click On Submit Should Not Create Duplicated User + [Documentation] This test case verifies that double-clicking the + ... "Cadastrar" button on the new user registration form + ... does not create two users with the same data. + [Tags] admin ui regression medium negative + [Teardown] Run Keywords Delete All Users With Email Via Api ${NEW_USER_EMAIL} + ... AND Cleanup Login Test + Given the admin fills in valid user details + When the admin double clicks the submit button + Then only one user should be created with that email + *** Keywords *** Open Browser To Admin Page [Documentation] Opens the browser and navigates to the admin page. @@ -107,4 +149,62 @@ the admin clicks on the "Listar" button on the Listar Produtos card Click Listar Button On Listar Produtos Card Then the list of products should be displayed - Products Table Should Be Displayed \ No newline at end of file + Products Table Should Be Displayed + +an admin user is logged in + No Operation + +this admin user navigates directly to the regular home URL + Navigate To Home Page + +the home page should be displayed + Home Page Should Be Displayed + +a user already exists with a known email + ${duplicate_email} ${duplicate_password} ${duplicate_user_id}= Create Standard User Via Api + Set Test Variable ${DUPLICATE_EMAIL} ${duplicate_email} + Set Test Variable ${DUPLICATE_USER_ID} ${duplicate_user_id} + +the admin tries to create a new user with the same email + ${name} ${email} ${password}= Generate Random User + Click Cadastrar Button On Cadastro De Usuario Card + Input New Name ${name} + Input New Email ${DUPLICATE_EMAIL} + Input New Password ${password} + Click Cadastrar Button + +a product already exists with a known name + ${name} ${price} ${description} ${quantity}= Generate Random Product + ${admin_token}= Get Admin Auth Token ${EMAIL} ${PASSWORD} + ${product_id}= Create Product Via Api ${name} ${price} ${description} ${quantity} ${admin_token} + Set Test Variable ${DUPLICATE_PRODUCT_NAME} ${name} + Set Test Variable ${DUPLICATE_PRODUCT_ID} ${product_id} + Set Test Variable ${ADMIN_TOKEN} ${admin_token} + +the admin tries to create a new product with the same name + ${other_name} ${price} ${description} ${quantity}= Generate Random Product + Click Cadastrar Button On Cadastrar Produtos Card + Input New Product Name ${DUPLICATE_PRODUCT_NAME} + Input New Product Price ${price} + Input New Product Description ${description} + Input New Product Quantity ${quantity} + Click Cadastrar Button on New Product Form + +the message "${message}" must appear + Alert Message Should Be ${message} + +the admin fills in valid user details + ${name} ${email} ${password}= Generate Random User + Click Cadastrar Button On Cadastro De Usuario Card + Input New Name ${name} + Input New Email ${email} + Input New Password ${password} + Set Test Variable ${NEW_USER_EMAIL} ${email} + +the admin double clicks the submit button + Double Click Cadastrar Button + +only one user should be created with that email + User Should Be Created ${NEW_USER_EMAIL} + ${quantity} ${users}= Get Users By Email Via Api ${NEW_USER_EMAIL} + Should Be Equal As Integers ${quantity} 1 \ No newline at end of file diff --git a/tests/login/login.robot b/tests/login/login.robot index 243f3c9..dc40e96 100644 --- a/tests/login/login.robot +++ b/tests/login/login.robot @@ -79,6 +79,30 @@ User With Invalid Email Format Should See Error Message And clicks on Entrar Then the message "Email deve ser um email válido" must appear +User With Invalidated Session Should Be Redirected To The Login Page + [Documentation] A logged in user whose session token becomes invalid + ... and who then tries to reach the admin home page must + ... be redirected back to the login page. + [Tags] login admin ui regression high + Given a logged in user is on the home page + When the user session token is invalidated + And the user navigates to the admin home page + Then this user must be redirected to the login page + +Regular User Should Not Be Able To Access The Admin Home Page + [Documentation] A logged in regular (non-admin) user who navigates + ... directly to the admin home URL must not see the admin + ... page and must be redirected to their own home page. + ... KNOWN ISSUE: the ServeRest front-end currently does + ... not enforce this restriction (see `Admin Page Should + ... Not Be Displayed`), so this test is expected to fail + ... until that authorization defect is fixed. + [Tags] login admin security ui regression high known-issue + Given a regular user is logged in + When this user navigates directly to the admin home URL + Then the admin page should not be displayed + And this user must be redirected to the home page + *** Keywords *** a user is trying to login No Operation @@ -109,4 +133,28 @@ this admin user types the email and password Click Entrar Button the admin page should be displayed - Admin Page Should Be Displayed \ No newline at end of file + Admin Page Should Be Displayed + +a logged in user is on the home page + Input Email ${EMAIL} + Input Password ${PASSWORD} + Click Entrar Button + Home Page Should Be Displayed + +the user session token is invalidated + Invalidate User Session Token + +the user navigates to the admin home page + Navigate To Admin Home Page + +this user must be redirected to the login page + Login Page Should Be Displayed + +a regular user is logged in + a logged in user is on the home page + +this user navigates directly to the admin home URL + Navigate To Admin Home Page + +the admin page should not be displayed + Admin Page Should Not Be Displayed \ No newline at end of file From dcf5c9b68d01b0974109dcb0217418cf5b5a8029 Mon Sep 17 00:00:00 2001 From: sub0br Date: Wed, 12 Aug 2026 23:43:16 -0300 Subject: [PATCH 3/6] ci: replace unmaintained allure-report-action with direct Allure CLI calls - simple-elf/allure-report-action's Docker build was failing (openjdk:8-jre-alpine removed from Docker Hub, action unmaintained) - Generate report and restore history directly via Allure CLI instead - Deploy allure-report/ (now includes history) to GitHub Pages --- .github/workflows/robot-tests.yml | 37 ++++++++++++++++++------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/.github/workflows/robot-tests.yml b/.github/workflows/robot-tests.yml index 01bda40..43c490b 100644 --- a/.github/workflows/robot-tests.yml +++ b/.github/workflows/robot-tests.yml @@ -140,6 +140,16 @@ jobs: retention-days: 15 # ---------- Allure ---------- + # + # NOTE: previously used simple-elf/allure-report-action, but that + # action's Docker image (openjdk:8-jre-alpine) was removed from + # Docker Hub upstream and the action is unmaintained, so the report + # generation is now done directly with the Allure CLI (installed via + # npm) instead of that action. + + - name: Install Allure CLI + if: always() + run: npm install -g allure-commandline # Retrieves the history of previous runs from the gh-pages branch. # continue-on-error covers the first run, when the branch does not exist yet. @@ -151,15 +161,16 @@ jobs: ref: gh-pages path: gh-pages + # Copies the previous run's history/ folder into allure-results so + # the Allure CLI picks it up and renders the trend graphs. + - name: Restore Allure history + if: always() + continue-on-error: true + run: cp -r gh-pages/history allure-results/history + - name: Generate Allure report with history if: always() - uses: simple-elf/allure-report-action@v1.12 - with: - allure_results: allure-results - gh_pages: gh-pages - allure_report: allure-report - allure_history: allure-history - keep_reports: 20 + run: allure generate allure-results --clean -o allure-report # Publishes to GitHub Pages only on pushes to main (and manual runs on # main), so that PRs with the "smoke" subset don't pollute the official @@ -170,7 +181,7 @@ jobs: with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_branch: gh-pages - publish_dir: allure-history + publish_dir: allure-report # On PRs, the Allure report is made available as a run artifact. - name: Upload Allure report artifact (PRs) @@ -183,14 +194,8 @@ jobs: # ---------- Email with Allure report ---------- - # The Allure CLI (via npm) generates the single-file version of the - # report: a self-contained index.html that's ideal as an email - # attachment. The Java required by the CLI is already installed on - # the ubuntu-latest runner. - - name: Install Allure CLI - if: always() - run: npm install -g allure-commandline - + # Single-file version of the report: a self-contained index.html + # that's ideal as an email attachment. - name: Generate single-file Allure report (email attachment) if: always() run: allure generate allure-results --single-file --clean -o allure-single From 0304f324d115fd5871d63dc98cc87193fb3e7df4 Mon Sep 17 00:00:00 2001 From: sub0br Date: Wed, 12 Aug 2026 23:56:38 -0300 Subject: [PATCH 4/6] ci: enable nightly full regression schedule --- .github/workflows/robot-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/robot-tests.yml b/.github/workflows/robot-tests.yml index 43c490b..3ebdce2 100644 --- a/.github/workflows/robot-tests.yml +++ b/.github/workflows/robot-tests.yml @@ -9,8 +9,8 @@ on: # To turn it back on: uncomment the two lines below and merge this file # into `main` (GitHub only reads `schedule` triggers from the workflow # file version on the repo's default branch, not from feature branches). - # schedule: - # - cron: '0 3 * * *' # 03:00 UTC = 00:00 (midnight) in Brasília + schedule: + - cron: '0 3 * * *' # 03:00 UTC = 00:00 (midnight) in Brasília workflow_dispatch: # allows manual trigger from the Actions tab inputs: tag: From 8d3772825ee3fdb67c65be37abac2e96e8548b38 Mon Sep 17 00:00:00 2001 From: sub0br Date: Thu, 13 Aug 2026 09:21:57 -0300 Subject: [PATCH 5/6] test: fix broken teardowns and create store products via API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - store.robot: create products via API with unique, random names instead of relying on fixed items from the shared public ServeRest catalog, which can collide with clutter from other students/QA courses (observed a duplicated "Logitech MX Vertical" break a locator in strict mode); reload the page after creation so the new product's card renders before interacting with it - admin.robot & store.robot: fix teardowns that were silently skipping cleanup — a test's own [Teardown] replaces the suite's Test Teardown instead of running alongside it, so "Cleanup Login Test" has to be chained explicitly; and Run Keywords needs "AND" even with a single keyword, otherwise its arguments get misread as extra keyword names to run - uppercase all keyword arguments and local variables project-wide, for a consistent style --- README.md | 101 +++++++++++++++-- resources/api/products_api.resource | 67 ++++++++--- resources/api/users_api.resource | 56 ++++----- resources/pages/global_page.resource | 51 ++++----- resources/pages/home_page.resource | 12 +- resources/pages/login_page.resource | 18 +-- resources/pages/newProduct_page.resource | 26 ++--- resources/pages/newUser_page.resource | 20 ++-- resources/pages/store_page.resource | 51 ++++++--- tests/admin/admin.robot | 97 ++++++++-------- tests/login/login.robot | 20 ++-- tests/store/store.robot | 137 ++++++++++++++++++----- 12 files changed, 431 insertions(+), 225 deletions(-) diff --git a/README.md b/README.md index f1189c5..dea6b23 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ robotframework/ ├── requirements.txt ├── resources/ │ ├── api/ +│ │ ├── products_api.resource │ │ └── users_api.resource │ ├── pages/ │ │ ├── global_page.resource @@ -96,6 +97,11 @@ random test data via Faker (`pt_BR` locale): the API, for tests that need to reach the admin area. - `Cleanup Login Test` — closes the browser and removes, via the API, the user created in the setup. + - `Invalidate User Session Token` — clears the browser's local storage, + simulating an expired or otherwise invalid session. + - `Alert Message Should Be` — asserts the generic dismissible alert + message shared by several forms across the app (login, new user, new + product, ...). - `Generate Random User` — returns a random name, email, and password (via `Generate Random Password`), using Faker. - `Generate Random Password` — generates a random alphanumeric password @@ -177,20 +183,23 @@ Page object for the admin's "create product" screen. Contains: Page object for the store/home screen's shopping list feature. Contains: -- **Locators**: `${HOME_BUTTON}`, `${ADD_TO_LIST_BUTTON}`, +- **Locators**: `${HOME_BUTTON}`, `${INCREASE_BUTTON}`, `${DECREASE_BUTTON}`, `${CLEAR_LIST_BUTTON}`, `${CART_LIST_EMPTY}`. - **Keywords**: - `Back To Home` — clicks the "Página Inicial" button to return to the home page. - `Clear List` — clicks the button to clear the shopping list. - - `Add Item To List` — finds a product card by its name and clicks the - button to add it to the shopping list. + - `Add Item To List` — finds a product card by its name (built as a + dynamic XPath, no fixed locator) and clicks the button to add it to + the shopping list. - `Item Should Be In List` — verifies that the given product is visible in the shopping cart list. - - `Increase Quantity of Item in List` — clicks the button to increase the - quantity of an item already in the shopping list. - - `Item Should Be Increased` — verifies that the quantity of the given - product has been increased in the shopping list. + - `Increase Quantity of Item in List` / `Decrease Quantity of Item in + List` — click the buttons to increase/decrease the quantity of an item + already in the shopping list. + - `Item Should Be Increased` / `Item Should Be Decreased` — verify that + the quantity of the given product went up/down accordingly in the + shopping list. - `List Should Be Empty` — verifies that the shopping list is empty. ### `resources/api/users_api.resource` @@ -206,6 +215,35 @@ through the UI: `administrador=true`, so it can log in and reach the admin area. - `Delete User Via Api` — deletes the user (by id) created for the test, keeping the test environment clean. +- `Get Users By Email Via Api` — queries all users registered with a given + email, returning how many were found and the matching records. +- `Delete All Users With Email Via Api` — deletes every user registered + with a given email. Used to clean up after tests that intentionally + create duplicated users (e.g. the double-click and duplicated-email + tests), where the id isn't known upfront. + +### `resources/api/products_api.resource` + +Support keywords that call the ServeRest REST API to prepare and clean up +test data (products) used by the UI tests. Unlike the user routes, the +product routes require an admin authorization token: + +- `Get Admin Auth Token` — logs in with the given admin credentials and + returns the authorization token required by the product creation/deletion + routes. +- `Create Product Via Api` — creates a product with the given fields, using + the given admin token, and returns the id of the created product. +- `Delete Product Via Api` — deletes the product (by id) created for the + test, using the given admin token. +- `Get Products By Name Via Api` — queries all products registered with a + given name, returning how many were found and the matching records. +- `Delete All Products With Name Via Api` — deletes every product + registered with a given name, using the given admin token. Used to clean + up after tests that intentionally create duplicated products. +- `Cleanup Product By Name Via Api` — obtains a fresh admin token with the + given credentials and removes every product registered with a given + name. Used to clean up after tests that create a product through the UI, + where no product id is known. ### `tests/login/login.robot` @@ -229,13 +267,32 @@ to the page object keywords described above. ### `tests/store/store.robot` Test suite covering the shopping list on the ServeRest store/home page. It -reuses `Prepare Login Test`/`Cleanup Login Test` (via `Open Browser To Home -Page`) to log in as a fresh API-created user before each test, then drives -the store page object to run scenarios such as: +reuses `Prepare Login Test` (via `Open Browser To Home Page`) to log in as a +fresh API-created shopper user before each test, then drives the store page +object to run scenarios such as: - Adding two items to the shopping list. -- Increasing the quantity of an item already in the list. - Clearing the shopping list. +- Increasing/decreasing the quantity of an item already in the list. + +Each `Given` step creates its own product(s) via the API (`Create Admin +User Via Api` + `Get Admin Auth Token` + `Create Product Via Api`, with a +Faker word name suffixed with a random string for uniqueness) instead of +relying on fixed catalog items, since the ServeRest catalog is a public, +shared demo environment where fixed product names can collide with +clutter created by other students/QA courses (this was observed in +practice: a duplicated "Logitech MX Vertical" card broke a locator in +strict mode). Because the store/home page has already loaded before the +`Given` step runs, it calls Browser library's `Reload` afterwards so the +newly created product's card appears before the `When` steps interact +with it. + +Each test case defines its own `[Teardown]`, chained with `AND` onto +`Cleanup Login Test`, to delete the product(s) and the temporary admin +user created for setup — a local `[Teardown]` replaces the suite's `Test +Teardown` rather than running in addition to it, so `Cleanup Login Test` +must be included explicitly in every custom teardown, or the browser +never closes and the shopper user is never deleted. The `*** Keywords ***` section of this file defines the Given/When/Then style keywords used by the test cases (e.g. `the user adds the first item to @@ -256,6 +313,26 @@ scenarios such as: - Creating a new product with randomly generated data (via `Generate Random Product`) and confirming it appears in the products table. - Listing all products and confirming the products table is displayed. +- An admin user being able to access the regular user's home page (store) + directly, without being blocked. +- The admin not being able to create a user or a product with a name/email + that already exists (negative cases), asserting the corresponding error + message. +- Double-clicking the submit button on the new user form not creating two + duplicated users. + +The five tests above that create extra data (new user, new product, the +two "cannot create duplicated ..." cases, and the double-click case) each +define their own `[Teardown]`, chained with `AND` +onto `Cleanup Login Test`, to delete that data via the API (e.g. `Delete +User Via Api`, `Delete All Users With Email Via Api`, `Cleanup Product By +Name Via Api`). A local `[Teardown]` replaces the suite's `Test Teardown` +instead of running in addition to it, so `Cleanup Login Test` has to be +included explicitly every time — and because `Run Keywords` only chains +multiple keywords when they're separated with `AND` (a single keyword +passed to it gets its arguments misread as more keyword names to run), a +teardown that runs just one cleanup keyword must call it directly instead +of wrapping it in `Run Keywords`. The `*** Keywords ***` section of this file defines the Given/When/Then style keywords used by the test cases (e.g. `the admin fills in the user @@ -271,7 +348,7 @@ without touching test code: | Dimension | Tags | Meaning | |-------------------|------------------------------------|---------| -| **Execution set** | `smoke`, `regression` | `regression` is on every test (the full suite). `smoke` marks the small, fast subset of critical happy paths — currently 5 of the 14 tests — meant to run on every PR for quick feedback. | +| **Execution set** | `smoke`, `regression` | `regression` is on every test (the full suite). `smoke` marks the small, fast subset of critical happy paths — currently 5 of the 21 tests — meant to run on every PR for quick feedback. | | **Criticality** | `critical`, `high`, `medium` | `critical` = core journeys the app is unusable without (login, admin create user/product, add to cart). `high` = important supporting flows (listing, quantity, clearing). `medium` = negative/validation edge cases. | | **Layer** | `ui` | All current tests drive the browser end-to-end (API is only used for setup/teardown). Kept as an explicit tag so future API-only suites can be filtered out (`--exclude ui`) or in (`--include ui`) separately. | diff --git a/resources/api/products_api.resource b/resources/api/products_api.resource index 7ee74e5..827122e 100644 --- a/resources/api/products_api.resource +++ b/resources/api/products_api.resource @@ -13,30 +13,61 @@ Get Admin Auth Token [Documentation] Logs in, via API, with the given admin credentials and ... returns the authorization token required by the ... product creation/deletion routes. - [Arguments] ${email} ${password} - ${body}= Create Dictionary email=${email} password=${password} - ${response}= POST ${API_BASE_URL}/login json=${body} expected_status=200 - ${token}= Set Variable ${response.json()}[authorization] - RETURN ${token} + [Arguments] ${EMAIL} ${PASSWORD} + ${BODY}= Create Dictionary email=${EMAIL} password=${PASSWORD} + ${RESPONSE}= POST ${API_BASE_URL}/login json=${BODY} expected_status=200 + ${TOKEN}= Set Variable ${RESPONSE.json()}[authorization] + RETURN ${TOKEN} Create Product Via Api [Documentation] Creates, via API, a product with the given fields, ... using the given admin authorization token, and ... returns the id of the created product. - [Arguments] ${name} ${price} ${description} ${quantity} ${admin_token} - ${body}= Create Dictionary - ... nome=${name} - ... preco=${price} - ... descricao=${description} - ... quantidade=${quantity} - ${headers}= Create Dictionary Authorization=${admin_token} - ${response}= POST ${API_BASE_URL}/produtos json=${body} headers=${headers} expected_status=201 - ${product_id}= Set Variable ${response.json()}[_id] - RETURN ${product_id} + [Arguments] ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY} ${ADMIN_TOKEN} + ${BODY}= Create Dictionary + ... nome=${NAME} + ... preco=${PRICE} + ... descricao=${DESCRIPTION} + ... quantidade=${QUANTITY} + ${HEADERS}= Create Dictionary Authorization=${ADMIN_TOKEN} + ${RESPONSE}= POST ${API_BASE_URL}/produtos json=${BODY} headers=${HEADERS} expected_status=201 + ${PRODUCT_ID}= Set Variable ${RESPONSE.json()}[_id] + RETURN ${PRODUCT_ID} Delete Product Via Api [Documentation] Removes, via API, the product created for the test, ... using the given admin authorization token. - [Arguments] ${product_id} ${admin_token} - ${headers}= Create Dictionary Authorization=${admin_token} - DELETE ${API_BASE_URL}/produtos/${product_id} headers=${headers} expected_status=200 + [Arguments] ${PRODUCT_ID} ${ADMIN_TOKEN} + ${HEADERS}= Create Dictionary Authorization=${ADMIN_TOKEN} + DELETE ${API_BASE_URL}/produtos/${PRODUCT_ID} headers=${HEADERS} expected_status=200 + +Get Products By Name Via Api + [Documentation] Queries, via API, all products registered with the given + ... name, returning how many were found and the list of + ... matching product records. + [Arguments] ${NAME} + ${PARAMS}= Create Dictionary nome=${NAME} + ${RESPONSE}= GET ${API_BASE_URL}/produtos params=${PARAMS} expected_status=200 + ${QUANTITY}= Set Variable ${RESPONSE.json()}[quantidade] + ${PRODUCTS}= Set Variable ${RESPONSE.json()}[produtos] + RETURN ${QUANTITY} ${PRODUCTS} + +Delete All Products With Name Via Api + [Documentation] Removes, via API, every product registered with the given + ... name, using the given admin authorization token. Used to + ... clean up after tests that intentionally try to create + ... duplicated products. + [Arguments] ${NAME} ${ADMIN_TOKEN} + ${QUANTITY} ${PRODUCTS}= Get Products By Name Via Api ${NAME} + FOR ${PRODUCT} IN @{PRODUCTS} + Delete Product Via Api ${PRODUCT}[_id] ${ADMIN_TOKEN} + END + +Cleanup Product By Name Via Api + [Documentation] Obtains a fresh admin token with the given credentials + ... and removes, via API, every product registered with the + ... given name. Used to clean up after tests that create a + ... product via the UI, where no product id is known. + [Arguments] ${NAME} ${EMAIL} ${PASSWORD} + ${ADMIN_TOKEN}= Get Admin Auth Token ${EMAIL} ${PASSWORD} + Delete All Products With Name Via Api ${NAME} ${ADMIN_TOKEN} diff --git a/resources/api/users_api.resource b/resources/api/users_api.resource index 43c9c91..21ce132 100644 --- a/resources/api/users_api.resource +++ b/resources/api/users_api.resource @@ -12,53 +12,53 @@ Create Standard User Via Api [Documentation] Creates, via API, a standard (non-admin) user with a ... unique email and returns the email, password, and id ... of the created user, to be used in the UI login test. - ${name} ${email} ${password}= Generate Random User - ${body}= Create Dictionary - ... nome=${name} - ... email=${email} - ... password=${password} + ${NAME} ${EMAIL} ${PASSWORD}= Generate Random User + ${BODY}= Create Dictionary + ... nome=${NAME} + ... email=${EMAIL} + ... password=${PASSWORD} ... administrador=false - ${response}= POST ${API_BASE_URL}/usuarios json=${body} expected_status=201 - ${user_id}= Set Variable ${response.json()}[_id] - RETURN ${email} ${password} ${user_id} + ${RESPONSE}= POST ${API_BASE_URL}/usuarios json=${BODY} expected_status=201 + ${USER_ID}= Set Variable ${RESPONSE.json()}[_id] + RETURN ${EMAIL} ${PASSWORD} ${USER_ID} Create Admin User Via Api [Documentation] Creates, via API, an admin user with a ... unique email and returns the email, password, and id ... of the created user, to be used in the UI login test. - ${name} ${email} ${password}= Generate Random User - ${body}= Create Dictionary - ... nome=${name} - ... email=${email} - ... password=${password} + ${NAME} ${EMAIL} ${PASSWORD}= Generate Random User + ${BODY}= Create Dictionary + ... nome=${NAME} + ... email=${EMAIL} + ... password=${PASSWORD} ... administrador=true - ${response}= POST ${API_BASE_URL}/usuarios json=${body} expected_status=201 - ${user_id}= Set Variable ${response.json()}[_id] - RETURN ${email} ${password} ${user_id} + ${RESPONSE}= POST ${API_BASE_URL}/usuarios json=${BODY} expected_status=201 + ${USER_ID}= Set Variable ${RESPONSE.json()}[_id] + RETURN ${EMAIL} ${PASSWORD} ${USER_ID} Delete User Via Api [Documentation] Removes, via API, the user created for the test, keeping ... the environment's test data clean. - [Arguments] ${user_id} - DELETE ${API_BASE_URL}/usuarios/${user_id} expected_status=200 + [Arguments] ${USER_ID} + DELETE ${API_BASE_URL}/usuarios/${USER_ID} expected_status=200 Get Users By Email Via Api [Documentation] Queries, via API, all users registered with the given ... email, returning how many were found and the list of ... matching user records. - [Arguments] ${email} - ${params}= Create Dictionary email=${email} - ${response}= GET ${API_BASE_URL}/usuarios params=${params} expected_status=200 - ${quantity}= Set Variable ${response.json()}[quantidade] - ${users}= Set Variable ${response.json()}[usuarios] - RETURN ${quantity} ${users} + [Arguments] ${EMAIL} + ${PARAMS}= Create Dictionary email=${EMAIL} + ${RESPONSE}= GET ${API_BASE_URL}/usuarios params=${PARAMS} expected_status=200 + ${QUANTITY}= Set Variable ${RESPONSE.json()}[quantidade] + ${USERS}= Set Variable ${RESPONSE.json()}[usuarios] + RETURN ${QUANTITY} ${USERS} Delete All Users With Email Via Api [Documentation] Removes, via API, every user registered with the given ... email. Used to clean up after tests that intentionally ... try to create duplicated users. - [Arguments] ${email} - ${quantity} ${users}= Get Users By Email Via Api ${email} - FOR ${user} IN @{users} - Delete User Via Api ${user}[_id] + [Arguments] ${EMAIL} + ${QUANTITY} ${USERS}= Get Users By Email Via Api ${EMAIL} + FOR ${USER} IN @{USERS} + Delete User Via Api ${USER}[_id] END diff --git a/resources/pages/global_page.resource b/resources/pages/global_page.resource index 339d11c..bfba307 100644 --- a/resources/pages/global_page.resource +++ b/resources/pages/global_page.resource @@ -1,6 +1,7 @@ *** Settings *** Documentation Page object for common actions. Library Browser +Library String Resource ../variables/global.resource Resource ../../resources/api/users_api.resource @@ -18,19 +19,19 @@ Open Login Page Prepare Login Test [Documentation] Creates a valid user via API and opens the login page, ... leaving email/password/id available for the test and teardown. - ${email} ${password} ${user_id}= Create Standard User Via Api - Set Test Variable ${EMAIL} ${email} - Set Test Variable ${PASSWORD} ${password} - Set Test Variable ${USER_ID} ${user_id} + ${EMAIL} ${PASSWORD} ${USER_ID}= Create Standard User Via Api + Set Test Variable ${EMAIL} ${EMAIL} + Set Test Variable ${PASSWORD} ${PASSWORD} + Set Test Variable ${USER_ID} ${USER_ID} Open Login Page Prepare Admin Login Test [Documentation] Creates a valid user via API and opens the login page, ... leaving email/password/id available for the test and teardown. - ${email} ${password} ${user_id}= Create Admin User Via Api - Set Test Variable ${EMAIL} ${email} - Set Test Variable ${PASSWORD} ${password} - Set Test Variable ${USER_ID} ${user_id} + ${EMAIL} ${PASSWORD} ${USER_ID}= Create Admin User Via Api + Set Test Variable ${EMAIL} ${EMAIL} + Set Test Variable ${PASSWORD} ${PASSWORD} + Set Test Variable ${USER_ID} ${USER_ID} Open Login Page Cleanup Login Test @@ -49,30 +50,30 @@ Alert Message Should Be ... current page matches the expected one. Several forms ... across the app (login, new user, new product, ...) ... share this same generic dismissible alert component. - [Arguments] ${expected_message} + [Arguments] ${EXPECTED_MESSAGE} Wait For Elements State ${ALERT_MESSAGE} visible - ${actual_message}= Get Text ${ALERT_MESSAGE} - Should Be Equal As Strings ${actual_message} ${expected_message} + ${ACTUAL_MESSAGE}= Get Text ${ALERT_MESSAGE} + Should Be Equal As Strings ${ACTUAL_MESSAGE} ${EXPECTED_MESSAGE} Generate Random User [Documentation] Return name, email and password using Faker (pt_BR) - ${fake}= Evaluate faker.Faker('pt_BR') modules=faker - ${name}= Evaluate $fake.name() - ${email}= Evaluate $fake.email() - ${password}= Generate Random Password - RETURN ${name} ${email} ${password} + ${FAKE}= Evaluate faker.Faker('pt_BR') modules=faker + ${NAME}= Evaluate $FAKE.name() + ${EMAIL}= Evaluate $FAKE.email() + ${PASSWORD}= Generate Random Password + RETURN ${NAME} ${EMAIL} ${PASSWORD} Generate Random Password [Documentation] Generates a random password with a default length of 10 characters. - [Arguments] ${length}=10 - ${password}= Generate Random String ${length} [LOWER][UPPER][NUMBERS] - RETURN ${password} + [Arguments] ${LENGTH}=10 + ${PASSWORD}= Generate Random String ${LENGTH} [LOWER][UPPER][NUMBERS] + RETURN ${PASSWORD} Generate Random Product [Documentation] Return name, price, description and quantity using Faker (pt_BR) - ${fake}= Evaluate faker.Faker('pt_BR') modules=faker - ${productName}= Evaluate $fake.word() - ${price}= Evaluate $fake.random_number(digits=5, fix_len=True) - ${description}= Evaluate $fake.sentence() - ${quantity}= Evaluate $fake.random_number(digits=2, fix_len=True) - RETURN ${productName} ${price} ${description} ${quantity} \ No newline at end of file + ${FAKE}= Evaluate faker.Faker('pt_BR') modules=faker + ${PRODUCT_NAME}= Evaluate $FAKE.word() + ${PRICE}= Evaluate $FAKE.random_number(digits=5, fix_len=True) + ${DESCRIPTION}= Evaluate $FAKE.sentence() + ${QUANTITY}= Evaluate $FAKE.random_number(digits=2, fix_len=True) + RETURN ${PRODUCT_NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY} diff --git a/resources/pages/home_page.resource b/resources/pages/home_page.resource index 84c732c..496bda3 100644 --- a/resources/pages/home_page.resource +++ b/resources/pages/home_page.resource @@ -21,8 +21,8 @@ Home Page Should Be Displayed ... is done via SPA (client-side), asynchronously after ... clicking "Entrar". Wait For Elements State ${LOGOUT_BUTTON} visible - ${current_url}= Get Url - Should Be Equal As Strings ${current_url} ${BASE_URL}/home + ${CURRENT_URL}= Get Url + Should Be Equal As Strings ${CURRENT_URL} ${BASE_URL}/home Admin Page Should Be Displayed [Documentation] Confirms that the user was redirected to the admin @@ -32,8 +32,8 @@ Admin Page Should Be Displayed ... is done via SPA (client-side), asynchronously after ... clicking "Entrar". Wait For Elements State ${LOGOUT_BUTTON} visible - ${current_url}= Get Url - Should Be Equal As Strings ${current_url} ${BASE_URL}/admin/home + ${CURRENT_URL}= Get Url + Should Be Equal As Strings ${CURRENT_URL} ${BASE_URL}/admin/home Click Cadastrar Button On Cadastro De Usuario Card [Documentation] Clicks the "Cadastrar" button on the "Cadastro de Usuario" @@ -85,5 +85,5 @@ Admin Page Should Not Be Displayed ... correct behavior, so it currently fails until that ... authorization defect is fixed. Wait For Elements State ${CREATE_USER_BUTTON} hidden timeout=5s - ${current_url}= Get Url - Should Not Be Equal As Strings ${current_url} ${BASE_URL}/admin/home \ No newline at end of file + ${CURRENT_URL}= Get Url + Should Not Be Equal As Strings ${CURRENT_URL} ${BASE_URL}/admin/home \ No newline at end of file diff --git a/resources/pages/login_page.resource b/resources/pages/login_page.resource index 9310674..7e1aac7 100644 --- a/resources/pages/login_page.resource +++ b/resources/pages/login_page.resource @@ -12,13 +12,13 @@ ${LOGIN_ERROR_MESSAGE} .alert-dismissible > span *** Keywords *** Input Email [Documentation] Fills in the email field. - [Arguments] ${email} - Fill Text ${EMAIL_INPUT} ${email} + [Arguments] ${EMAIL} + Fill Text ${EMAIL_INPUT} ${EMAIL} Input Password [Documentation] Fills in the password field. - [Arguments] ${password} - Fill Text ${PASSWORD_INPUT} ${password} + [Arguments] ${PASSWORD} + Fill Text ${PASSWORD_INPUT} ${PASSWORD} Click Entrar Button [Documentation] Clicks the "Entrar" button to submit the login form. @@ -27,10 +27,10 @@ Click Entrar Button Login Error Message Should Be [Documentation] Confirms that the error message displayed on the login screen ... matches the expected one. - [Arguments] ${expected_message} + [Arguments] ${EXPECTED_MESSAGE} Wait For Elements State ${LOGIN_ERROR_MESSAGE} visible - ${actual_message}= Get Text ${LOGIN_ERROR_MESSAGE} - Should Be Equal As Strings ${actual_message} ${expected_message} + ${ACTUAL_MESSAGE}= Get Text ${LOGIN_ERROR_MESSAGE} + Should Be Equal As Strings ${ACTUAL_MESSAGE} ${EXPECTED_MESSAGE} Login Page Should Be Displayed [Documentation] Confirms that the user was redirected to the login @@ -38,5 +38,5 @@ Login Page Should Be Displayed ... with an expired or invalid session), by waiting for ... the email field and checking the current URL. Wait For Elements State ${EMAIL_INPUT} visible - ${current_url}= Get Url - Should Be Equal As Strings ${current_url} ${BASE_URL}/login + ${CURRENT_URL}= Get Url + Should Be Equal As Strings ${CURRENT_URL} ${BASE_URL}/login diff --git a/resources/pages/newProduct_page.resource b/resources/pages/newProduct_page.resource index ce991da..0cecd80 100644 --- a/resources/pages/newProduct_page.resource +++ b/resources/pages/newProduct_page.resource @@ -10,25 +10,25 @@ ${NEW_PRODUCT_QUANTITY} [data-testid="quantity"] ${NEW_PRODUCT_CADASTRAR_BUTTON} [data-testid="cadastarProdutos"] *** Keywords *** -Input New Product Name +Input New Product Name [Documentation] Fills in the name field on the new product registration form. - [Arguments] ${productName} - Fill Text ${NEW_PRODUCT_NAME} ${productName} + [Arguments] ${PRODUCT_NAME} + Fill Text ${NEW_PRODUCT_NAME} ${PRODUCT_NAME} Input New Product Price [Documentation] Fills in the price field on the new product registration form. - [Arguments] ${price} - Fill Text ${NEW_PRODUCT_PRICE} ${price} + [Arguments] ${PRICE} + Fill Text ${NEW_PRODUCT_PRICE} ${PRICE} Input New Product Description [Documentation] Fills in the description field on the new product registration form. - [Arguments] ${description} - Fill Text ${NEW_PRODUCT_DESCRIPTION} ${description} + [Arguments] ${DESCRIPTION} + Fill Text ${NEW_PRODUCT_DESCRIPTION} ${DESCRIPTION} Input New Product Quantity [Documentation] Fills in the quantity field on the new product registration form. - [Arguments] ${quantity} - Fill Text ${NEW_PRODUCT_QUANTITY} ${quantity} + [Arguments] ${QUANTITY} + Fill Text ${NEW_PRODUCT_QUANTITY} ${QUANTITY} Click Cadastrar Button on New Product Form [Documentation] Clicks the "Cadastrar" button to submit the new product registration form. @@ -36,7 +36,7 @@ Click Cadastrar Button on New Product Form Product Should Be Created [Documentation] Verifies that the new product has been created successfully. - [Arguments] ${productName} - ${locator}= Set Variable ${USERS_TABLE}//td[normalize-space(text())='${productName}'] - Wait For Elements State ${locator} visible timeout=10s - # Add verification steps here, such as checking for a success message or the presence of the new product in the product list. \ No newline at end of file + [Arguments] ${PRODUCT_NAME} + ${LOCATOR}= Set Variable ${USERS_TABLE}//td[normalize-space(text())='${PRODUCT_NAME}'] + Wait For Elements State ${LOCATOR} visible timeout=10s + # Add verification steps here, such as checking for a success message or the presence of the new product in the product list. diff --git a/resources/pages/newUser_page.resource b/resources/pages/newUser_page.resource index 9c6cc62..f8d2b88 100644 --- a/resources/pages/newUser_page.resource +++ b/resources/pages/newUser_page.resource @@ -9,20 +9,20 @@ ${NEW_USER_PASSWORD} [data-testid="password"] ${NEW_USER_CADASTRAR_BUTTON} [data-testid="cadastrarUsuario"] *** Keywords *** -Input New Name +Input New Name [Documentation] Fills in the name field on the new user registration form. - [Arguments] ${name} - Fill Text ${NEW_USER_NAME} ${name} + [Arguments] ${NAME} + Fill Text ${NEW_USER_NAME} ${NAME} Input New Email [Documentation] Fills in the email field on the new user registration form. - [Arguments] ${email} - Fill Text ${NEW_USER_EMAIL} ${email} + [Arguments] ${EMAIL} + Fill Text ${NEW_USER_EMAIL} ${EMAIL} Input New Password [Documentation] Fills in the password field on the new user registration form. - [Arguments] ${password} - Fill Text ${NEW_USER_PASSWORD} ${password} + [Arguments] ${PASSWORD} + Fill Text ${NEW_USER_PASSWORD} ${PASSWORD} Click Cadastrar Button [Documentation] Clicks the "Cadastrar" button to submit the new user registration form. @@ -38,6 +38,6 @@ Double Click Cadastrar Button User Should Be Created [Documentation] Confirms that the user was created successfully by ... checking for a success message on the screen. - [Arguments] ${email} - ${locator}= Set Variable ${USERS_TABLE}//td[normalize-space(text())='${email}'] - Wait For Elements State ${locator} visible timeout=10s \ No newline at end of file + [Arguments] ${EMAIL} + ${LOCATOR}= Set Variable ${USERS_TABLE}//td[normalize-space(text())='${EMAIL}'] + Wait For Elements State ${LOCATOR} visible timeout=10s \ No newline at end of file diff --git a/resources/pages/store_page.resource b/resources/pages/store_page.resource index 3edcbff..d1d2dec 100644 --- a/resources/pages/store_page.resource +++ b/resources/pages/store_page.resource @@ -4,9 +4,10 @@ Resource ../variables/global.resource *** Variables *** ${HOME_BUTTON} [data-testid="paginaInicial"] -${ADD_TO_LIST_BUTTON} [data-testid="product-increase-quantity"] -${CLEAR_LIST_BUTTON} [data-testid="limparLista"] -${CART_LIST_EMPTY} [data-testid="shopping-cart-empty-message"] +${INCREASE_BUTTON} [data-testid="product-increase-quantity"] +${DECREASE_BUTTON} [data-testid="product-decrease-quantity"] +${CLEAR_LIST_BUTTON} [data-testid="limparLista"] +${CART_LIST_EMPTY} [data-testid="shopping-cart-empty-message"] *** Keywords *** Back To Home @@ -19,31 +20,45 @@ Clear List Add Item To List [Documentation] Finds the product card by its name and clicks the button to add it to the shopping list. - [Arguments] ${product_name} - ${card_xpath}= Set Variable - ... //h5[contains(@class,"card-title") and contains(normalize-space(.), "${product_name}")]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " card ") or contains(@class, "col-3")][1] - Click xpath=${card_xpath}//button[@data-testid="adicionarNaLista"] + [Arguments] ${PRODUCT_NAME} + ${CARD_XPATH}= Set Variable + ... //h5[contains(@class,"card-title") and contains(normalize-space(.), "${PRODUCT_NAME}")]/ancestor::div[contains(concat(" ", normalize-space(@class), " "), " card ") or contains(@class, "col-3")][1] + Click xpath=${CARD_XPATH}//button[@data-testid="adicionarNaLista"] Item Should Be In List [Documentation] Verifies that the given product is visible in the shopping cart list. - [Arguments] ${product_name} - ${xpath}= Set Variable - ... //div[@data-testid="shopping-cart-product-name"][contains(normalize-space(.), "${product_name}")] - Wait For Elements State xpath=${xpath} visible timeout=10s + [Arguments] ${PRODUCT_NAME} + ${XPATH}= Set Variable + ... //div[@data-testid="shopping-cart-product-name"][contains(normalize-space(.), "${PRODUCT_NAME}")] + Wait For Elements State xpath=${XPATH} visible timeout=10s Increase Quantity of Item in List [Documentation] Clicks the button to increase the quantity of an item already in the shopping list. - Click ${ADD_TO_LIST_BUTTON} + Click ${INCREASE_BUTTON} + +Decrease Quantity of Item in List + [Documentation] Clicks the button to decrease the quantity of an item already in the shopping list. + Click ${DECREASE_BUTTON} Item Should Be Increased [Documentation] Verifies that the quantity of the given product has been increased in the shopping list. - [Arguments] ${product_name} - ${xpath}= Set Variable + [Arguments] ${PRODUCT_NAME} + ${XPATH}= Set Variable + ... //div[@id='root']/div[@class='App']/div/div[@class='jumbotron']/div[@class='container-fluid']/div/section[@class='row espacamento']/div[@class='card col-3'][1]/div[@class='card-body']/div[@class='row']/div[@class='col-3'][2]/p + Wait For Elements State xpath=${XPATH} visible timeout=10s + ${QUANTITY_TXT}= Get Text xpath=${XPATH} + ${QUANTITY}= Convert To Integer ${QUANTITY_TXT} + Should be True ${QUANTITY} > 1 msg=Expected quantity to be greater than 1, but got ${QUANTITY}. + +Item Should Be Decreased + [Documentation] Verifies that the quantity of the given product has been decreased in the shopping list. + [Arguments] ${PRODUCT_NAME} + ${XPATH}= Set Variable ... //div[@id='root']/div[@class='App']/div/div[@class='jumbotron']/div[@class='container-fluid']/div/section[@class='row espacamento']/div[@class='card col-3'][1]/div[@class='card-body']/div[@class='row']/div[@class='col-3'][2]/p - Wait For Elements State xpath=${xpath} visible timeout=10s - ${quantity_txt}= Get Text xpath=${xpath} - ${quantity}= Convert To Integer ${quantity_txt} - Should be True ${quantity} > 1 msg=Expected quantity to be greater than 1, but got ${quantity}. + Wait For Elements State xpath=${XPATH} visible timeout=10s + ${QUANTITY_TXT}= Get Text xpath=${XPATH} + ${QUANTITY}= Convert To Integer ${QUANTITY_TXT} + Should be True ${QUANTITY} == 1 msg=Expected quantity to be 1, but got ${QUANTITY}. List Should Be Empty [Documentation] Verifies that the shopping list is empty. diff --git a/tests/admin/admin.robot b/tests/admin/admin.robot index adf6b7b..896a104 100644 --- a/tests/admin/admin.robot +++ b/tests/admin/admin.robot @@ -14,10 +14,12 @@ Test Teardown Cleanup Login Test Admin Wants To Create a New User [Documentation] This test case verifies that an admin can create a new user. [Tags] admin ui smoke regression critical - ${name} ${email} ${password}= Generate Random User - Given the admin wants to create a new user + [Teardown] Run Keywords Delete All Users With Email Via Api ${EMAIL} + ... AND Cleanup Login Test + ${NAME} ${EMAIL} ${PASSWORD}= Generate Random User + Given the admin wants to create a new user When the admin clicks on the "Cadastrar" button on the Cadastro de Usuário card - And the admin fills in the user details with valid information ${name} ${email} ${password} + And the admin fills in the user details with valid information ${NAME} ${EMAIL} ${PASSWORD} And the admin clicks on the "Cadastrar" button to submit the form Then the new user should be created successfully @@ -31,12 +33,14 @@ Admin Wants To See The List Of Users Admin Wants To Create A New Product [Documentation] This test case verifies that an admin can create a new product. [Tags] admin ui smoke regression critical - ${productName} ${price} ${description} ${quantity}= Generate Random Product + [Teardown] Run Keywords Cleanup Product By Name Via Api ${PRODUCT_NAME} ${EMAIL} ${PASSWORD} + ... AND Cleanup Login Test + ${PRODUCT_NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY}= Generate Random Product Given the admin wants to create a new product When the admin clicks on the "Cadastrar" button on the Cadastrar Produtos card - And the admin fills in the product details with valid information ${productName} ${price} ${description} ${quantity} + And the admin fills in the product details with valid information ${PRODUCT_NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY} And the admin clicks on the "Cadastrar" button to submit the product form - Then the new product should be created successfully ${productName} + Then the new product should be created successfully ${PRODUCT_NAME} Admin Wants To List All Products [Documentation] This test case verifies that an admin can see the list of products. @@ -89,29 +93,28 @@ Double Click On Submit Should Not Create Duplicated User Open Browser To Admin Page [Documentation] Opens the browser and navigates to the admin page. Prepare Admin Login Test - Input Email ${email} - Input Password ${password} + Input Email ${EMAIL} + Input Password ${PASSWORD} Click Entrar Button Admin Page Should Be Displayed -the admin wants to create a new user +the admin wants to create a new user No Operation the admin clicks on the "Cadastrar" button on the Cadastro de Usuário card Click Cadastrar Button On Cadastro De Usuario Card the admin fills in the user details with valid information - [Arguments] ${name} ${email} ${password} - Input New Name ${name} - Input New Email ${email} - Input New Password ${password} - + [Arguments] ${NAME} ${EMAIL} ${PASSWORD} + Input New Name ${NAME} + Input New Email ${EMAIL} + Input New Password ${PASSWORD} the admin clicks on the "Cadastrar" button to submit the form Click Cadastrar Button the new user should be created successfully - User Should Be Created ${email} + User Should Be Created ${EMAIL} the admin wants to see the list of users No Operation @@ -129,18 +132,18 @@ the admin clicks on the "Cadastrar" button on the Cadastrar Produtos card Click Cadastrar Button On Cadastrar Produtos Card the admin fills in the product details with valid information - [Arguments] ${productName} ${price} ${description} ${quantity} - Input New Product Name ${productName} - Input New Product Price ${price} - Input New Product Description ${description} - Input New Product Quantity ${quantity} + [Arguments] ${PRODUCT_NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY} + Input New Product Name ${PRODUCT_NAME} + Input New Product Price ${PRICE} + Input New Product Description ${DESCRIPTION} + Input New Product Quantity ${QUANTITY} the admin clicks on the "Cadastrar" button to submit the product form Click Cadastrar Button on New Product Form the new product should be created successfully - [Arguments] ${productName} - Product Should Be Created ${productName} + [Arguments] ${PRODUCT_NAME} + Product Should Be Created ${PRODUCT_NAME} the admin wants to see the list of products No Operation @@ -161,50 +164,50 @@ the home page should be displayed Home Page Should Be Displayed a user already exists with a known email - ${duplicate_email} ${duplicate_password} ${duplicate_user_id}= Create Standard User Via Api - Set Test Variable ${DUPLICATE_EMAIL} ${duplicate_email} - Set Test Variable ${DUPLICATE_USER_ID} ${duplicate_user_id} + ${DUPLICATE_EMAIL} ${DUPLICATE_PASSWORD} ${DUPLICATE_USER_ID}= Create Standard User Via Api + Set Test Variable ${DUPLICATE_EMAIL} ${DUPLICATE_EMAIL} + Set Test Variable ${DUPLICATE_USER_ID} ${DUPLICATE_USER_ID} the admin tries to create a new user with the same email - ${name} ${email} ${password}= Generate Random User + ${NAME} ${EMAIL} ${PASSWORD}= Generate Random User Click Cadastrar Button On Cadastro De Usuario Card - Input New Name ${name} + Input New Name ${NAME} Input New Email ${DUPLICATE_EMAIL} - Input New Password ${password} + Input New Password ${PASSWORD} Click Cadastrar Button a product already exists with a known name - ${name} ${price} ${description} ${quantity}= Generate Random Product - ${admin_token}= Get Admin Auth Token ${EMAIL} ${PASSWORD} - ${product_id}= Create Product Via Api ${name} ${price} ${description} ${quantity} ${admin_token} - Set Test Variable ${DUPLICATE_PRODUCT_NAME} ${name} - Set Test Variable ${DUPLICATE_PRODUCT_ID} ${product_id} - Set Test Variable ${ADMIN_TOKEN} ${admin_token} + ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY}= Generate Random Product + ${ADMIN_TOKEN}= Get Admin Auth Token ${EMAIL} ${PASSWORD} + ${PRODUCT_ID}= Create Product Via Api ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY} ${ADMIN_TOKEN} + Set Test Variable ${DUPLICATE_PRODUCT_NAME} ${NAME} + Set Test Variable ${DUPLICATE_PRODUCT_ID} ${PRODUCT_ID} + Set Test Variable ${ADMIN_TOKEN} ${ADMIN_TOKEN} the admin tries to create a new product with the same name - ${other_name} ${price} ${description} ${quantity}= Generate Random Product + ${OTHER_NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY}= Generate Random Product Click Cadastrar Button On Cadastrar Produtos Card Input New Product Name ${DUPLICATE_PRODUCT_NAME} - Input New Product Price ${price} - Input New Product Description ${description} - Input New Product Quantity ${quantity} + Input New Product Price ${PRICE} + Input New Product Description ${DESCRIPTION} + Input New Product Quantity ${QUANTITY} Click Cadastrar Button on New Product Form -the message "${message}" must appear - Alert Message Should Be ${message} +the message "${MESSAGE}" must appear + Alert Message Should Be ${MESSAGE} the admin fills in valid user details - ${name} ${email} ${password}= Generate Random User + ${NAME} ${EMAIL} ${PASSWORD}= Generate Random User Click Cadastrar Button On Cadastro De Usuario Card - Input New Name ${name} - Input New Email ${email} - Input New Password ${password} - Set Test Variable ${NEW_USER_EMAIL} ${email} + Input New Name ${NAME} + Input New Email ${EMAIL} + Input New Password ${PASSWORD} + Set Test Variable ${NEW_USER_EMAIL} ${EMAIL} the admin double clicks the submit button Double Click Cadastrar Button only one user should be created with that email User Should Be Created ${NEW_USER_EMAIL} - ${quantity} ${users}= Get Users By Email Via Api ${NEW_USER_EMAIL} - Should Be Equal As Integers ${quantity} 1 \ No newline at end of file + ${QUANTITY} ${USERS}= Get Users By Email Via Api ${NEW_USER_EMAIL} + Should Be Equal As Integers ${QUANTITY} 1 diff --git a/tests/login/login.robot b/tests/login/login.robot index dc40e96..4d066c5 100644 --- a/tests/login/login.robot +++ b/tests/login/login.robot @@ -23,7 +23,7 @@ User With Valid Credentials Should Be Redirected To The Home Admin Can Access Admin Page [Documentation] This test case verifies that an admin user can access the admin page. [Tags] admin login ui smoke regression critical - Given the admin user wants to access the admin page + Given the admin user wants to access the admin page When this admin user types the email and password Then the admin page should be displayed @@ -108,12 +108,12 @@ a user is trying to login No Operation this user types the email - [Arguments] ${email} - Input Email ${email} + [Arguments] ${EMAIL} + Input Email ${EMAIL} this user types the password - [Arguments] ${password} - Input Password ${password} + [Arguments] ${PASSWORD} + Input Password ${PASSWORD} clicks on Entrar Click Entrar Button @@ -121,15 +121,15 @@ clicks on Entrar this user must be redirected to the home page Home Page Should Be Displayed -the message "${message}" must appear - Login Error Message Should Be ${message} +the message "${MESSAGE}" must appear + Login Error Message Should Be ${MESSAGE} the admin user wants to access the admin page Prepare Admin Login Test this admin user types the email and password - Input Email ${email} - Input Password ${password} + Input Email ${EMAIL} + Input Password ${PASSWORD} Click Entrar Button the admin page should be displayed @@ -157,4 +157,4 @@ this user navigates directly to the admin home URL Navigate To Admin Home Page the admin page should not be displayed - Admin Page Should Not Be Displayed \ No newline at end of file + Admin Page Should Not Be Displayed diff --git a/tests/store/store.robot b/tests/store/store.robot index bdfb8bf..1ed37c7 100644 --- a/tests/store/store.robot +++ b/tests/store/store.robot @@ -1,6 +1,8 @@ *** Settings *** Resource ../../resources/variables/global.resource Resource ../../resources/pages/global_page.resource +Resource ../../resources/api/products_api.resource +Resource ../../resources/api/users_api.resource Resource ../../resources/pages/home_page.resource Resource ../../resources/pages/login_page.resource Resource ../../resources/pages/store_page.resource @@ -11,71 +13,148 @@ Test Teardown Cleanup Login Test User Can Add 2 Items to List [Documentation] This test case verifies that a user can add two items to the list. [Tags] store list ui smoke regression critical - Given the user wants to add 2 items to the list - When the user adds the first item to the list Logitech MX Vertical - And the user adds the second item to the list Samsung 60 polegadas + [Teardown] Run Keywords Delete Product Via Api ${PRODUCT_ID_1} ${ADMIN_TOKEN} + ... AND Delete Product Via Api ${PRODUCT_ID_2} ${ADMIN_TOKEN} + ... AND Delete User Via Api ${ADMIN_ID} + ... AND Cleanup Login Test + Given the user wants to add 2 items to the list + When the user adds the first item to the list ${PRODUCT_NAME_1} + And the user adds the second item to the list ${PRODUCT_NAME_2} Then the list should contain 2 items +User Can Clear the List + [Documentation] This test case verifies that a user can clear the list. + [Tags] store list ui regression high + [Teardown] Run Keywords Delete Product Via Api ${PRODUCT_ID} ${ADMIN_TOKEN} + ... AND Delete User Via Api ${ADMIN_ID} + ... AND Cleanup Login Test + Given the user wants to clear the list + When the user adds an item to the list ${PRODUCT_NAME} + And the user clears the list + Then the list should be empty + User Can Increase Quantity of an Item in the List [Documentation] This test case verifies that a user can increase the quantity of an item in the list. [Tags] store list ui regression high - Given the user wants to increase item in the list - When the user adds an item to the list Logitech MX Vertical + [Teardown] Run Keywords Delete Product Via Api ${PRODUCT_ID} ${ADMIN_TOKEN} + ... AND Delete User Via Api ${ADMIN_ID} + ... AND Cleanup Login Test + Given the user wants to increase item in the list + When the user adds an item to the list ${PRODUCT_NAME} And the user increases the quantity of the item in the list Then the quantity of the item in the list should be bigger than 1 -User Can Clear the List - [Documentation] This test case verifies that a user can clear the list. +User Can Decrease Quantity of an Item in the List + [Documentation] This test case verifies that a user can decrease the quantity of an item in the list. [Tags] store list ui regression high - Given the user wants to clear the list - When the user adds an item to the list Logitech MX Vertical - And the user clears the list - Then the list should be empty + [Teardown] Run Keywords Delete Product Via Api ${PRODUCT_ID} ${ADMIN_TOKEN} + ... AND Delete User Via Api ${ADMIN_ID} + ... AND Cleanup Login Test + Given the user wants to decrease item in the list + When the user adds an item to the list ${PRODUCT_NAME} + And the user increases the quantity of the item in the list + And the user decreases the quantity of the item in the list + Then the quantity of the item in the list should be 1 *** Keywords *** Open Browser To Home Page [Documentation] Opens the browser and navigates to the home page. Prepare Login Test - Input Email ${email} - Input Password ${password} + Input Email ${EMAIL} + Input Password ${PASSWORD} Click Entrar Button Home Page Should Be Displayed -the user wants to add 2 items to the list - No Operation +the user wants to add 2 items to the list + ${NAME_1} ${PRICE_1} ${DESCRIPTION_1} ${QUANTITY_1}= Generate Random Product + ${NAME_2} ${PRICE_2} ${DESCRIPTION_2} ${QUANTITY_2}= Generate Random Product + ${SUFFIX_1}= Generate Random String 6 [LOWER][NUMBERS] + ${SUFFIX_2}= Generate Random String 6 [LOWER][NUMBERS] + ${NAME_1}= Catenate SEPARATOR= ${NAME_1} ${SUFFIX_1} + ${NAME_2}= Catenate SEPARATOR= ${NAME_2} ${SUFFIX_2} + ${ADMIN_EMAIL} ${ADMIN_PASSWORD} ${ADMIN_ID}= Create Admin User Via Api + ${ADMIN_TOKEN}= Get Admin Auth Token ${ADMIN_EMAIL} ${ADMIN_PASSWORD} + ${PRODUCT_ID_1}= Create Product Via Api ${NAME_1} ${PRICE_1} ${DESCRIPTION_1} ${QUANTITY_1} ${ADMIN_TOKEN} + ${PRODUCT_ID_2}= Create Product Via Api ${NAME_2} ${PRICE_2} ${DESCRIPTION_2} ${QUANTITY_2} ${ADMIN_TOKEN} + Set Test Variable ${PRODUCT_NAME_1} ${NAME_1} + Set Test Variable ${PRODUCT_NAME_2} ${NAME_2} + Set Test Variable ${PRODUCT_ID_1} ${PRODUCT_ID_1} + Set Test Variable ${PRODUCT_ID_2} ${PRODUCT_ID_2} + Set Test Variable ${ADMIN_ID} ${ADMIN_ID} + Set Test Variable ${ADMIN_TOKEN} ${ADMIN_TOKEN} + Reload the user adds the first item to the list - [Arguments] ${product_name} - Add Item To List ${product_name} + [Arguments] ${PRODUCT_NAME} + Add Item To List ${PRODUCT_NAME} Back To Home - + the user adds the second item to the list - [Arguments] ${product_name} - Add Item To List ${product_name} + [Arguments] ${PRODUCT_NAME} + Add Item To List ${PRODUCT_NAME} the list should contain 2 items - Item Should Be In List Logitech MX Vertical - Item Should Be In List Samsung 60 polegadas + Item Should Be In List ${PRODUCT_NAME_1} + Item Should Be In List ${PRODUCT_NAME_2} -the user wants to increase item in the list - No Operation +the user wants to increase item in the list + ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY}= Generate Random Product + ${SUFFIX}= Generate Random String 6 [LOWER][NUMBERS] + ${NAME}= Catenate SEPARATOR= ${NAME} ${SUFFIX} + ${ADMIN_EMAIL} ${ADMIN_PASSWORD} ${ADMIN_ID}= Create Admin User Via Api + ${ADMIN_TOKEN}= Get Admin Auth Token ${ADMIN_EMAIL} ${ADMIN_PASSWORD} + ${PRODUCT_ID}= Create Product Via Api ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY} ${ADMIN_TOKEN} + Set Test Variable ${PRODUCT_NAME} ${NAME} + Set Test Variable ${PRODUCT_ID} ${PRODUCT_ID} + Set Test Variable ${ADMIN_ID} ${ADMIN_ID} + Set Test Variable ${ADMIN_TOKEN} ${ADMIN_TOKEN} + Reload the user adds an item to the list - [Arguments] ${product_name} - Add Item To List ${product_name} + [Arguments] ${PRODUCT_NAME} + Add Item To List ${PRODUCT_NAME} the user increases the quantity of the item in the list Increase Quantity of Item in List the quantity of the item in the list should be bigger than 1 - Item Should Be Increased Logitech MX Vertical + Item Should Be Increased ${PRODUCT_NAME} the user wants to clear the list - No Operation + ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY}= Generate Random Product + ${SUFFIX}= Generate Random String 6 [LOWER][NUMBERS] + ${NAME}= Catenate SEPARATOR= ${NAME} ${SUFFIX} + ${ADMIN_EMAIL} ${ADMIN_PASSWORD} ${ADMIN_ID}= Create Admin User Via Api + ${ADMIN_TOKEN}= Get Admin Auth Token ${ADMIN_EMAIL} ${ADMIN_PASSWORD} + ${PRODUCT_ID}= Create Product Via Api ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY} ${ADMIN_TOKEN} + Set Test Variable ${PRODUCT_NAME} ${NAME} + Set Test Variable ${PRODUCT_ID} ${PRODUCT_ID} + Set Test Variable ${ADMIN_ID} ${ADMIN_ID} + Set Test Variable ${ADMIN_TOKEN} ${ADMIN_TOKEN} + Reload the user clears the list Clear List the list should be empty - List Should Be Empty \ No newline at end of file + List Should Be Empty + +the user wants to decrease item in the list + ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY}= Generate Random Product + ${SUFFIX}= Generate Random String 6 [LOWER][NUMBERS] + ${NAME}= Catenate SEPARATOR= ${NAME} ${SUFFIX} + ${ADMIN_EMAIL} ${ADMIN_PASSWORD} ${ADMIN_ID}= Create Admin User Via Api + ${ADMIN_TOKEN}= Get Admin Auth Token ${ADMIN_EMAIL} ${ADMIN_PASSWORD} + ${PRODUCT_ID}= Create Product Via Api ${NAME} ${PRICE} ${DESCRIPTION} ${QUANTITY} ${ADMIN_TOKEN} + Set Test Variable ${PRODUCT_NAME} ${NAME} + Set Test Variable ${PRODUCT_ID} ${PRODUCT_ID} + Set Test Variable ${ADMIN_ID} ${ADMIN_ID} + Set Test Variable ${ADMIN_TOKEN} ${ADMIN_TOKEN} + Reload + +the user decreases the quantity of the item in the list + Decrease Quantity of Item in List + +the quantity of the item in the list should be 1 + Item Should Be Decreased ${PRODUCT_NAME} From 25379ba704d0fbeeaf35c04839808315a9a9af9a Mon Sep 17 00:00:00 2001 From: sub0br Date: Thu, 13 Aug 2026 09:32:03 -0300 Subject: [PATCH 6/6] ci: skip gh-pages checkout cleanly when branch doesn't exist yet git fetch was failing with retries/delay on every run before the first Pages deploy, since gh-pages doesn't exist yet; now checks via git ls-remote first and skips the checkout step entirely instead of letting it fail --- .github/workflows/robot-tests.yml | 47 ++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/.github/workflows/robot-tests.yml b/.github/workflows/robot-tests.yml index 3ebdce2..2b495a7 100644 --- a/.github/workflows/robot-tests.yml +++ b/.github/workflows/robot-tests.yml @@ -9,8 +9,8 @@ on: # To turn it back on: uncomment the two lines below and merge this file # into `main` (GitHub only reads `schedule` triggers from the workflow # file version on the repo's default branch, not from feature branches). - schedule: - - cron: '0 3 * * *' # 03:00 UTC = 00:00 (midnight) in Brasília + # schedule: + # - cron: '0 3 * * *' # 03:00 UTC = 00:00 (midnight) in Brasília workflow_dispatch: # allows manual trigger from the Actions tab inputs: tag: @@ -39,7 +39,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Determine which tag to run id: tag @@ -57,13 +57,13 @@ jobs: fi - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: '3.11' cache: 'pip' - name: Set up Node.js (required by the Browser library driver) - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: '22' @@ -73,7 +73,7 @@ jobs: pip install -r requirements.txt - name: Cache Playwright browsers - uses: actions/cache@v4 + uses: actions/cache@v5 id: playwright-cache with: path: ~/.cache/ms-playwright @@ -125,7 +125,7 @@ jobs: - name: Upload artifacts (log.html, report.html, output.xml) if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: robot-framework-results path: results/ @@ -133,7 +133,7 @@ jobs: - name: Upload JUnit/xUnit report if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: robot-junit-report path: results/xunit.xml @@ -151,12 +151,23 @@ jobs: if: always() run: npm install -g allure-commandline + # Checks whether gh-pages exists yet (it won't on the very first run, + # before any deploy to Pages has happened), to skip the checkout below + # cleanly instead of letting it fail with retries. + - name: Check if gh-pages branch exists + if: always() + id: gh-pages-check + run: | + if git ls-remote --exit-code --heads origin gh-pages > /dev/null 2>&1; then + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + # Retrieves the history of previous runs from the gh-pages branch. - # continue-on-error covers the first run, when the branch does not exist yet. - name: Get Allure history - if: always() - continue-on-error: true - uses: actions/checkout@v4 + if: always() && steps.gh-pages-check.outputs.exists == 'true' + uses: actions/checkout@v5 with: ref: gh-pages path: gh-pages @@ -165,8 +176,12 @@ jobs: # the Allure CLI picks it up and renders the trend graphs. - name: Restore Allure history if: always() - continue-on-error: true - run: cp -r gh-pages/history allure-results/history + run: | + if [ -d "gh-pages/history" ]; then + cp -r gh-pages/history allure-results/history + else + echo "No previous history found (gh-pages branch or history/ folder doesn't exist yet) — skipping." + fi - name: Generate Allure report with history if: always() @@ -186,7 +201,7 @@ jobs: # On PRs, the Allure report is made available as a run artifact. - name: Upload Allure report artifact (PRs) if: always() && github.event_name == 'pull_request' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: allure-report path: allure-report/ @@ -202,7 +217,7 @@ jobs: - name: Send Allure report by email if: always() - uses: dawidd6/action-send-mail@v4 + uses: dawidd6/action-send-mail@v14 with: server_address: ${{ secrets.MAIL_SERVER }} server_port: 465