From efed128f0325ae18342a0dd64913dc51b5ccec91 Mon Sep 17 00:00:00 2001 From: konrad Date: Wed, 1 Jun 2022 16:59:59 +0000 Subject: [PATCH] fix: rely on api to properly sort tasks on home page (#1997) This PR changes the behaviour of how tasks are sorted. Before, the frontend would sort tasks but this resulted in some cases where tasks were not sorted properly. Most of this is test code to reliably reproduce the problem and make fixing it easier. The actual bug was in Vikunja's api, therefore I've removed all sorting of tasks in the frontend and ensured the api properly sorts tasks. Fixes https://github.com/go-vikunja/frontend/issues/54 Depends on https://kolaente.dev/vikunja/api/pulls/1177 Co-authored-by: kolaente Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/1997 Reviewed-by: Dominik Pschenitschni --- .../integration/list/list-view-list.spec.js | 10 ++ cypress/integration/task/overview.spec.js | 130 ++++++++++++++++++ cypress/integration/task/task.spec.js | 4 +- cypress/support/updateUserSettings.js | 26 ++++ src/views/tasks/ShowTasks.vue | 29 +--- 5 files changed, 171 insertions(+), 28 deletions(-) create mode 100644 cypress/integration/task/overview.spec.js create mode 100644 cypress/support/updateUserSettings.js diff --git a/cypress/integration/list/list-view-list.spec.js b/cypress/integration/list/list-view-list.spec.js index e1a4a0f691..631827d783 100644 --- a/cypress/integration/list/list-view-list.spec.js +++ b/cypress/integration/list/list-view-list.spec.js @@ -21,6 +21,16 @@ describe('List View List', () => { .contains('This list is currently empty.') .should('exist') }) + + it('Should create a new task', () => { + const newTaskTitle = 'New task' + + cy.visit('/lists/1') + cy.get('.task-add textarea') + .type(newTaskTitle+'{enter}') + cy.get('.tasks') + .should('contain.text', newTaskTitle) + }) it('Should navigate to the task when the title is clicked', () => { const tasks = TaskFactory.create(5, { diff --git a/cypress/integration/task/overview.spec.js b/cypress/integration/task/overview.spec.js new file mode 100644 index 0000000000..af3ca05b4a --- /dev/null +++ b/cypress/integration/task/overview.spec.js @@ -0,0 +1,130 @@ +import {ListFactory} from '../../factories/list' +import {seed} from '../../support/seed' +import {TaskFactory} from '../../factories/task' +import {formatISO} from 'date-fns' +import {UserFactory} from '../../factories/user' +import {NamespaceFactory} from '../../factories/namespace' +import {BucketFactory} from '../../factories/bucket' +import {updateUserSettings} from '../../support/updateUserSettings' + +import '../../support/authenticateUser' + +function seedTasks(numberOfTasks = 100, startDueDate = new Date()) { + UserFactory.create(1) + NamespaceFactory.create(1) + const list = ListFactory.create()[0] + BucketFactory.create(1, { + list_id: list.id, + }) + const tasks = [] + let dueDate = startDueDate + for (let i = 0; i < numberOfTasks; i++) { + const now = new Date() + dueDate = (new Date(dueDate.valueOf())).setDate((new Date(dueDate.valueOf())).getDate() + 2) + tasks.push({ + id: i + 1, + list_id: list.id, + done: false, + created_by_id: 1, + title: 'Test Task ' + i, + index: i + 1, + due_date: formatISO(dueDate), + created: formatISO(now), + updated: formatISO(now), + }) + } + seed(TaskFactory.table, tasks) + return {tasks, list} +} + +describe('Home Page Task Overview', () => { + it('Should show tasks with a near due date first on the home page overview', () => { + const {tasks} = seedTasks() + + cy.visit('/') + cy.get('[data-cy="showTasks"] .card .task') + .each(([task], index) => { + expect(task.innerText).to.contain(tasks[index].title) + }) + }) + + it('Should show overdue tasks first, then show other tasks', () => { + const oldDate = (new Date()).setDate((new Date()).getDate() - 14) + const {tasks} = seedTasks(100, oldDate) + + cy.visit('/') + cy.get('[data-cy="showTasks"] .card .task') + .each(([task], index) => { + expect(task.innerText).to.contain(tasks[index].title) + }) + }) + + it('Should show a new task with a very soon due date at the top', () => { + const {tasks} = seedTasks() + const newTaskTitle = 'New Task' + + cy.visit('/') + + TaskFactory.create(1, { + id: 999, + title: newTaskTitle, + due_date: formatISO(new Date()), + }, false) + + cy.visit(`/lists/${tasks[0].list_id}/list`) + cy.get('.tasks .task') + .first() + .should('contain.text', newTaskTitle) + cy.visit('/') + cy.get('[data-cy="showTasks"] .card .task') + .first() + .should('contain.text', newTaskTitle) + }) + + it('Should not show a new task without a date at the bottom when there are > 50 tasks', () => { + // We're not using the api here to create the task in order to verify the flow + const {tasks} = seedTasks() + const newTaskTitle = 'New Task' + + cy.visit('/') + + cy.visit(`/lists/${tasks[0].list_id}/list`) + cy.get('.task-add textarea') + .type(newTaskTitle+'{enter}') + cy.visit('/') + cy.get('[data-cy="showTasks"] .card .task') + .last() + .should('not.contain.text', newTaskTitle) + }) + + it('Should show a new task without a date at the bottom when there are < 50 tasks', () => { + seedTasks(40) + const newTaskTitle = 'New Task' + TaskFactory.create(1, { + id: 999, + title: newTaskTitle, + }, false) + + cy.visit('/') + cy.get('[data-cy="showTasks"] .card .task') + .last() + .should('contain.text', newTaskTitle) + }) + + it('Should show a task without a due date added via default list at the bottom', () => { + const {list} = seedTasks(40) + updateUserSettings({ + default_list_id: list.id, + }) + + const newTaskTitle = 'New Task' + cy.visit('/') + + cy.get('.add-task-textarea') + .type(`${newTaskTitle}{enter}`) + + cy.get('[data-cy="showTasks"] .card .task') + .last() + .should('contain.text', newTaskTitle) + }) +}) diff --git a/cypress/integration/task/task.spec.js b/cypress/integration/task/task.spec.js index 29ade1d240..c482c7a788 100644 --- a/cypress/integration/task/task.spec.js +++ b/cypress/integration/task/task.spec.js @@ -6,13 +6,13 @@ import {TaskCommentFactory} from '../../factories/task_comment' import {UserFactory} from '../../factories/user' import {NamespaceFactory} from '../../factories/namespace' import {UserListFactory} from '../../factories/users_list' - -import '../../support/authenticateUser' import {TaskAssigneeFactory} from '../../factories/task_assignee' import {LabelFactory} from '../../factories/labels' import {LabelTaskFactory} from '../../factories/label_task' import {BucketFactory} from '../../factories/bucket' +import '../../support/authenticateUser' + describe('Task', () => { let namespaces let lists diff --git a/cypress/support/updateUserSettings.js b/cypress/support/updateUserSettings.js new file mode 100644 index 0000000000..be54a752c2 --- /dev/null +++ b/cypress/support/updateUserSettings.js @@ -0,0 +1,26 @@ + +export function updateUserSettings(settings) { + const token = `Bearer ${window.localStorage.getItem('token')}` + + return cy.request({ + method: 'GET', + url: `${Cypress.env('API_URL')}/user`, + headers: { + 'Authorization': token, + }, + }) + .its('body') + .then(oldSettings => { + return cy.request({ + method: 'POST', + url: `${Cypress.env('API_URL')}/user/settings/general`, + headers: { + 'Authorization': token, + }, + body: { + ...oldSettings, + ...settings, + }, + }) + }) +} \ No newline at end of file diff --git a/src/views/tasks/ShowTasks.vue b/src/views/tasks/ShowTasks.vue index dd21069db2..914c6080d6 100644 --- a/src/views/tasks/ShowTasks.vue +++ b/src/views/tasks/ShowTasks.vue @@ -1,5 +1,5 @@