diff --git a/cypress/integration/list/list.spec.js b/cypress/integration/list/list.spec.js index 1def740e9..3c8c0d6fc 100644 --- a/cypress/integration/list/list.spec.js +++ b/cypress/integration/list/list.spec.js @@ -262,11 +262,15 @@ describe('Lists', () => { it('Shows tasks from the current and next month', () => { const now = new Date() + const nextMonth = now + nextMonth.setDate(1) + nextMonth.setMonth(now.getMonth() + 1) + cy.visit('/lists/1/gantt') cy.get('.gantt-chart-container .gantt-chart .months') .should('contain', format(now, 'MMMM')) - .should('contain', format(now.setMonth(now.getMonth() + 1), 'MMMM')) + .should('contain', format(nextMonth, 'MMMM')) }) it('Shows tasks with dates', () => { @@ -461,7 +465,7 @@ describe('Lists', () => { }) cy.visit('/lists/1/kanban') - cy.getAttached('.kanban .bucket .tasks .task') + cy.getSettled('.kanban .bucket .tasks .task') .contains(tasks[0].title) .should('be.visible') .click() @@ -483,7 +487,7 @@ describe('Lists', () => { const task = tasks[0] cy.visit('/lists/1/kanban') - cy.getAttached('.kanban .bucket .tasks .task') + cy.getSettled('.kanban .bucket .tasks .task') .contains(task.title) .should('be.visible') .click() diff --git a/cypress/integration/task/task.spec.js b/cypress/integration/task/task.spec.js index be95a475e..e07936375 100644 --- a/cypress/integration/task/task.spec.js +++ b/cypress/integration/task/task.spec.js @@ -113,9 +113,10 @@ describe('Task', () => { cy.visit(`/tasks/${tasks[0].id}`) cy.get('.task-view .heading .is-done') - .should('exist') + .should('be.visible') .should('contain', 'Done') cy.get('.task-view .action-buttons p.created') + .should('be.visible') .should('contain', 'Done') }) @@ -183,9 +184,11 @@ describe('Task', () => { cy.visit(`/tasks/${tasks[0].id}`) cy.get('.task-view .comments .media.comment .editor .vue-easymde .EasyMDEContainer .CodeMirror-scroll') + .should('be.visible') .type('{selectall}New Comment') cy.get('.task-view .comments .media.comment .button:not([disabled])') .contains('Comment') + .should('be.visible') .click() cy.get('.task-view .comments .media.comment .editor') @@ -232,6 +235,7 @@ describe('Task', () => { cy.visit(`/tasks/${tasks[0].id}`) cy.get('.task-view .action-buttons .button') + .should('be.visible') .contains('Delete task') .click() cy.get('.modal-mask .modal-container .modal-content .header') @@ -314,6 +318,7 @@ describe('Task', () => { cy.get('.task-view .action-buttons .button') .contains('Add labels') + .should('be.visible') .click() cy.get('.task-view .details.labels-list .multiselect input') .type(newLabelText) @@ -369,6 +374,7 @@ describe('Task', () => { cy.visit(`/tasks/${tasks[0].id}`) cy.get('.task-view .details.labels-list .multiselect .input-wrapper') + .should('be.visible') .should('contain', labels[0].title) cy.get('.task-view .details.labels-list .multiselect .input-wrapper') .children() diff --git a/cypress/support/commands.js b/cypress/support/commands.js index ccdc6f366..4bc18b684 100644 --- a/cypress/support/commands.js +++ b/cypress/support/commands.js @@ -1,17 +1,33 @@ /** - * getAttached(selector) - * getAttached(selectorFn) + * Recursively gets an element, returning only after it's determined to be attached to the DOM for good. * - * Waits until the selector finds an attached element, then yields it (wrapped). - * selectorFn, if provided, is passed $(document). Don't use cy methods inside selectorFn. - * - * Source: https://github.com/cypress-io/cypress/issues/5743#issuecomment-650421731 + * Source: https://github.com/cypress-io/cypress/issues/7306#issuecomment-850621378 */ -Cypress.Commands.add('getAttached', selector => { - const getElement = typeof selector === 'function' ? selector : $d => $d.find(selector); - let $el = null; - return cy.document().should($d => { - $el = getElement(Cypress.$($d)); - expect(Cypress.dom.isDetached($el)).to.be.false; - }).then(() => cy.wrap($el)); -}); +Cypress.Commands.add('getSettled', (selector, opts = {}) => { + const retries = opts.retries || 3 + const delay = opts.delay || 100 + + const isAttached = (resolve, count = 0) => { + const el = Cypress.$(selector) + + // is element attached to the DOM? + count = Cypress.dom.isAttached(el) ? count + 1 : 0 + + // hit our base case, return the element + if (count >= retries) { + return resolve(el) + } + + // retry after a bit of a delay + setTimeout(() => isAttached(resolve, count), delay) + } + + // wrap, so we can chain cypress commands off the result + return cy.wrap(null).then(() => { + return new Cypress.Promise((resolve) => { + return isAttached(resolve, 0) + }).then((el) => { + return cy.wrap(el) + }) + }) +})