From b417218f1d6261478f4c7e6ef41e53633965df1f Mon Sep 17 00:00:00 2001 From: MitulDavid Date: Tue, 17 Aug 2021 19:06:01 +0530 Subject: [PATCH 1/3] test: Add support for Testing-Library queries within Cypress tests --- cypress/integration/awesome_bar.js | 14 ++++++------- cypress/integration/control_barcode.js | 6 +++--- cypress/integration/control_icon.js | 10 ++++----- cypress/integration/control_link.js | 4 ++-- cypress/integration/control_select.js | 2 ++ cypress/integration/depends_on.js | 6 +++--- cypress/integration/file_uploader.js | 29 +++++++++++++------------- cypress/support/commands.js | 1 + frappe/commands/utils.py | 4 +++- 9 files changed, 41 insertions(+), 35 deletions(-) diff --git a/cypress/integration/awesome_bar.js b/cypress/integration/awesome_bar.js index 3e12101532..08a2a71843 100644 --- a/cypress/integration/awesome_bar.js +++ b/cypress/integration/awesome_bar.js @@ -10,9 +10,9 @@ context('Awesome Bar', () => { }); it('navigates to doctype list', () => { - cy.get('#navbar-search').type('todo', { delay: 200 }); - cy.get('#navbar-search + ul').should('be.visible'); - cy.get('#navbar-search').type('{downarrow}{enter}', { delay: 100 }); + cy.findByPlaceholderText('Search or type a command (Ctrl + G)').type('todo', { delay: 200 }); + cy.findByRole('listbox').should('be.visible'); + cy.findByPlaceholderText('Search or type a command (Ctrl + G)').type('{downarrow}{enter}', { delay: 100 }); cy.get('.title-text').should('contain', 'To Do'); @@ -20,24 +20,24 @@ context('Awesome Bar', () => { }); it('find text in doctype list', () => { - cy.get('#navbar-search') + cy.findByPlaceholderText('Search or type a command (Ctrl + G)') .type('test in todo{downarrow}{enter}', { delay: 200 }); cy.get('.title-text').should('contain', 'To Do'); - cy.get('[data-original-title="Name"] > .input-with-feedback') + cy.findByPlaceholderText('Name') .should('have.value', '%test%'); }); it('navigates to new form', () => { - cy.get('#navbar-search') + cy.findByPlaceholderText('Search or type a command (Ctrl + G)') .type('new blog post{downarrow}{enter}', { delay: 200 }); cy.get('.title-text:visible').should('have.text', 'New Blog Post'); }); it('calculates math expressions', () => { - cy.get('#navbar-search') + cy.findByPlaceholderText('Search or type a command (Ctrl + G)') .type('55 + 32{downarrow}{enter}', { delay: 200 }); cy.get('.modal-title').should('contain', 'Result'); diff --git a/cypress/integration/control_barcode.js b/cypress/integration/control_barcode.js index 1df5e64f0e..51984fdbd2 100644 --- a/cypress/integration/control_barcode.js +++ b/cypress/integration/control_barcode.js @@ -20,7 +20,7 @@ context('Control Barcode', () => { it('should generate barcode on setting a value', () => { get_dialog_with_barcode().as('dialog'); - cy.get('.frappe-control[data-fieldname=barcode] input') + cy.findByRole('textbox') .focus() .type('123456789') .blur(); @@ -37,11 +37,11 @@ context('Control Barcode', () => { it('should reset when input is cleared', () => { get_dialog_with_barcode().as('dialog'); - cy.get('.frappe-control[data-fieldname=barcode] input') + cy.findByRole('textbox') .focus() .type('123456789') .blur(); - cy.get('.frappe-control[data-fieldname=barcode] input') + cy.findByRole('textbox') .clear() .blur(); cy.get('.frappe-control[data-fieldname=barcode] svg[data-barcode-value="123456789"]') diff --git a/cypress/integration/control_icon.js b/cypress/integration/control_icon.js index f92927f267..73927a15c6 100644 --- a/cypress/integration/control_icon.js +++ b/cypress/integration/control_icon.js @@ -17,17 +17,17 @@ context('Control Icon', () => { it('should set icon', () => { get_dialog_with_icon().as('dialog'); - cy.get('.frappe-control[data-fieldname=icon] input').first().click(); + cy.findByRole('textbox').first().click(); cy.get('.icon-picker .icon-wrapper[id=active]').first().click(); - cy.get('.frappe-control[data-fieldname=icon] input').first().should('have.value', 'active'); + cy.findByRole('textbox').first().should('have.value', 'active'); cy.get('@dialog').then(dialog => { let value = dialog.get_value('icon'); expect(value).to.equal('active'); }); cy.get('.icon-picker .icon-wrapper[id=resting]').first().click(); - cy.get('.frappe-control[data-fieldname=icon] input').first().should('have.value', 'resting'); + cy.findByRole('textbox').first().should('have.value', 'resting'); cy.get('@dialog').then(dialog => { let value = dialog.get_value('icon'); expect(value).to.equal('resting'); @@ -36,14 +36,14 @@ context('Control Icon', () => { it('search for icon and clear search input', () => { let search_text = 'ed'; - cy.get('.icon-picker input[type=search]').first().click().type(search_text); + cy.findByRole('searchbox').first().click().type(search_text); cy.get('.icon-section .icon-wrapper:not(.hidden)').then(i => { cy.get(`.icon-section .icon-wrapper[id*='${search_text}']`).then(icons => { expect(i.length).to.equal(icons.length); }); }); - cy.get('.icon-picker input[type=search]').clear().blur(); + cy.findByRole('searchbox').clear().blur(); cy.get('.icon-section .icon-wrapper').should('not.have.class', 'hidden'); }); diff --git a/cypress/integration/control_link.js b/cypress/integration/control_link.js index 8f9257e9c4..d2aa467af1 100644 --- a/cypress/integration/control_link.js +++ b/cypress/integration/control_link.js @@ -35,7 +35,7 @@ context('Control Link', () => { cy.wait('@search_link'); cy.get('@input').type('todo for link', { delay: 200 }); cy.wait('@search_link'); - cy.get('.frappe-control[data-fieldname=link] ul').should('be.visible'); + cy.findByRole('listbox').should('be.visible'); cy.get('.frappe-control[data-fieldname=link] input').type('{enter}', { delay: 100 }); cy.get('.frappe-control[data-fieldname=link] input').blur(); cy.get('@dialog').then(dialog => { @@ -71,7 +71,7 @@ context('Control Link', () => { cy.get('@input').type(todos[0]).blur(); cy.wait('@validate_link'); cy.get('@input').focus(); - cy.get('.frappe-control[data-fieldname=link] .link-btn') + cy.findByTitle('Open Link') .should('be.visible') .click(); cy.location('pathname').should('eq', `/app/todo/${todos[0]}`); diff --git a/cypress/integration/control_select.js b/cypress/integration/control_select.js index 0bc719b4a7..8e18d21260 100644 --- a/cypress/integration/control_select.js +++ b/cypress/integration/control_select.js @@ -24,8 +24,10 @@ context('Control Select', () => { cy.get('@control').get('.select-icon').should('exist'); cy.get('@control').get('.placeholder').should('have.css', 'display', 'block'); cy.get('@select').select('Option 1'); + cy.findByDisplayValue('Option 1').should('exist'); cy.get('@control').get('.placeholder').should('have.css', 'display', 'none'); cy.get('@select').invoke('val', ''); + cy.findByDisplayValue('Option 1').should('not.exist'); cy.get('@control').get('.placeholder').should('have.css', 'display', 'block'); diff --git a/cypress/integration/depends_on.js b/cypress/integration/depends_on.js index d33babb134..9aa6b5d89d 100644 --- a/cypress/integration/depends_on.js +++ b/cypress/integration/depends_on.js @@ -62,11 +62,11 @@ context('Depends On', () => { it('should set the field as mandatory depending on other fields value', () => { cy.new_form('Test Depends On'); cy.fill_field('test_field', 'Some Value'); - cy.get('button.primary-action').contains('Save').click(); + cy.findByRole('button', {name: 'Save'}).click(); cy.get('.msgprint-dialog .modal-title').contains('Missing Fields').should('be.visible'); cy.hide_dialog(); cy.fill_field('test_field', 'Random value'); - cy.get('button.primary-action').contains('Save').click(); + cy.findByRole('button', {name: 'Save'}).click(); cy.get('.msgprint-dialog .modal-title').contains('Missing Fields').should('not.be.visible'); }); it('should set the field as read only depending on other fields value', () => { @@ -84,7 +84,7 @@ context('Depends On', () => { cy.fill_field('dependant_field', 'Some Value'); //cy.fill_field('test_field', 'Some Other Value'); cy.get('.frappe-control[data-fieldname="child_test_depends_on_field"]').as('table'); - cy.get('@table').find('button.grid-add-row').click(); + cy.get('@table').findByRole('button', {name: 'Add Row'}).click(); cy.get('@table').find('[data-idx="1"]').as('row1'); cy.get('@row1').find('.btn-open-row').click(); cy.get('@row1').find('.form-in-grid').as('row1-form_in_grid'); diff --git a/cypress/integration/file_uploader.js b/cypress/integration/file_uploader.js index e1e232c058..3d4f92df3c 100644 --- a/cypress/integration/file_uploader.js +++ b/cypress/integration/file_uploader.js @@ -25,7 +25,7 @@ context('FileUploader', () => { cy.get_open_dialog().find('.file-name').should('contain', 'example.json'); cy.intercept('POST', '/api/method/upload_file').as('upload_file'); - cy.get_open_dialog().find('.btn-modal-primary').click(); + cy.get_open_dialog().findByRole('button', {name: 'Upload'}).click(); cy.wait('@upload_file').its('response.statusCode').should('eq', 200); cy.get('.modal:visible').should('not.exist'); }); @@ -33,11 +33,11 @@ context('FileUploader', () => { it('should accept uploaded files', () => { open_upload_dialog(); - cy.get_open_dialog().find('.btn-file-upload div:contains("Library")').click(); - cy.get('.file-filter').type('example.json'); - cy.get_open_dialog().find('.tree-label:contains("example.json")').first().click(); + cy.get_open_dialog().findByRole('button', {name: 'Library'}).click(); + cy.findByPlaceholderText('Search by filename or extension').type('example.json'); + cy.get_open_dialog().findAllByText('example.json').first().click(); cy.intercept('POST', '/api/method/upload_file').as('upload_file'); - cy.get_open_dialog().find('.btn-primary').click(); + cy.get_open_dialog().findByRole('button', {name: 'Upload'}).click(); cy.wait('@upload_file').its('response.body.message') .should('have.property', 'file_name', 'example.json'); cy.get('.modal:visible').should('not.exist'); @@ -46,10 +46,12 @@ context('FileUploader', () => { it('should accept web links', () => { open_upload_dialog(); - cy.get_open_dialog().find('.btn-file-upload div:contains("Link")').click(); - cy.get_open_dialog().find('.file-web-link input').type('https://github.com', { delay: 100, force: true }); + cy.get_open_dialog().findByRole('button', {name: 'Link'}).click(); + cy.get_open_dialog() + .findByPlaceholderText('Attach a web link') + .type('https://github.com', { delay: 100, force: true }); cy.intercept('POST', '/api/method/upload_file').as('upload_file'); - cy.get_open_dialog().find('.btn-primary').click(); + cy.get_open_dialog().findByRole('button', {name: 'Upload'}).click(); cy.wait('@upload_file').its('response.body.message') .should('have.property', 'file_url', 'https://github.com'); cy.get('.modal:visible').should('not.exist'); @@ -62,15 +64,14 @@ context('FileUploader', () => { subjectType: 'drag-n-drop', }); - cy.get_open_dialog().find('.file-name').should('contain', 'sample_image.jpg'); + cy.get_open_dialog().findAllByText('sample_image.jpg').should('exist'); cy.get_open_dialog().find('.btn-crop').first().click(); - cy.get_open_dialog().find('.image-cropper-actions > .btn-primary').should('contain', 'Crop'); - cy.get_open_dialog().find('.image-cropper-actions > .btn-primary').click(); - cy.get_open_dialog().find('.optimize-checkbox').first().should('contain', 'Optimize'); - cy.get_open_dialog().find('.optimize-checkbox').first().click(); + cy.get_open_dialog().findByRole('button', {name: 'Crop'}).click(); + cy.get_open_dialog().findAllByRole('checkbox', {name: 'Optimize'}).should('exist'); + cy.get_open_dialog().findAllByLabelText('Optimize').first().click(); cy.intercept('POST', '/api/method/upload_file').as('upload_file'); - cy.get_open_dialog().find('.btn-modal-primary').click(); + cy.get_open_dialog().findByRole('button', {name: 'Upload'}).click(); cy.wait('@upload_file').its('response.statusCode').should('eq', 200); cy.get('.modal:visible').should('not.exist'); }); diff --git a/cypress/support/commands.js b/cypress/support/commands.js index a81ba60fb0..c941652487 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,4 +1,5 @@ import 'cypress-file-upload'; +import '@testing-library/cypress/add-commands'; // *********************************************** // This example commands.js shows you how to // create various custom commands and overwrite diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index f2395ae490..ac574841fe 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -597,16 +597,18 @@ def run_ui_tests(context, app, headless=False, parallel=True, ci_build_id=None): node_bin = subprocess.getoutput("npm bin") cypress_path = "{0}/cypress".format(node_bin) plugin_path = "{0}/../cypress-file-upload".format(node_bin) + testing_library_path = f"{node_bin}/../@testing-library" # check if cypress in path...if not, install it. if not ( os.path.exists(cypress_path) and os.path.exists(plugin_path) + and os.path.exists(testing_library_path) and cint(subprocess.getoutput("npm view cypress version")[:1]) >= 6 ): # install cypress click.secho("Installing Cypress...", fg="yellow") - frappe.commands.popen("yarn add cypress@^6 cypress-file-upload@^5 --no-lockfile") + frappe.commands.popen("yarn add cypress@^6 cypress-file-upload@^5 @testing-library/cypress@^8 --no-lockfile") # run for headless mode run_or_open = 'run --browser firefox --record' if headless else 'open' From 93198b7123efde04c0251e75c34c250e3bca4ee4 Mon Sep 17 00:00:00 2001 From: MitulDavid Date: Wed, 18 Aug 2021 19:11:01 +0530 Subject: [PATCH 2/3] test: Replace existing queries with Testing-Library queries --- cypress/integration/awesome_bar.js | 2 +- cypress/integration/control_barcode.js | 6 ++-- cypress/integration/control_icon.js | 10 +++--- cypress/integration/control_link.js | 2 +- cypress/integration/form.js | 2 +- cypress/integration/form_tour.js | 16 ++++----- cypress/integration/grid_pagination.js | 4 +-- cypress/integration/list_view_settings.js | 12 +++---- cypress/integration/login.js | 12 +++---- cypress/integration/recorder.js | 16 ++++----- cypress/integration/report_view.js | 2 +- cypress/integration/timeline.js | 40 +++++++++++------------ 12 files changed, 62 insertions(+), 62 deletions(-) diff --git a/cypress/integration/awesome_bar.js b/cypress/integration/awesome_bar.js index 08a2a71843..fb09b384a8 100644 --- a/cypress/integration/awesome_bar.js +++ b/cypress/integration/awesome_bar.js @@ -11,7 +11,7 @@ context('Awesome Bar', () => { it('navigates to doctype list', () => { cy.findByPlaceholderText('Search or type a command (Ctrl + G)').type('todo', { delay: 200 }); - cy.findByRole('listbox').should('be.visible'); + cy.get('.awesomplete').findByRole('listbox').should('be.visible'); cy.findByPlaceholderText('Search or type a command (Ctrl + G)').type('{downarrow}{enter}', { delay: 100 }); cy.get('.title-text').should('contain', 'To Do'); diff --git a/cypress/integration/control_barcode.js b/cypress/integration/control_barcode.js index 51984fdbd2..5f1ab86d41 100644 --- a/cypress/integration/control_barcode.js +++ b/cypress/integration/control_barcode.js @@ -20,7 +20,7 @@ context('Control Barcode', () => { it('should generate barcode on setting a value', () => { get_dialog_with_barcode().as('dialog'); - cy.findByRole('textbox') + cy.get('.frappe-control[data-fieldname=barcode]').findByRole('textbox') .focus() .type('123456789') .blur(); @@ -37,11 +37,11 @@ context('Control Barcode', () => { it('should reset when input is cleared', () => { get_dialog_with_barcode().as('dialog'); - cy.findByRole('textbox') + cy.get('.frappe-control[data-fieldname=barcode]').findByRole('textbox') .focus() .type('123456789') .blur(); - cy.findByRole('textbox') + cy.get('.frappe-control[data-fieldname=barcode]').findByRole('textbox') .clear() .blur(); cy.get('.frappe-control[data-fieldname=barcode] svg[data-barcode-value="123456789"]') diff --git a/cypress/integration/control_icon.js b/cypress/integration/control_icon.js index 73927a15c6..5c531a0823 100644 --- a/cypress/integration/control_icon.js +++ b/cypress/integration/control_icon.js @@ -17,17 +17,17 @@ context('Control Icon', () => { it('should set icon', () => { get_dialog_with_icon().as('dialog'); - cy.findByRole('textbox').first().click(); + cy.get('.frappe-control[data-fieldname=icon]').findByRole('textbox').click(); cy.get('.icon-picker .icon-wrapper[id=active]').first().click(); - cy.findByRole('textbox').first().should('have.value', 'active'); + cy.get('.frappe-control[data-fieldname=icon]').findByRole('textbox').should('have.value', 'active'); cy.get('@dialog').then(dialog => { let value = dialog.get_value('icon'); expect(value).to.equal('active'); }); cy.get('.icon-picker .icon-wrapper[id=resting]').first().click(); - cy.findByRole('textbox').first().should('have.value', 'resting'); + cy.get('.frappe-control[data-fieldname=icon]').findByRole('textbox').should('have.value', 'resting'); cy.get('@dialog').then(dialog => { let value = dialog.get_value('icon'); expect(value).to.equal('resting'); @@ -36,14 +36,14 @@ context('Control Icon', () => { it('search for icon and clear search input', () => { let search_text = 'ed'; - cy.findByRole('searchbox').first().click().type(search_text); + cy.get('.icon-picker').findByRole('searchbox').click().type(search_text); cy.get('.icon-section .icon-wrapper:not(.hidden)').then(i => { cy.get(`.icon-section .icon-wrapper[id*='${search_text}']`).then(icons => { expect(i.length).to.equal(icons.length); }); }); - cy.findByRole('searchbox').clear().blur(); + cy.get('.icon-picker').findByRole('searchbox').clear().blur(); cy.get('.icon-section .icon-wrapper').should('not.have.class', 'hidden'); }); diff --git a/cypress/integration/control_link.js b/cypress/integration/control_link.js index d2aa467af1..7d44a71d06 100644 --- a/cypress/integration/control_link.js +++ b/cypress/integration/control_link.js @@ -35,7 +35,7 @@ context('Control Link', () => { cy.wait('@search_link'); cy.get('@input').type('todo for link', { delay: 200 }); cy.wait('@search_link'); - cy.findByRole('listbox').should('be.visible'); + cy.get('.frappe-control[data-fieldname=link]').findByRole('listbox').should('be.visible'); cy.get('.frappe-control[data-fieldname=link] input').type('{enter}', { delay: 100 }); cy.get('.frappe-control[data-fieldname=link] input').blur(); cy.get('@dialog').then(dialog => { diff --git a/cypress/integration/form.js b/cypress/integration/form.js index 909955c1df..d20750b1d5 100644 --- a/cypress/integration/form.js +++ b/cypress/integration/form.js @@ -26,7 +26,7 @@ context('Form', () => { cy.visit('/app/contact'); cy.add_filter(); cy.get('.filter-field .input-with-feedback.form-control').type('123', { force: true }); - cy.get('.filter-popover .apply-filters').click({ force: true }); + cy.findByRole('button', {name: 'Apply Filters'}).click({ force: true }); cy.visit('/app/contact/Test Form Contact 3'); cy.get('.prev-doc').should('be.visible').click(); cy.get('.msgprint-dialog .modal-body').contains('No further records').should('be.visible'); diff --git a/cypress/integration/form_tour.js b/cypress/integration/form_tour.js index d12be63f3b..d2d39679a8 100644 --- a/cypress/integration/form_tour.js +++ b/cypress/integration/form_tour.js @@ -9,7 +9,7 @@ context('Form Tour', () => { const open_test_form_tour = () => { cy.visit('/app/form-tour/Test Form Tour'); - cy.get('button[data-label="Show%20Tour"]').should('be.visible').and('contain', 'Show Tour').as('show_tour'); + cy.findByRole('button', {name: 'Show Tour'}).should('be.visible').as('show_tour'); cy.get('@show_tour').click(); cy.wait(500); cy.url().should('include', '/app/contact'); @@ -23,7 +23,7 @@ context('Form Tour', () => { cy.get('#driver-popover-item').should('be.visible'); cy.get('.frappe-control[data-fieldname="first_name"]').as('first_name'); cy.get('@first_name').should('have.class', 'driver-highlighted-element'); - cy.get('.driver-next-btn').as('next_btn'); + cy.get('#driver-popover-item').findByRole('button', {name: 'Next'}).as('next_btn'); // next btn shouldn't move to next step, if first name is not entered cy.get('@next_btn').click(); @@ -39,7 +39,7 @@ context('Form Tour', () => { // assert field is highlighted cy.get('.frappe-control[data-fieldname="last_name"]').as('last_name'); cy.get('@last_name').should('have.class', 'driver-highlighted-element'); - + // after filling the field, next step should be highlighted cy.fill_field('last_name', 'Test Last Name', 'Data'); cy.wait(500); @@ -49,12 +49,12 @@ context('Form Tour', () => { // assert field is highlighted cy.get('.frappe-control[data-fieldname="phone_nos"]').as('phone_nos'); cy.get('@phone_nos').should('have.class', 'driver-highlighted-element'); - + // move to next step cy.wait(500); cy.get('@next_btn').click(); cy.wait(500); - + // assert add row btn is highlighted cy.get('@phone_nos').find('.grid-add-row').as('add_row'); cy.get('@add_row').should('have.class', 'driver-highlighted-element'); @@ -78,11 +78,11 @@ context('Form Tour', () => { // collapse row cy.get('.grid-row-open .grid-collapse-row').click(); cy.wait(500); - + // assert save btn is highlighted cy.get('.primary-action').should('have.class', 'driver-highlighted-element'); - cy.get('@next_btn').should('contain', 'Save'); + cy.wait(500); + cy.get('#driver-popover-item').findByRole('button', {name: 'Save'}).should('be.visible'); }); }); - \ No newline at end of file diff --git a/cypress/integration/grid_pagination.js b/cypress/integration/grid_pagination.js index 8f6b79c1f4..c07230d2b8 100644 --- a/cypress/integration/grid_pagination.js +++ b/cypress/integration/grid_pagination.js @@ -30,12 +30,12 @@ context('Grid Pagination', () => { it('adds and deletes rows and changes page', () => { cy.visit('/app/contact/Test Contact'); cy.get('.frappe-control[data-fieldname="phone_nos"]').as('table'); - cy.get('@table').find('button.grid-add-row').click(); + cy.get('@table').findByRole('button', {name: 'Add Row'}).click(); cy.get('@table').find('.grid-body .row-index').should('contain', 1001); cy.get('@table').find('.current-page-number').should('contain', '21'); cy.get('@table').find('.total-page-number').should('contain', '21'); cy.get('@table').find('.grid-body .grid-row .grid-row-check').click({ force: true }); - cy.get('@table').find('button.grid-remove-rows').click(); + cy.get('@table').findByRole('button', {name: 'Delete'}).click(); cy.get('@table').find('.grid-body .row-index').last().should('contain', 1000); cy.get('@table').find('.current-page-number').should('contain', '20'); cy.get('@table').find('.total-page-number').should('contain', '20'); diff --git a/cypress/integration/list_view_settings.js b/cypress/integration/list_view_settings.js index 52512b911e..61d4b8aae5 100644 --- a/cypress/integration/list_view_settings.js +++ b/cypress/integration/list_view_settings.js @@ -17,9 +17,9 @@ context('List View Settings', () => { cy.get('.dropdown-menu li').filter(':visible').contains('List Settings').click(); cy.get('.modal-dialog').should('contain', 'DocType Settings'); - cy.get('input[data-fieldname="disable_count"]').check({ force: true }); - cy.get('input[data-fieldname="disable_sidebar_stats"]').check({ force: true }); - cy.get('button').filter(':visible').contains('Save').click(); + cy.findByLabelText('Disable Count').check({ force: true }); + cy.findByLabelText('Disable Sidebar Stats').check({ force: true }); + cy.findByRole('button', {name: 'Save'}).click(); cy.reload({ force: true }); @@ -29,8 +29,8 @@ context('List View Settings', () => { cy.get('.menu-btn-group button').click({ force: true }); cy.get('.dropdown-menu li').filter(':visible').contains('List Settings').click(); cy.get('.modal-dialog').should('contain', 'DocType Settings'); - cy.get('input[data-fieldname="disable_count"]').uncheck({ force: true }); - cy.get('input[data-fieldname="disable_sidebar_stats"]').uncheck({ force: true }); - cy.get('button').filter(':visible').contains('Save').click(); + cy.findByLabelText('Disable Count').uncheck({ force: true }); + cy.findByLabelText('Disable Sidebar Stats').uncheck({ force: true }); + cy.findByRole('button', {name: 'Save'}).click(); }); }); diff --git a/cypress/integration/login.js b/cypress/integration/login.js index 6b109dd18d..98739bb4c9 100644 --- a/cypress/integration/login.js +++ b/cypress/integration/login.js @@ -11,13 +11,13 @@ context('Login', () => { it('validates password', () => { cy.get('#login_email').type('Administrator'); - cy.get('.btn-login:visible').click(); + cy.findByRole('button', {name: 'Login'}).click(); cy.location('pathname').should('eq', '/login'); }); it('validates email', () => { cy.get('#login_password').type('qwe'); - cy.get('.btn-login:visible').click(); + cy.findByRole('button', {name: 'Login'}).click(); cy.location('pathname').should('eq', '/login'); }); @@ -25,8 +25,8 @@ context('Login', () => { cy.get('#login_email').type('Administrator'); cy.get('#login_password').type('qwer'); - cy.get('.btn-login:visible').click(); - cy.get('.btn-login:visible').contains('Invalid Login. Try again.'); + cy.findByRole('button', {name: 'Login'}).click(); + cy.findByRole('button', {name: 'Invalid Login. Try again.'}).should('exist'); cy.location('pathname').should('eq', '/login'); }); @@ -34,7 +34,7 @@ context('Login', () => { cy.get('#login_email').type('Administrator'); cy.get('#login_password').type(Cypress.config('adminPassword')); - cy.get('.btn-login:visible').click(); + cy.findByRole('button', {name: 'Login'}).click(); cy.location('pathname').should('eq', '/app'); cy.window().its('frappe.session.user').should('eq', 'Administrator'); }); @@ -60,7 +60,7 @@ context('Login', () => { cy.get('#login_email').type('Administrator'); cy.get('#login_password').type(Cypress.config('adminPassword')); - cy.get('.btn-login:visible').click(); + cy.findByRole('button', {name: 'Login'}).click(); // verify redirected location and url params after login cy.url().should('include', '/me?' + payload.toString().replace('+', '%20')); diff --git a/cypress/integration/recorder.js b/cypress/integration/recorder.js index 5b7692d8ff..7a62b2e6d9 100644 --- a/cypress/integration/recorder.js +++ b/cypress/integration/recorder.js @@ -16,24 +16,24 @@ context('Recorder', () => { it('Navigate to Recorder', () => { cy.visit('/app'); cy.awesomebar('recorder'); - cy.get('h3').should('contain', 'Recorder'); + cy.findByTitle('Recorder').should('exist'); cy.url().should('include', '/recorder/detail'); }); it('Recorder Empty State', () => { - cy.get('.title-text').should('contain', 'Recorder'); + cy.findByTitle('Recorder').should('exist'); cy.get('.indicator-pill').should('contain', 'Inactive').should('have.class', 'red'); - cy.get('.primary-action').should('contain', 'Start'); - cy.get('.btn-secondary').should('contain', 'Clear'); + cy.findByRole('button', {name: 'Start'}).should('exist'); + cy.findByRole('button', {name: 'Clear'}).should('exist'); cy.get('.msg-box').should('contain', 'Inactive'); - cy.get('.msg-box .btn-primary').should('contain', 'Start Recording'); + cy.findByRole('button', {name: 'Start Recording'}).should('exist'); }); it('Recorder Start', () => { - cy.get('.primary-action').should('contain', 'Start').click(); + cy.findByRole('button', {name: 'Start'}).click(); cy.get('.indicator-pill').should('contain', 'Active').should('have.class', 'green'); cy.get('.msg-box').should('contain', 'No Requests'); @@ -46,12 +46,12 @@ context('Recorder', () => { cy.get('.list-count').should('contain', '20 of '); cy.visit('/app/recorder'); - cy.get('.title-text').should('contain', 'Recorder'); + cy.findByTitle('Recorder').should('exist'); cy.get('.result-list').should('contain', '/api/method/frappe.desk.reportview.get'); }); it('Recorder View Request', () => { - cy.get('.primary-action').should('contain', 'Start').click(); + cy.findByRole('button', {name: 'Start'}).click(); cy.visit('/app/List/DocType/List'); cy.intercept('POST', '/api/method/frappe.desk.reportview.get').as('list_refresh'); diff --git a/cypress/integration/report_view.js b/cypress/integration/report_view.js index ea76246ae2..e762eebea1 100644 --- a/cypress/integration/report_view.js +++ b/cypress/integration/report_view.js @@ -23,7 +23,7 @@ context('Report View', () => { let cell = cy.get('.dt-row-0 > .dt-cell--col-4'); // select the cell cell.dblclick(); - cell.find('input[data-fieldname="enabled"]').check({ force: true }); + cell.findByRole('checkbox').check({ force: true }); cy.get('.dt-row-0 > .dt-cell--col-5').click(); cy.wait('@value-update'); cy.get('@doc').then(doc => { diff --git a/cypress/integration/timeline.js b/cypress/integration/timeline.js index c7bbe29e5a..7a8f3a159b 100644 --- a/cypress/integration/timeline.js +++ b/cypress/integration/timeline.js @@ -10,26 +10,26 @@ context('Timeline', () => { it('Adding new ToDo, adding new comment, verifying comment addition & deletion and deleting ToDo', () => { //Adding new ToDo cy.click_listview_primary_button('Add ToDo'); - cy.get('.modal-footer > .custom-actions > .btn').contains('Edit in full page').click(); - cy.get('.row > .section-body > .form-column > form > .frappe-control > .form-group > .control-input-wrapper > .control-input > .ql-container > .ql-editor').eq(0).type('Test ToDo', {force: true}); + cy.findByRole('button', {name: 'Edit in full page'}).click(); + cy.get('[data-fieldname="description"] .ql-editor').eq(0).type('Test ToDo', {force: true}); cy.wait(200); - cy.get('#page-ToDo > .page-head > .container > .row > .col > .standard-actions > .primary-action').contains('Save').click(); + cy.findByRole('button', {name: 'Save'}).click(); cy.wait(700); cy.visit('/app/todo'); - cy.get('.list-row > .level-left > .list-subject > .level-item.ellipsis > .ellipsis').eq(0).click(); + cy.get('.level-item.ellipsis').eq(0).click(); //To check if the comment box is initially empty and tying some text into it - cy.get('.comment-input-container > .frappe-control > .ql-container > .ql-editor').should('contain', '').type('Testing Timeline'); + cy.get('[data-fieldname="comment"] .ql-editor').should('contain', '').type('Testing Timeline'); //Adding new comment - cy.get('.comment-input-wrapper > .btn').contains('Comment').click(); + cy.findByRole('button', {name: 'Comment'}).click(); //To check if the commented text is visible in the timeline content cy.get('.timeline-content').should('contain', 'Testing Timeline'); //Editing comment cy.click_timeline_action_btn(0); - cy.get('.timeline-content > .timeline-message-box > .comment-edit-box > .frappe-control > .ql-container > .ql-editor').first().type(' 123'); + cy.get('.timeline-content [data-fieldname="comment"] .ql-editor').first().type(' 123'); cy.click_timeline_action_btn(0); //To check if the edited comment text is visible in timeline content @@ -37,20 +37,20 @@ context('Timeline', () => { //Discarding comment cy.click_timeline_action_btn(0); - cy.get('.actions > .btn').eq(1).first().click(); + cy.findByRole('button', {name: 'Dismiss'}).click(); //To check if after discarding the timeline content is same as previous cy.get('.timeline-content').should('contain', 'Testing Timeline 123'); //Deleting the added comment cy.get('.actions > .btn > .icon').first().click(); - cy.get('.modal-footer > .standard-actions > .btn-primary').contains('Yes').click(); + cy.findByRole('button', {name: 'Yes'}).click(); cy.click_modal_primary_button('Yes'); //Deleting the added ToDo - cy.get('#page-ToDo > .page-head > .container > .row > .col > .standard-actions > .menu-btn-group > .btn').click({force: true}); - cy.get('.menu-btn-group > .dropdown-menu > li > .grey-link').eq(17).click({force: true}); - cy.get('.modal.show > .modal-dialog > .modal-content > .modal-footer > .standard-actions > .btn-primary').contains('Yes').click({force: true}); + cy.get('.menu-btn-group button').eq(1).click(); + cy.get('.menu-btn-group [data-label="Delete"]').click(); + cy.findByRole('button', {name: 'Yes'}).click(); }); it('Timeline should have submit and cancel activity information', () => { @@ -64,31 +64,31 @@ context('Timeline', () => { //Adding a new entry for the created custom doctype cy.fill_field('title', 'Test'); - cy.get('.modal-footer > .standard-actions > .btn-primary').contains('Save').click(); - cy.get('.modal-footer > .standard-actions > .btn-primary').contains('Submit').click(); + cy.findByRole('button', {name: 'Save'}).click(); + cy.findByRole('button', {name: 'Submit'}).click(); cy.visit('/app/custom-submittable-doctype'); cy.get('.list-subject > .bold > .ellipsis').eq(0).click(); //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('.page-actions > .standard-actions > .btn-secondary').contains('Cancel').click({delay: 900}); - cy.get('.modal-footer > .standard-actions > .btn-primary').contains('Yes').click(); - + cy.findByRole('button', {name: 'Cancel'}).click({delay: 900}); + cy.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'); //Deleting the document cy.visit('/app/custom-submittable-doctype'); cy.get('.list-subject > .select-like > .list-row-checkbox').eq(0).click(); - cy.get('.page-actions > .standard-actions > .actions-btn-group > .btn').contains('Actions').click(); + cy.findByRole('button', {name: 'Actions'}).click(); cy.get('.actions-btn-group > .dropdown-menu > li > .grey-link').eq(7).click(); cy.click_modal_primary_button('Yes', {force: true, delay: 700}); //Deleting the custom doctype cy.visit('/app/doctype'); cy.get('.list-subject > .select-like > .list-row-checkbox').eq(0).click(); - cy.get('.page-actions > .standard-actions > .actions-btn-group > .btn').contains('Actions').click(); - cy.get('.actions-btn-group > .dropdown-menu > li > .grey-link').eq(5).click(); + cy.findByRole('button', {name: 'Actions'}).click(); + cy.get('.actions-btn-group [data-label="Delete"]').click(); cy.click_modal_primary_button('Yes'); }); }); \ No newline at end of file From 29dfffb9c5d1877170ef19e14740f335e079df0a Mon Sep 17 00:00:00 2001 From: MitulDavid Date: Wed, 18 Aug 2021 19:32:16 +0530 Subject: [PATCH 3/3] refactor: Replace .format() with f-strings --- frappe/commands/utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frappe/commands/utils.py b/frappe/commands/utils.py index ac574841fe..be8304e45d 100644 --- a/frappe/commands/utils.py +++ b/frappe/commands/utils.py @@ -589,14 +589,14 @@ def run_ui_tests(context, app, headless=False, parallel=True, ci_build_id=None): admin_password = frappe.get_conf(site).admin_password # override baseUrl using env variable - site_env = 'CYPRESS_baseUrl={}'.format(site_url) - password_env = 'CYPRESS_adminPassword={}'.format(admin_password) if admin_password else '' + site_env = f'CYPRESS_baseUrl={site_url}' + password_env = f'CYPRESS_adminPassword={admin_password}' if admin_password else '' os.chdir(app_base_path) node_bin = subprocess.getoutput("npm bin") - cypress_path = "{0}/cypress".format(node_bin) - plugin_path = "{0}/../cypress-file-upload".format(node_bin) + cypress_path = f"{node_bin}/cypress" + plugin_path = f"{node_bin}/../cypress-file-upload" testing_library_path = f"{node_bin}/../@testing-library" # check if cypress in path...if not, install it. @@ -619,7 +619,7 @@ def run_ui_tests(context, app, headless=False, parallel=True, ci_build_id=None): formatted_command += ' --parallel' if ci_build_id: - formatted_command += ' --ci-build-id {}'.format(ci_build_id) + formatted_command += f' --ci-build-id {ci_build_id}' click.secho("Running Cypress...", fg="yellow") frappe.commands.popen(formatted_command, cwd=app_base_path, raise_err=True)