diff --git a/cypress/integration/list/list-history.spec.js b/cypress/integration/list/list-history.spec.js new file mode 100644 index 000000000..b7633cbda --- /dev/null +++ b/cypress/integration/list/list-history.spec.js @@ -0,0 +1,56 @@ +import {ListFactory} from '../../factories/list' + +import '../../support/authenticateUser' +import {prepareLists} from './prepareLists' + +describe('List History', () => { + prepareLists() + + it('should show a list history on the home page', () => { + cy.intercept(Cypress.env('API_URL') + '/namespaces*').as('loadNamespaces') + cy.intercept(Cypress.env('API_URL') + '/lists/*').as('loadList') + + const lists = ListFactory.create(6) + + cy.visit('/') + cy.wait('@loadNamespaces') + cy.get('body') + .should('not.contain', 'Last viewed') + + cy.visit(`/lists/${lists[0].id}`) + cy.wait('@loadNamespaces') + cy.wait('@loadList') + cy.visit(`/lists/${lists[1].id}`) + cy.wait('@loadNamespaces') + cy.wait('@loadList') + cy.visit(`/lists/${lists[2].id}`) + cy.wait('@loadNamespaces') + cy.wait('@loadList') + cy.visit(`/lists/${lists[3].id}`) + cy.wait('@loadNamespaces') + cy.wait('@loadList') + cy.visit(`/lists/${lists[4].id}`) + cy.wait('@loadNamespaces') + cy.wait('@loadList') + cy.visit(`/lists/${lists[5].id}`) + cy.wait('@loadNamespaces') + cy.wait('@loadList') + + // cy.visit('/') + // cy.wait('@loadNamespaces') + // Not using cy.visit here to work around the redirect issue fixed in #1337 + cy.get('nav.menu.top-menu a') + .contains('Overview') + .click() + + cy.get('body') + .should('contain', 'Last viewed') + cy.get('.list-cards-wrapper-2-rows') + .should('not.contain', lists[0].title) + .should('contain', lists[1].title) + .should('contain', lists[2].title) + .should('contain', lists[3].title) + .should('contain', lists[4].title) + .should('contain', lists[5].title) + }) +}) \ No newline at end of file diff --git a/cypress/integration/list/list-view-gantt.spec.js b/cypress/integration/list/list-view-gantt.spec.js new file mode 100644 index 000000000..69805a30d --- /dev/null +++ b/cypress/integration/list/list-view-gantt.spec.js @@ -0,0 +1,76 @@ +import {formatISO, format} from 'date-fns' +import {TaskFactory} from '../../factories/task' +import {prepareLists} from './prepareLists' + +import '../../support/authenticateUser' + +describe('List View Gantt', () => { + prepareLists() + + it('Hides tasks with no dates', () => { + const tasks = TaskFactory.create(1) + cy.visit('/lists/1/gantt') + + cy.get('.gantt-chart .tasks') + .should('not.contain', tasks[0].title) + }) + + 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 .months') + .should('contain', format(now, 'MMMM')) + .should('contain', format(nextMonth, 'MMMM')) + }) + + it('Shows tasks with dates', () => { + const now = new Date() + const tasks = TaskFactory.create(1, { + start_date: formatISO(now), + end_date: formatISO(now.setDate(now.getDate() + 4)) + }) + cy.visit('/lists/1/gantt') + + cy.get('.gantt-chart .tasks') + .should('not.be.empty') + cy.get('.gantt-chart .tasks') + .should('contain', tasks[0].title) + }) + + it('Shows tasks with no dates after enabling them', () => { + TaskFactory.create(1, { + start_date: null, + end_date: null, + }) + cy.visit('/lists/1/gantt') + + cy.get('.gantt-options .fancycheckbox') + .contains('Show tasks which don\'t have dates set') + .click() + + cy.get('.gantt-chart .tasks') + .should('not.be.empty') + cy.get('.gantt-chart .tasks .task.nodate') + .should('exist') + }) + + it('Drags a task around', () => { + const now = new Date() + TaskFactory.create(1, { + start_date: formatISO(now), + end_date: formatISO(now.setDate(now.getDate() + 4)) + }) + cy.visit('/lists/1/gantt') + + cy.get('.gantt-chart .tasks .task') + .first() + .trigger('mousedown', {which: 1}) + .trigger('mousemove', {clientX: 500, clientY: 0}) + .trigger('mouseup', {force: true}) + }) +}) \ No newline at end of file diff --git a/cypress/integration/list/list-view-kanban.spec.js b/cypress/integration/list/list-view-kanban.spec.js new file mode 100644 index 000000000..52d672829 --- /dev/null +++ b/cypress/integration/list/list-view-kanban.spec.js @@ -0,0 +1,196 @@ +import {BucketFactory} from '../../factories/bucket' +import {ListFactory} from '../../factories/list' +import {TaskFactory} from '../../factories/task' +import {prepareLists} from './prepareLists' + +import '../../support/authenticateUser' + +describe('List View Kanban', () => { + let buckets + prepareLists() + + beforeEach(() => { + buckets = BucketFactory.create(2) + }) + + it('Shows all buckets with their tasks', () => { + const data = TaskFactory.create(10, { + list_id: 1, + bucket_id: 1, + }) + cy.visit('/lists/1/kanban') + + cy.get('.kanban .bucket .title') + .contains(buckets[0].title) + .should('exist') + cy.get('.kanban .bucket .title') + .contains(buckets[1].title) + .should('exist') + cy.get('.kanban .bucket') + .first() + .should('contain', data[0].title) + }) + + it('Can add a new task to a bucket', () => { + TaskFactory.create(2, { + list_id: 1, + bucket_id: 1, + }) + cy.visit('/lists/1/kanban') + + cy.getSettled('.kanban .bucket') + .contains(buckets[0].title) + .get('.bucket-footer .button') + .contains('Add another task') + .click() + cy.get('.kanban .bucket') + .contains(buckets[0].title) + .get('.bucket-footer .field .control input.input') + .type('New Task{enter}') + + cy.get('.kanban .bucket') + .first() + .should('contain', 'New Task') + }) + + it('Can create a new bucket', () => { + cy.visit('/lists/1/kanban') + + cy.get('.kanban .bucket.new-bucket .button') + .click() + cy.get('.kanban .bucket.new-bucket input.input') + .type('New Bucket{enter}') + + cy.wait(1000) // Wait for the request to finish + cy.get('.kanban .bucket .title') + .contains('New Bucket') + .should('exist') + }) + + it('Can set a bucket limit', () => { + cy.visit('/lists/1/kanban') + + cy.getSettled('.kanban .bucket .bucket-header .dropdown.options .dropdown-trigger') + .first() + .click() + cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item') + .contains('Limit: Not Set') + .click() + cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item .field input.input') + .first() + .type(3) + cy.get('[data-cy="setBucketLimit"]') + .first() + .click() + + cy.get('.kanban .bucket .bucket-header span.limit') + .contains('0/3') + .should('exist') + }) + + it('Can rename a bucket', () => { + cy.visit('/lists/1/kanban') + + cy.getSettled('.kanban .bucket .bucket-header .title') + .first() + .type('{selectall}New Bucket Title{enter}') + cy.get('.kanban .bucket .bucket-header .title') + .first() + .should('contain', 'New Bucket Title') + }) + + it('Can delete a bucket', () => { + cy.visit('/lists/1/kanban') + + cy.getSettled('.kanban .bucket .bucket-header .dropdown.options .dropdown-trigger') + .first() + .click() + cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item') + .contains('Delete') + .click() + cy.get('.modal-mask .modal-container .modal-content .header') + .should('contain', 'Delete the bucket') + cy.get('.modal-mask .modal-container .modal-content .actions .button') + .contains('Do it!') + .click() + + cy.get('.kanban .bucket .title') + .contains(buckets[0].title) + .should('not.exist') + cy.get('.kanban .bucket .title') + .contains(buckets[1].title) + .should('exist') + }) + + it('Can drag tasks around', () => { + const tasks = TaskFactory.create(2, { + list_id: 1, + bucket_id: 1, + }) + cy.visit('/lists/1/kanban') + + cy.getSettled('.kanban .bucket .tasks .task') + .contains(tasks[0].title) + .first() + .drag('.kanban .bucket:nth-child(2) .tasks .dropper') + + cy.get('.kanban .bucket:nth-child(2) .tasks') + .should('contain', tasks[0].title) + cy.get('.kanban .bucket:nth-child(1) .tasks') + .should('not.contain', tasks[0].title) + }) + + it('Should navigate to the task when the task card is clicked', () => { + const tasks = TaskFactory.create(5, { + id: '{increment}', + list_id: 1, + bucket_id: 1, + }) + cy.visit('/lists/1/kanban') + + cy.getSettled('.kanban .bucket .tasks .task') + .contains(tasks[0].title) + .should('be.visible') + .click() + + cy.url() + .should('contain', `/tasks/${tasks[0].id}`, { timeout: 1000 }) + }) + + it('Should remove a task from the kanban board when moving it to another list', () => { + const lists = ListFactory.create(2) + BucketFactory.create(2, { + list_id: '{increment}', + }) + const tasks = TaskFactory.create(5, { + id: '{increment}', + list_id: 1, + bucket_id: 1, + }) + const task = tasks[0] + cy.visit('/lists/1/kanban') + + cy.getSettled('.kanban .bucket .tasks .task') + .contains(task.title) + .should('be.visible') + .click() + + cy.get('.task-view .action-buttons .button', { timeout: 3000 }) + .contains('Move task') + .click() + cy.get('.task-view .content.details .field .multiselect.control .input-wrapper input') + .type(`${lists[1].title}{enter}`) + // The requests happen with a 200ms timeout. Because of that, the results are not yet there when cypress + // presses enter and we can't simulate pressing on enter to select the item. + cy.get('.task-view .content.details .field .multiselect.control .search-results') + .children() + .first() + .click() + + cy.get('.global-notification', { timeout: 1000 }) + .should('contain', 'Success') + cy.go('back') + cy.get('.kanban .bucket') + .should('not.contain', task.title) + }) +}) \ No newline at end of file diff --git a/cypress/integration/list/list-view-list.spec.js b/cypress/integration/list/list-view-list.spec.js new file mode 100644 index 000000000..e1a4a0f69 --- /dev/null +++ b/cypress/integration/list/list-view-list.spec.js @@ -0,0 +1,97 @@ +import {UserListFactory} from '../../factories/users_list' +import {TaskFactory} from '../../factories/task' +import {UserFactory} from '../../factories/user' +import {ListFactory} from '../../factories/list' +import {prepareLists} from './prepareLists' + +import '../../support/authenticateUser' + +describe('List View List', () => { + prepareLists() + + it('Should be an empty list', () => { + cy.visit('/lists/1') + cy.url() + .should('contain', '/lists/1/list') + cy.get('.list-title h1') + .should('contain', 'First List') + cy.get('.list-title .dropdown') + .should('exist') + cy.get('p') + .contains('This list is currently empty.') + .should('exist') + }) + + it('Should navigate to the task when the title is clicked', () => { + const tasks = TaskFactory.create(5, { + id: '{increment}', + list_id: 1, + }) + cy.visit('/lists/1/list') + + cy.get('.tasks .task .tasktext') + .contains(tasks[0].title) + .first() + .click() + + cy.url() + .should('contain', `/tasks/${tasks[0].id}`) + }) + + it('Should not see any elements for a list which is shared read only', () => { + UserFactory.create(2) + UserListFactory.create(1, { + list_id: 2, + user_id: 1, + right: 0, + }) + const lists = ListFactory.create(2, { + owner_id: '{increment}', + namespace_id: '{increment}', + }) + cy.visit(`/lists/${lists[1].id}/`) + + cy.get('.list-title a.icon') + .should('not.exist') + cy.get('input.input[placeholder="Add a new task..."') + .should('not.exist') + }) + + it('Should only show the color of a list in the navigation and not in the list view', () => { + const lists = ListFactory.create(1, { + hex_color: '00db60', + }) + TaskFactory.create(10, { + list_id: lists[0].id, + }) + cy.visit(`/lists/${lists[0].id}/`) + + cy.get('.menu-list li .list-menu-link .color-bubble') + .should('have.css', 'background-color', 'rgb(0, 219, 96)') + cy.get('.tasks-container .tasks .color-bubble') + .should('not.exist') + }) + + it('Should paginate for > 50 tasks', () => { + const tasks = TaskFactory.create(100, { + id: '{increment}', + title: i => `task${i}`, + list_id: 1, + }) + cy.visit('/lists/1/list') + + cy.get('.tasks-container .tasks') + .should('contain', tasks[99].title) + + cy.get('.card-content .pagination .pagination-link') + .contains('2') + .click() + + cy.url() + .should('contain', '?page=2') + cy.get('.tasks-container .tasks') + .should('contain', tasks[1].title) + cy.get('.tasks-container .tasks') + .should('not.contain', tasks[99].title) + }) +}) \ No newline at end of file diff --git a/cypress/integration/list/list-view-table.spec.js b/cypress/integration/list/list-view-table.spec.js new file mode 100644 index 000000000..e0336efc5 --- /dev/null +++ b/cypress/integration/list/list-view-table.spec.js @@ -0,0 +1,52 @@ +import {TaskFactory} from '../../factories/task' + +import '../../support/authenticateUser' + +describe('List View Table', () => { + it('Should show a table with tasks', () => { + const tasks = TaskFactory.create(1) + cy.visit('/lists/1/table') + + cy.get('.list-table table.table') + .should('exist') + cy.get('.list-table table.table') + .should('contain', tasks[0].title) + }) + + it('Should have working column switches', () => { + TaskFactory.create(1) + cy.visit('/lists/1/table') + + cy.get('.list-table .filter-container .items .button') + .contains('Columns') + .click() + cy.get('.list-table .filter-container .card.columns-filter .card-content .fancycheckbox .check') + .contains('Priority') + .click() + cy.get('.list-table .filter-container .card.columns-filter .card-content .fancycheckbox .check') + .contains('Done') + .click() + + cy.get('.list-table table.table th') + .contains('Priority') + .should('exist') + cy.get('.list-table table.table th') + .contains('Done') + .should('not.exist') + }) + + it('Should navigate to the task when the title is clicked', () => { + const tasks = TaskFactory.create(5, { + id: '{increment}', + list_id: 1, + }) + cy.visit('/lists/1/table') + + cy.get('.list-table table.table') + .contains(tasks[0].title) + .click() + + cy.url() + .should('contain', `/tasks/${tasks[0].id}`) + }) +}) \ No newline at end of file diff --git a/cypress/integration/list/list.spec.js b/cypress/integration/list/list.spec.js index 8b8630fdb..ce7f6f551 100644 --- a/cypress/integration/list/list.spec.js +++ b/cypress/integration/list/list.spec.js @@ -1,25 +1,11 @@ -import {formatISO, format} from 'date-fns' - import {TaskFactory} from '../../factories/task' -import {ListFactory} from '../../factories/list' -import {UserListFactory} from '../../factories/users_list' -import {UserFactory} from '../../factories/user' -import {NamespaceFactory} from '../../factories/namespace' -import {BucketFactory} from '../../factories/bucket' +import {prepareLists} from './prepareLists' import '../../support/authenticateUser' describe('Lists', () => { let lists - - beforeEach(() => { - UserFactory.create(1) - NamespaceFactory.create(1) - lists = ListFactory.create(1, { - title: 'First List' - }) - TaskFactory.truncate() - }) + prepareLists((newLists) => (lists = newLists)) it('Should create a new list', () => { cy.visit('/') @@ -29,7 +15,7 @@ describe('Lists', () => { .contains('New list') .click() cy.url() - .should('contain', '/namespaces/1/list') + .should('contain', '/lists/new/1') cy.get('.card-header-title') .contains('New list') cy.get('input.input') @@ -56,7 +42,7 @@ describe('Lists', () => { }) it('Should rename the list in all places', () => { - const tasks = TaskFactory.create(5, { + TaskFactory.create(5, { id: '{increment}', list_id: 1, }) @@ -112,429 +98,4 @@ describe('Lists', () => { cy.location('pathname') .should('equal', '/') }) - - describe('List View', () => { - it('Should be an empty list', () => { - cy.visit('/lists/1') - cy.url() - .should('contain', '/lists/1/list') - cy.get('.list-title h1') - .should('contain', 'First List') - cy.get('.list-title .dropdown') - .should('exist') - cy.get('p') - .contains('This list is currently empty.') - .should('exist') - }) - - it('Should navigate to the task when the title is clicked', () => { - const tasks = TaskFactory.create(5, { - id: '{increment}', - list_id: 1, - }) - cy.visit('/lists/1/list') - - cy.get('.tasks .task .tasktext') - .contains(tasks[0].title) - .first() - .click() - - cy.url() - .should('contain', `/tasks/${tasks[0].id}`) - }) - - it('Should not see any elements for a list which is shared read only', () => { - UserFactory.create(2) - UserListFactory.create(1, { - list_id: 2, - user_id: 1, - right: 0, - }) - const lists = ListFactory.create(2, { - owner_id: '{increment}', - namespace_id: '{increment}', - }) - cy.visit(`/lists/${lists[1].id}/`) - - cy.get('.list-title a.icon') - .should('not.exist') - cy.get('input.input[placeholder="Add a new task..."') - .should('not.exist') - }) - - it('Should only show the color of a list in the navigation and not in the list view', () => { - const lists = ListFactory.create(1, { - hex_color: '00db60', - }) - TaskFactory.create(10, { - list_id: lists[0].id, - }) - cy.visit(`/lists/${lists[0].id}/`) - - cy.get('.menu-list li .list-menu-link .color-bubble') - .should('have.css', 'background-color', 'rgb(0, 219, 96)') - cy.get('.tasks-container .tasks .color-bubble') - .should('not.exist') - }) - - it('Should paginate for > 50 tasks', () => { - const tasks = TaskFactory.create(100, { - id: '{increment}', - title: i => `task${i}`, - list_id: 1, - }) - cy.visit('/lists/1/list') - - cy.get('.tasks-container .tasks') - .should('contain', tasks[99].title) - - cy.get('.card-content .pagination .pagination-link') - .contains('2') - .click() - - cy.url() - .should('contain', '?page=2') - cy.get('.tasks-container .tasks') - .should('contain', tasks[1].title) - cy.get('.tasks-container .tasks') - .should('not.contain', tasks[99].title) - }) - }) - - describe('Table View', () => { - it('Should show a table with tasks', () => { - const tasks = TaskFactory.create(1) - cy.visit('/lists/1/table') - - cy.get('.table-view table.table') - .should('exist') - cy.get('.table-view table.table') - .should('contain', tasks[0].title) - }) - - it('Should have working column switches', () => { - TaskFactory.create(1) - cy.visit('/lists/1/table') - - cy.get('.table-view .filter-container .items .button') - .contains('Columns') - .click() - cy.get('.table-view .filter-container .card.columns-filter .card-content .fancycheckbox .check') - .contains('Priority') - .click() - cy.get('.table-view .filter-container .card.columns-filter .card-content .fancycheckbox .check') - .contains('Done') - .click() - - cy.get('.table-view table.table th') - .contains('Priority') - .should('exist') - cy.get('.table-view table.table th') - .contains('Done') - .should('not.exist') - }) - - it('Should navigate to the task when the title is clicked', () => { - const tasks = TaskFactory.create(5, { - id: '{increment}', - list_id: 1, - }) - cy.visit('/lists/1/table') - - cy.get('.table-view table.table') - .contains(tasks[0].title) - .click() - - cy.url() - .should('contain', `/tasks/${tasks[0].id}`) - }) - }) - - describe('Gantt View', () => { - it('Hides tasks with no dates', () => { - const tasks = TaskFactory.create(1) - cy.visit('/lists/1/gantt') - - cy.get('.gantt-chart-container .gantt-chart .tasks') - .should('not.contain', tasks[0].title) - }) - - 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(nextMonth, 'MMMM')) - }) - - it('Shows tasks with dates', () => { - const now = new Date() - const tasks = TaskFactory.create(1, { - start_date: formatISO(now), - end_date: formatISO(now.setDate(now.getDate() + 4)) - }) - cy.visit('/lists/1/gantt') - - cy.get('.gantt-chart-container .gantt-chart .tasks') - .should('not.be.empty') - cy.get('.gantt-chart-container .gantt-chart .tasks') - .should('contain', tasks[0].title) - }) - - it('Shows tasks with no dates after enabling them', () => { - TaskFactory.create(1, { - start_date: null, - end_date: null, - }) - cy.visit('/lists/1/gantt') - - cy.get('.gantt-chart-container .gantt-options .fancycheckbox') - .contains('Show tasks which don\'t have dates set') - .click() - - cy.get('.gantt-chart-container .gantt-chart .tasks') - .should('not.be.empty') - cy.get('.gantt-chart-container .gantt-chart .tasks .task.nodate') - .should('exist') - }) - - it('Drags a task around', () => { - const now = new Date() - TaskFactory.create(1, { - start_date: formatISO(now), - end_date: formatISO(now.setDate(now.getDate() + 4)) - }) - cy.visit('/lists/1/gantt') - - cy.get('.gantt-chart-container .gantt-chart .tasks .task') - .first() - .trigger('mousedown', {which: 1}) - .trigger('mousemove', {clientX: 500, clientY: 0}) - .trigger('mouseup', {force: true}) - }) - }) - - describe('Kanban', () => { - let buckets - - beforeEach(() => { - buckets = BucketFactory.create(2) - }) - - it('Shows all buckets with their tasks', () => { - const data = TaskFactory.create(10, { - list_id: 1, - bucket_id: 1, - }) - cy.visit('/lists/1/kanban') - - cy.get('.kanban .bucket .title') - .contains(buckets[0].title) - .should('exist') - cy.get('.kanban .bucket .title') - .contains(buckets[1].title) - .should('exist') - cy.get('.kanban .bucket') - .first() - .should('contain', data[0].title) - }) - - it('Can add a new task to a bucket', () => { - const data = TaskFactory.create(2, { - list_id: 1, - bucket_id: 1, - }) - cy.visit('/lists/1/kanban') - - cy.get('.kanban .bucket') - .contains(buckets[0].title) - .get('.bucket-footer .button') - .contains('Add another task') - .click() - cy.get('.kanban .bucket') - .contains(buckets[0].title) - .get('.bucket-footer .field .control input.input') - .type('New Task{enter}') - - cy.get('.kanban .bucket') - .first() - .should('contain', 'New Task') - }) - - it('Can create a new bucket', () => { - cy.visit('/lists/1/kanban') - - cy.get('.kanban .bucket.new-bucket .button') - .click() - cy.get('.kanban .bucket.new-bucket input.input') - .type('New Bucket{enter}') - - cy.wait(1000) // Wait for the request to finish - cy.get('.kanban .bucket .title') - .contains('New Bucket') - .should('exist') - }) - - it('Can set a bucket limit', () => { - cy.visit('/lists/1/kanban') - - cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-trigger') - .first() - .click() - cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item') - .contains('Limit: Not Set') - .click() - cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item .field input.input') - .first() - .type(3) - cy.get('[data-cy="setBucketLimit"]') - .first() - .click() - - cy.get('.kanban .bucket .bucket-header span.limit') - .contains('0/3') - .should('exist') - }) - - it('Can rename a bucket', () => { - cy.visit('/lists/1/kanban') - - cy.get('.kanban .bucket .bucket-header .title') - .first() - .type('{selectall}New Bucket Title{enter}') - cy.get('.kanban .bucket .bucket-header .title') - .first() - .should('contain', 'New Bucket Title') - }) - - it('Can delete a bucket', () => { - cy.visit('/lists/1/kanban') - - cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-trigger') - .first() - .click() - cy.get('.kanban .bucket .bucket-header .dropdown.options .dropdown-menu .dropdown-item') - .contains('Delete') - .click() - cy.get('.modal-mask .modal-container .modal-content .header') - .should('contain', 'Delete the bucket') - cy.get('.modal-mask .modal-container .modal-content .actions .button') - .contains('Do it!') - .click() - - cy.get('.kanban .bucket .title') - .contains(buckets[0].title) - .should('not.exist') - cy.get('.kanban .bucket .title') - .contains(buckets[1].title) - .should('exist') - }) - - it('Can drag tasks around', () => { - const tasks = TaskFactory.create(2, { - list_id: 1, - bucket_id: 1, - }) - cy.visit('/lists/1/kanban') - - cy.get('.kanban .bucket .tasks .task') - .contains(tasks[0].title) - .first() - .drag('.kanban .bucket:nth-child(2) .tasks .dropper') - - cy.get('.kanban .bucket:nth-child(2) .tasks') - .should('contain', tasks[0].title) - cy.get('.kanban .bucket:nth-child(1) .tasks') - .should('not.contain', tasks[0].title) - }) - - it('Should navigate to the task when the task card is clicked', () => { - const tasks = TaskFactory.create(5, { - id: '{increment}', - list_id: 1, - bucket_id: 1, - }) - cy.visit('/lists/1/kanban') - - cy.getSettled('.kanban .bucket .tasks .task') - .contains(tasks[0].title) - .should('be.visible') - .click() - - cy.url() - .should('contain', `/tasks/${tasks[0].id}`) - }) - - it('Should remove a task from the kanban board when moving it to another list', () => { - const lists = ListFactory.create(2) - BucketFactory.create(2, { - list_id: '{increment}', - }) - const tasks = TaskFactory.create(5, { - id: '{increment}', - list_id: 1, - bucket_id: 1, - }) - const task = tasks[0] - cy.visit('/lists/1/kanban') - - cy.getSettled('.kanban .bucket .tasks .task') - .contains(task.title) - .should('be.visible') - .click() - - cy.get('.task-view .action-buttons .button') - .contains('Move task') - .click() - cy.get('.task-view .content.details .field .multiselect.control .input-wrapper input') - .type(`${lists[1].title}{enter}`) - // The requests happen with a 200ms timeout. Because of that, the results are not yet there when cypress - // presses enter and we can't simulate pressing on enter to select the item. - cy.get('.task-view .content.details .field .multiselect.control .search-results') - .children() - .first() - .click() - - cy.get('.global-notification', { timeout: 1000 }) - .should('contain', 'Success') - cy.go('back') - cy.get('.kanban .bucket') - .should('not.contain', task.title) - }) - }) - - describe('List history', () => { - it('should show a list history on the home page', () => { - const lists = ListFactory.create(6) - - cy.visit('/') - cy.get('h3') - .contains('Last viewed') - .should('not.exist') - - cy.visit(`/lists/${lists[0].id}`) - cy.visit(`/lists/${lists[1].id}`) - cy.visit(`/lists/${lists[2].id}`) - cy.visit(`/lists/${lists[3].id}`) - cy.visit(`/lists/${lists[4].id}`) - cy.visit(`/lists/${lists[5].id}`) - - cy.visit('/') - cy.get('h3') - .contains('Last viewed') - .should('exist') - cy.get('.list-cards-wrapper-2-rows') - .should('not.contain', lists[0].title) - .should('contain', lists[1].title) - .should('contain', lists[2].title) - .should('contain', lists[3].title) - .should('contain', lists[4].title) - .should('contain', lists[5].title) - }) - }) }) diff --git a/cypress/integration/list/prepareLists.js b/cypress/integration/list/prepareLists.js new file mode 100644 index 000000000..afef6ba4f --- /dev/null +++ b/cypress/integration/list/prepareLists.js @@ -0,0 +1,16 @@ +import {ListFactory} from '../../factories/list' +import {UserFactory} from '../../factories/user' +import {NamespaceFactory} from '../../factories/namespace' +import {TaskFactory} from '../../factories/task' + +export function prepareLists(setLists = () => {}) { + beforeEach(() => { + UserFactory.create(1) + NamespaceFactory.create(1) + const lists = ListFactory.create(1, { + title: 'First List' + }) + setLists(lists) + TaskFactory.truncate() + }) +} \ No newline at end of file diff --git a/cypress/integration/task/task.spec.js b/cypress/integration/task/task.spec.js index 1b85e9921..62343c91e 100644 --- a/cypress/integration/task/task.spec.js +++ b/cypress/integration/task/task.spec.js @@ -116,6 +116,7 @@ describe('Task', () => { .should('be.visible') .should('contain', 'Done') cy.get('.task-view .action-buttons p.created') + .scrollIntoView() .should('be.visible') .should('contain', 'Done') }) @@ -372,13 +373,13 @@ describe('Task', () => { cy.visit(`/tasks/${tasks[0].id}`) - cy.get('.task-view .details.labels-list .multiselect .input-wrapper') + cy.getSettled('.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') + cy.getSettled('.task-view .details.labels-list .multiselect .input-wrapper') .children() .first() - .get('a.delete') + .get('[data-cy="taskDetail.removeLabel"]') .click() cy.get('.global-notification') diff --git a/package.json b/package.json index 2063c472a..590203d1a 100644 --- a/package.json +++ b/package.json @@ -129,7 +129,7 @@ "parser": "vue-eslint-parser", "parserOptions": { "parser": "@typescript-eslint/parser", - "ecmaVersion": 2021 + "ecmaVersion": 2022 }, "ignorePatterns": [ "*.test.*", diff --git a/src/components/home/contentAuth.vue b/src/components/home/contentAuth.vue index 06ab48e2a..25fd01e73 100644 --- a/src/components/home/contentAuth.vue +++ b/src/components/home/contentAuth.vue @@ -1,8 +1,12 @@