From 38d15d38fae06bcd0ef5030bf0f71fa5eeeacd58 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 10 Sep 2022 13:49:32 +0530 Subject: [PATCH] test(UI): non-admin user for UI tests and misc fixes (backport #17995) (#18079) * test(UI): use non-admin user for tests (cherry picked from commit f07bc3b36902e4f6495ded004fad25c97610fa65) # Conflicts: # .github/workflows/ui-tests.yml * test: fix tests using admin account (cherry picked from commit a6b341bd59fcd1c217d549132de05af34b6d2bd0) # Conflicts: # cypress/integration/dashboard_links.js * test: add test role to user (cherry picked from commit 0896873c8a9c0ac0c1fb93474775478d6b75795c) * chore: conflicts * test: fix broken test Not sure why there's test on doctype "created by". Makes no sense. Co-authored-by: Ankush Menat --- .github/workflows/ui-tests.yml | 5 ++- cypress.config.js | 1 + cypress/integration/control_link.js | 10 +++--- cypress/integration/dashboard_links.js | 15 ++++---- cypress/integration/login.js | 4 +-- cypress/integration/sidebar.js | 7 +--- cypress/integration/table_multiselect.js | 4 ++- cypress/integration/timeline.js | 4 +-- cypress/integration/web_form.js | 16 ++++++--- cypress/support/commands.js | 2 +- frappe/tests/ui_test_helpers.py | 35 +++++++++++++++++++ .../doctype/workflow/test_workflow.py | 20 +++++++---- 12 files changed, 84 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml index db215cbc7b..7f792f4878 100644 --- a/.github/workflows/ui-tests.yml +++ b/.github/workflows/ui-tests.yml @@ -137,7 +137,10 @@ jobs: - name: Site Setup if: ${{ steps.check-build.outputs.build == 'strawberry' }} - run: cd ~/frappe-bench/ && bench --site test_site execute frappe.utils.install.complete_setup_wizard + run: | + cd ~/frappe-bench/ + bench --site test_site execute frappe.utils.install.complete_setup_wizard + bench --site test_site execute frappe.tests.ui_test_helpers.create_test_user - name: UI Tests if: ${{ steps.check-build.outputs.build == 'strawberry' }} diff --git a/cypress.config.js b/cypress.config.js index f86354a06d..bfd0bc0025 100644 --- a/cypress.config.js +++ b/cypress.config.js @@ -3,6 +3,7 @@ const { defineConfig } = require("cypress"); module.exports = defineConfig({ projectId: "92odwv", adminPassword: "admin", + testUser: "frappe@example.com", defaultCommandTimeout: 20000, pageLoadTimeout: 15000, video: true, diff --git a/cypress/integration/control_link.js b/cypress/integration/control_link.js index 240515be45..a5281d9b09 100644 --- a/cypress/integration/control_link.js +++ b/cypress/integration/control_link.js @@ -177,14 +177,14 @@ context("Control Link", () => { cy.intercept("POST", "/api/method/frappe.client.validate_link").as("validate_link"); cy.get(".frappe-control[data-fieldname=assigned_by] input").focus().as("input"); - cy.get("@input").type("Administrator", { delay: 100 }).blur(); + cy.get("@input").type(cy.config("testUser"), { delay: 100 }).blur(); cy.wait("@validate_link"); cy.get(".frappe-control[data-fieldname=assigned_by_full_name] .control-value").should( "contain", - "Administrator" + "Frappe" ); - cy.window().its("cur_frm.doc.assigned_by").should("eq", "Administrator"); + cy.window().its("cur_frm.doc.assigned_by").should("eq", cy.config("testUser")); // invalid input cy.get("@input").clear().type("invalid input", { delay: 100 }).blur(); @@ -198,10 +198,10 @@ context("Control Link", () => { // set valid value again cy.get("@input").clear().focus(); cy.wait("@search_link"); - cy.get("@input").type("Administrator", { delay: 100 }).blur(); + cy.get("@input").type(cy.config("testUser"), { delay: 100 }).blur(); cy.wait("@validate_link"); - cy.window().its("cur_frm.doc.assigned_by").should("eq", "Administrator"); + cy.window().its("cur_frm.doc.assigned_by").should("eq", cy.config("testUser")); // clear input cy.get("@input").clear().blur(); diff --git a/cypress/integration/dashboard_links.js b/cypress/integration/dashboard_links.js index 31572b7976..462069f773 100644 --- a/cypress/integration/dashboard_links.js +++ b/cypress/integration/dashboard_links.js @@ -8,7 +8,7 @@ const child_table_doctype_name = child_table_doctype.name; context("Dashboard links", () => { before(() => { cy.visit("/login"); - cy.login(); + cy.login("Administrator"); cy.insert_doc("DocType", child_table_doctype, true); cy.insert_doc("DocType", child_table_doctype_1, true); cy.insert_doc("DocType", doctype_with_child_table, true); @@ -27,8 +27,7 @@ context("Dashboard links", () => { cy.visit("/app/contact"); cy.clear_filters(); - cy.visit("/app/user"); - cy.get(".list-row-col > .level-item > .ellipsis").eq(0).click({ force: true }); + cy.visit(`/app/user/${cy.config("testUser")}`); //To check if initially the dashboard contains only the "Contact" link and there is no counter cy.get('[data-doctype="Contact"]').should("contain", "Contact"); @@ -40,11 +39,10 @@ context("Dashboard links", () => { cy.findByRole("button", { name: "Add Contact" }).click(); cy.get('[data-doctype="Contact"][data-fieldname="first_name"]').type("Admin"); cy.findByRole("button", { name: "Save" }).click(); - cy.visit("/app/user"); - cy.get(".list-row-col > .level-item > .ellipsis").eq(0).click({ force: true }); + cy.visit(`/app/user/${cy.config("testUser")}`); - //To check if the counter for contact doc is "1" after adding the contact - cy.get('[data-doctype="Contact"] > .count').should("contain", "1"); + //To check if the counter for contact doc is "2" after adding additional contact + cy.get('[data-doctype="Contact"] > .count').should("contain", "2"); cy.get('[data-doctype="Contact"]').contains("Contact").click(); //Deleting the newly created contact @@ -62,8 +60,7 @@ context("Dashboard links", () => { }); it("Report link in dashboard", () => { - cy.visit("/app/user"); - cy.visit("/app/user/Administrator"); + cy.visit(`/app/user/${cy.config("testUser")}`); cy.get('[data-doctype="Contact"]').should("contain", "Contact"); cy.findByText("Connections"); cy.window() diff --git a/cypress/integration/login.js b/cypress/integration/login.js index 2db4b1fdcd..912f34c508 100644 --- a/cypress/integration/login.js +++ b/cypress/integration/login.js @@ -32,7 +32,7 @@ context("Login", () => { it("logs in using correct credentials", () => { cy.get("#login_email").type("Administrator"); - cy.get("#login_password").type(Cypress.config("adminPassword")); + cy.get("#login_password").type(Cypress.env("adminPassword")); cy.findByRole("button", { name: "Login" }).click(); cy.location("pathname").should("eq", "/app"); @@ -56,7 +56,7 @@ context("Login", () => { ); cy.get("#login_email").type("Administrator"); - cy.get("#login_password").type(Cypress.config("adminPassword")); + cy.get("#login_password").type(Cypress.env("adminPassword")); cy.findByRole("button", { name: "Login" }).click(); diff --git a/cypress/integration/sidebar.js b/cypress/integration/sidebar.js index 147d425aa2..0b2a21aa4f 100644 --- a/cypress/integration/sidebar.js +++ b/cypress/integration/sidebar.js @@ -38,11 +38,6 @@ context("Sidebar", () => { //To check if no filter is available in "Assigned To" dropdown cy.get(".empty-state").should("contain", "No filters found"); - cy.click_sidebar_button("Created By"); - - //To check if "Created By" dropdown contains filter - cy.get(".group-by-item > .dropdown-item").should("contain", "Me"); - //Assigning a doctype to a user cy.visit("/app/doctype/ToDo"); cy.get(".form-assignments > .flex > .text-muted").click(); @@ -72,7 +67,7 @@ context("Sidebar", () => { cy.get(".condition").should("have.value", "like"); cy.get(".filter-field > .form-group > .input-with-feedback").should( "have.value", - "%Administrator%" + `%${cy.config("testUser")}%` ); cy.click_filter_button(); diff --git a/cypress/integration/table_multiselect.js b/cypress/integration/table_multiselect.js index 133af44d51..74884e4ffd 100644 --- a/cypress/integration/table_multiselect.js +++ b/cypress/integration/table_multiselect.js @@ -13,7 +13,9 @@ context("Table MultiSelect", () => { cy.fill_field("assign_condition", 'status=="Open"', "Code"); cy.get('input[data-fieldname="users"]').focus().as("input"); cy.get('input[data-fieldname="users"] + ul').should("be.visible"); - cy.get("@input").type("test{enter}", { delay: 100 }); + cy.get("@input").type("test@erpnext", { delay: 100 }); + cy.wait(500); + cy.get("@input").type("{enter}"); cy.get( '.frappe-control[data-fieldname="users"] .form-control .tb-selected-value .btn-link-to-form' ).as("selected-value"); diff --git a/cypress/integration/timeline.js b/cypress/integration/timeline.js index 5841891af6..7835819334 100644 --- a/cypress/integration/timeline.js +++ b/cypress/integration/timeline.js @@ -72,14 +72,14 @@ context("Timeline", () => { cy.click_listview_row_item(0); //To check if the submission of the documemt is visible in the timeline content - cy.get(".timeline-content").should("contain", "Administrator submitted this document"); + cy.get(".timeline-content").should("contain", "Frappe submitted this document"); cy.get('[id="page-Custom Submittable DocType"] .page-actions') .findByRole("button", { name: "Cancel" }) .click(); cy.get_open_dialog().findByRole("button", { name: "Yes" }).click(); //To check if the cancellation of the documemt is visible in the timeline content - cy.get(".timeline-content").should("contain", "Administrator cancelled this document"); + cy.get(".timeline-content").should("contain", "Frappe cancelled this document"); //Deleting the document cy.visit("/app/custom-submittable-doctype"); diff --git a/cypress/integration/web_form.js b/cypress/integration/web_form.js index d7f210e7d2..53f72ab013 100644 --- a/cypress/integration/web_form.js +++ b/cypress/integration/web_form.js @@ -1,6 +1,13 @@ context("Web Form", () => { before(() => { - cy.login(); + cy.login("Administrator"); + cy.visit("/app/"); + return cy + .window() + .its("frappe") + .then((frappe) => { + return frappe.xcall("frappe.tests.ui_test_helpers.clear_notes"); + }); }); it("Create Web Form", () => { @@ -42,7 +49,7 @@ context("Web Form", () => { }); it("Login Required", () => { - cy.login(); + cy.login("Administrator"); cy.visit("/app/web-form/note"); cy.findByRole("tab", { name: "Settings" }).click(); @@ -51,7 +58,6 @@ context("Web Form", () => { cy.save(); cy.visit("/note"); - cy.url().should("include", "/note/Note%201"); cy.call("logout"); @@ -62,7 +68,7 @@ context("Web Form", () => { }); it("Show List", () => { - cy.login(); + cy.login("Administrator"); cy.visit("/app/web-form/note"); cy.findByRole("tab", { name: "Settings" }).click(); @@ -156,7 +162,7 @@ context("Web Form", () => { }); it("Read Only", () => { - cy.login(); + cy.login("Administrator"); cy.visit("/note"); cy.url().should("include", "/note/list"); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index c8757ffed5..d88fda7884 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -29,7 +29,7 @@ import "cypress-real-events/support"; Cypress.Commands.add("login", (email, password) => { if (!email) { - email = "Administrator"; + email = Cypress.config("testUser") || "Administrator"; } if (!password) { password = Cypress.env("adminPassword"); diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py index 39a23f0468..cb8fe8e70a 100644 --- a/frappe/tests/ui_test_helpers.py +++ b/frappe/tests/ui_test_helpers.py @@ -2,6 +2,8 @@ import frappe from frappe import _ from frappe.utils import add_to_date, now +UI_TEST_USER = "frappe@example.com" + @frappe.whitelist() def create_if_not_exists(doc): @@ -54,6 +56,15 @@ def create_todo_records(): ).insert() +@frappe.whitelist() +def clear_notes(): + if not frappe.local.dev_server: + frappe.throw(_("Not allowed"), frappe.PermissionError) + + for note in frappe.get_all("Note", pluck="name"): + frappe.delete_doc("Note", note, force=True) + + @frappe.whitelist() def create_communication_record(): doc = frappe.get_doc( @@ -396,3 +407,27 @@ def create_blog_post(): ).insert(ignore_if_duplicate=True) return doc + + +def create_test_user(): + if frappe.db.exists("User", UI_TEST_USER): + return + + user = frappe.new_doc("User") + user.email = UI_TEST_USER + user.first_name = "Frappe" + user.new_password = frappe.local.conf.admin_password + user.send_welcome_email = 0 + user.time_zone = "Asia/Kolkata" + user.flags.ignore_password_policy = True + user.insert(ignore_if_duplicate=True) + + user.reload() + + blocked_roles = {"Administrator", "Guest", "All"} + all_roles = set(frappe.get_all("Role", pluck="name")) + + for role in all_roles - blocked_roles: + user.append("roles", {"role": role}) + + user.save() diff --git a/frappe/workflow/doctype/workflow/test_workflow.py b/frappe/workflow/doctype/workflow/test_workflow.py index 92ca95f0ff..b7740242c3 100644 --- a/frappe/workflow/doctype/workflow/test_workflow.py +++ b/frappe/workflow/doctype/workflow/test_workflow.py @@ -2,7 +2,6 @@ # License: MIT. See LICENSE import frappe from frappe.model.workflow import ( - WorkflowPermissionError, WorkflowTransitionError, apply_workflow, get_common_transition_actions, @@ -191,11 +190,18 @@ class TestWorkflow(FrappeTestCase): def create_todo_workflow(): + from frappe.tests.ui_test_helpers import UI_TEST_USER + if frappe.db.exists("Workflow", "Test ToDo"): frappe.delete_doc("Workflow", "Test ToDo") - if not frappe.db.exists("Role", "Test Approver"): - frappe.get_doc(dict(doctype="Role", role_name="Test Approver")).insert(ignore_if_duplicate=True) + TEST_ROLE = "Test Approver" + + if not frappe.db.exists("Role", TEST_ROLE): + frappe.get_doc(dict(doctype="Role", role_name=TEST_ROLE)).insert(ignore_if_duplicate=True) + if frappe.db.exists("User", UI_TEST_USER): + frappe.get_doc("User", UI_TEST_USER).add_roles(TEST_ROLE) + workflow = frappe.new_doc("Workflow") workflow.workflow_name = "Test ToDo" workflow.document_type = "ToDo" @@ -205,16 +211,16 @@ def create_todo_workflow(): workflow.append("states", dict(state="Pending", allow_edit="All")) workflow.append( "states", - dict(state="Approved", allow_edit="Test Approver", update_field="status", update_value="Closed"), + dict(state="Approved", allow_edit=TEST_ROLE, update_field="status", update_value="Closed"), ) - workflow.append("states", dict(state="Rejected", allow_edit="Test Approver")) + workflow.append("states", dict(state="Rejected", allow_edit=TEST_ROLE)) workflow.append( "transitions", dict( state="Pending", action="Approve", next_state="Approved", - allowed="Test Approver", + allowed=TEST_ROLE, allow_self_approval=1, ), ) @@ -224,7 +230,7 @@ def create_todo_workflow(): state="Pending", action="Reject", next_state="Rejected", - allowed="Test Approver", + allowed=TEST_ROLE, allow_self_approval=1, ), )