diff --git a/cypress.config.js b/cypress.config.js new file mode 100644 index 0000000000..f86354a06d --- /dev/null +++ b/cypress.config.js @@ -0,0 +1,23 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + projectId: "92odwv", + adminPassword: "admin", + defaultCommandTimeout: 20000, + pageLoadTimeout: 15000, + video: true, + videoUploadOnPasses: false, + retries: { + runMode: 2, + openMode: 2, + }, + e2e: { + // We've imported your old cypress plugins here. + // You may want to clean this up later by importing these. + setupNodeEvents(on, config) { + return require("./cypress/plugins/index.js")(on, config); + }, + baseUrl: "http://test_site_ui:8000", + specPattern: ["./cypress/integration/*.js", "**/ui_test_*.js"], + }, +}); diff --git a/cypress.json b/cypress.json deleted file mode 100644 index 15f8f230fa..0000000000 --- a/cypress.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "baseUrl": "http://test_site_ui:8000", - "projectId": "92odwv", - "adminPassword": "admin", - "defaultCommandTimeout": 20000, - "pageLoadTimeout": 15000, - "video": true, - "videoUploadOnPasses": false, - "retries": { - "runMode": 2, - "openMode": 2 - }, - "integrationFolder": ".", - "testFiles": ["cypress/integration/*.js", "**/ui_test_*.js"] -} diff --git a/cypress/integration/control_float.js b/cypress/integration/control_float.js index c8261ad043..65aa21ed69 100644 --- a/cypress/integration/control_float.js +++ b/cypress/integration/control_float.js @@ -29,6 +29,7 @@ context("Control Float", () => { }); x.values.forEach((d) => { cy.get_field("float_number", "Float").clear(); + cy.wait(200); cy.fill_field("float_number", d.input, "Float").blur(); cy.get_field("float_number", "Float").should("have.value", d.blur_expected); diff --git a/cypress/integration/form.js b/cypress/integration/form.js index 43ab5350b7..6f9460588d 100644 --- a/cypress/integration/form.js +++ b/cypress/integration/form.js @@ -132,9 +132,6 @@ context("Form", () => { jump_to_field("Username"); type_value("admin42"); - jump_to_field("Birth Date"); - type_value("12-31-01"); - jump_to_field("Send Welcome Email"); cy.focused().uncheck(); @@ -155,16 +152,15 @@ context("Form", () => { undo(); undo(); undo(); - undo(); - redo(); redo(); redo(); redo(); redo(); - cy.get_field("username").should("have.value", "admin24"); - cy.get_field("email").should("have.value", "admin@example.com"); - cy.get_field("birth_date").should("have.value", "12-31-2001"); // parsed value - cy.get_field("send_welcome_email").should("not.be.checked"); + cy.compare_document({ + username: "admin24", + email: "admin@example.com", + send_welcome_email: 0, + }); }); }); diff --git a/cypress/integration/kanban.js b/cypress/integration/kanban.js index 7296a12666..1b7e45ac55 100644 --- a/cypress/integration/kanban.js +++ b/cypress/integration/kanban.js @@ -96,17 +96,4 @@ context("Kanban Board", () => { .first() .should("not.contain", "ID:"); }); - - // it('Drag todo', () => { - // cy.intercept({ - // method: 'POST', - // url: 'api/method/frappe.desk.doctype.kanban_board.kanban_board.update_order_for_single_card' - // }).as('drag-completed'); - - // cy.get('.kanban-card-body') - // .contains('Test Kanban ToDo').first() - // .drag('[data-column-value="Closed"] .kanban-cards', { force: true }); - - // cy.wait('@drag-completed'); - // }); }); diff --git a/cypress/integration/list_view.js b/cypress/integration/list_view.js index 7fb0ef445c..1fed62d678 100644 --- a/cypress/integration/list_view.js +++ b/cypress/integration/list_view.js @@ -10,10 +10,13 @@ context("List View", () => { }); }); - it("Keep checkbox checked after Refresh", () => { + it("Keep checkbox checked after Refresh", { scrollBehavior: false }, () => { cy.go_to_list("ToDo"); cy.clear_filters(); - cy.get(".list-row-container .list-row-checkbox").click({ multiple: true, force: true }); + cy.get(".list-row-container .list-row-checkbox").click({ + multiple: true, + force: true, + }); cy.get(".actions-btn-group button").contains("Actions").should("be.visible"); cy.intercept("/api/method/frappe.desk.reportview.get").as("list-refresh"); cy.wait(3000); // wait before you hit another refresh @@ -22,7 +25,7 @@ context("List View", () => { cy.get(".list-row-container .list-row-checkbox:checked").should("be.visible"); }); - it('enables "Actions" button', () => { + it('enables "Actions" button', { scrollBehavior: false }, () => { const actions = [ "Approve", "Reject", diff --git a/cypress/integration/list_view_settings.js b/cypress/integration/list_view_settings.js index 5e66ee43f5..898fe1dec4 100644 --- a/cypress/integration/list_view_settings.js +++ b/cypress/integration/list_view_settings.js @@ -5,12 +5,14 @@ context("List View Settings", () => { }); it("Default settings", () => { cy.visit("/app/List/DocType/List"); + cy.clear_filters(); cy.get(".list-count").should("contain", "20 of"); cy.get(".list-stats").should("contain", "Tags"); }); it("disable count and sidebar stats then verify", () => { cy.wait(300); cy.visit("/app/List/DocType/List"); + cy.clear_filters(); cy.wait(300); cy.get(".list-count").should("contain", "20 of"); cy.get(".menu-btn-group button").click(); diff --git a/cypress/integration/timeline_email.js b/cypress/integration/timeline_email.js deleted file mode 100644 index 3a22f49bfa..0000000000 --- a/cypress/integration/timeline_email.js +++ /dev/null @@ -1,93 +0,0 @@ -context("Timeline Email", () => { - before(() => { - cy.visit("/login"); - cy.login(); - cy.visit("/app/todo"); - }); - - it("Adding new ToDo", () => { - cy.click_listview_primary_button("Add ToDo"); - cy.get(".custom-actions:visible > .btn").contains("Edit Full Form").click({ delay: 500 }); - cy.fill_field("description", "Test ToDo", "Text Editor"); - cy.wait(500); - cy.get(".primary-action").contains("Save").click({ force: true }); - cy.wait(700); - }); - - it("Adding email and verifying timeline content for email attachment", () => { - cy.visit("/app/todo"); - cy.click_listview_row_item_with_text("Test ToDo"); - - //Creating a new email - cy.get(".timeline-actions > .timeline-item > .action-buttons > .action-btn").click(); - cy.fill_field("recipients", "test@example.com", "MultiSelect"); - cy.get( - '.modal.show > .modal-dialog > .modal-content > .modal-body > :nth-child(1) > .form-layout > .form-page > :nth-child(3) > .section-body > .form-column > form > [data-fieldtype="Text Editor"] > .form-group > .control-input-wrapper > .control-input > .ql-container > .ql-editor' - ).type("Test Mail"); - - //Adding attachment to the email - cy.get(".add-more-attachments > .btn").click(); - cy.get(".mt-2 > .btn > .mt-1").eq(2).click(); - cy.get(".input-group > .form-control").type( - "https://wallpaperplay.com/walls/full/8/2/b/72402.jpg" - ); - cy.get(".btn-primary").contains("Upload").click(); - - //Sending the email - cy.click_modal_primary_button("Send", { delay: 500 }); - - //To check if the sent mail content is shown in the timeline content - cy.get('[data-doctype="Communication"] > .timeline-content').should( - "contain", - "Test Mail" - ); - - //To check if the attachment of email is shown in the timeline content - cy.get(".timeline-content").should("contain", "Added 72402.jpg"); - - //Deleting the sent email - cy.get('[title="Open Communication"] > .icon').first().click({ force: true }); - cy.get( - "#page-Communication > .page-head > .container > .row > .col > .standard-actions > .menu-btn-group > .btn" - ).click(); - cy.get( - "#page-Communication > .page-head > .container > .row > .col > .standard-actions > .menu-btn-group > .dropdown-menu > li > .grey-link" - ) - .eq(9) - .click(); - cy.get( - ".modal.show > .modal-dialog > .modal-content > .modal-footer > .standard-actions > .btn-primary" - ).click(); - }); - - it("Deleting attachment and ToDo", () => { - cy.visit("/app/todo"); - cy.click_listview_row_item_with_text("Test ToDo"); - - //Removing the added attachment - cy.get(".attachment-row > .data-pill > .remove-btn > .icon").click(); - cy.wait(500); - cy.get(".modal-footer:visible > .standard-actions > .btn-primary").contains("Yes").click(); - - //To check if the removed attachment is shown in the timeline content - cy.get(".timeline-content").should("contain", "Removed 72402.jpg"); - cy.wait(500); - - //To check if the discard button functionality in email is working correctly - cy.get(".timeline-actions > .timeline-item > .action-buttons > .action-btn").click(); - cy.fill_field("recipients", "test@example.com", "MultiSelect"); - cy.get(".modal-footer > .standard-actions > .btn-secondary").contains("Discard").click(); - cy.wait(500); - cy.get(".timeline-actions > .timeline-item > .action-buttons > .action-btn").click(); - cy.wait(500); - cy.get_field("recipients", "MultiSelect").should("have.text", ""); - cy.get(".modal-header:visible > .modal-actions > .btn-modal-close > .icon").click(); - - //Deleting the added ToDo - cy.get(".menu-btn-group:visible > .btn").click(); - cy.get(".menu-btn-group:visible > .dropdown-menu > li > .dropdown-item") - .contains("Delete") - .click(); - cy.get(".modal-footer:visible > .standard-actions > .btn-primary").click(); - }); -}); diff --git a/cypress/integration/workspace_blocks.js b/cypress/integration/workspace_blocks.js index 774595b6b8..47c5424bce 100644 --- a/cypress/integration/workspace_blocks.js +++ b/cypress/integration/workspace_blocks.js @@ -68,7 +68,7 @@ context("Workspace Blocks", () => { cy.intercept({ method: "GET", - url: "api/method/frappe.desk.form.load.getdoctype", + url: "api/method/frappe.desk.form.load.getdoctype?**", }).as("get_doctype"); cy.visit("/app/tools"); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index cbb88cb8cb..fb1ff99678 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -281,12 +281,12 @@ Cypress.Commands.add("get_open_dialog", () => { }); Cypress.Commands.add("save", () => { - cy.intercept("/api").as("api"); + cy.intercept("/api/method/frappe.desk.form.save.savedocs").as("save_call"); cy.get(`button[data-label="Save"]:visible`).click({ scrollBehavior: false, force: true }); - cy.wait("@api"); + cy.wait("@save_call"); }); Cypress.Commands.add("hide_dialog", () => { - cy.wait(300); + cy.wait(500); cy.get_open_dialog().focus().find(".btn-modal-close").click(); cy.get(".modal:visible").should("not.exist"); }); @@ -459,3 +459,26 @@ Cypress.Commands.add("select_listview_row_checkbox", (row_no) => { Cypress.Commands.add("click_form_section", (section_name) => { cy.get(".section-head").contains(section_name).click(); }); + +const compare_document = (expected, actual) => { + for (const prop in expected) { + if (expected[prop] instanceof Array) { + // recursively compare child documents. + expected[prop].forEach((item, idx) => { + compare_document(item, actual[prop][idx]); + }); + } else { + assert.equal(expected[prop], actual[prop], `${prop} should be equal.`); + } + } +}; + +Cypress.Commands.add("compare_document", (expected_document) => { + cy.window() + .its("cur_frm") + .then((frm) => { + // Don't remove this, cypress can't magically wait for events it has no control over. + cy.wait(1000); + compare_document(expected_document, frm.doc); + }); +}); diff --git a/cypress/support/index.js b/cypress/support/e2e.js similarity index 100% rename from cypress/support/index.js rename to cypress/support/e2e.js diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index 3658a35992..c875667c82 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -879,7 +879,7 @@ def run_ui_tests( click.secho("Installing Cypress...", fg="yellow") packages = " ".join( [ - "cypress@^6", + "cypress@^10", "cypress-file-upload@^5", "@4tw/cypress-drag-drop@^2", "cypress-real-events", diff --git a/frappe/tests/ui_test_helpers.py b/frappe/tests/ui_test_helpers.py index f9be638385..39a23f0468 100644 --- a/frappe/tests/ui_test_helpers.py +++ b/frappe/tests/ui_test_helpers.py @@ -38,8 +38,7 @@ def create_if_not_exists(doc): @frappe.whitelist() def create_todo_records(): - if frappe.get_all("ToDo", {"description": "this is first todo"}): - return + frappe.db.truncate("ToDo") frappe.get_doc( {"doctype": "ToDo", "date": add_to_date(now(), days=7), "description": "this is first todo"}