fix: list specs
This commit is contained in:
parent
5937f01cc5
commit
e78d47fdcf
13 changed files with 481 additions and 449 deletions
|
@ -7,5 +7,9 @@
|
||||||
"video": false,
|
"video": false,
|
||||||
"retries": {
|
"retries": {
|
||||||
"runMode": 2
|
"runMode": 2
|
||||||
}
|
},
|
||||||
|
"testFiles": [
|
||||||
|
"list/list.spec.js",
|
||||||
|
"**/*.spec.js"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
33
cypress/integration/list/list-history.spec.js
Normal file
33
cypress/integration/list/list-history.spec.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import {ListFactory} from '../../factories/list'
|
||||||
|
|
||||||
|
import '../../support/authenticateUser'
|
||||||
|
|
||||||
|
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)
|
||||||
|
})
|
||||||
|
})
|
73
cypress/integration/list/list-view-gantt.spec.js
Normal file
73
cypress/integration/list/list-view-gantt.spec.js
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import {formatISO, format} from 'date-fns'
|
||||||
|
import {TaskFactory} from '../../factories/task'
|
||||||
|
|
||||||
|
import '../../support/authenticateUser'
|
||||||
|
|
||||||
|
describe('List View Gantt', () => {
|
||||||
|
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})
|
||||||
|
})
|
||||||
|
})
|
196
cypress/integration/list/list-view-kanban.spec.js
Normal file
196
cypress/integration/list/list-view-kanban.spec.js
Normal file
|
@ -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.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}`, { 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)
|
||||||
|
})
|
||||||
|
})
|
97
cypress/integration/list/list-view-list.spec.js
Normal file
97
cypress/integration/list/list-view-list.spec.js
Normal file
|
@ -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)
|
||||||
|
})
|
||||||
|
})
|
52
cypress/integration/list/list-view-table.spec.js
Normal file
52
cypress/integration/list/list-view-table.spec.js
Normal file
|
@ -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}`)
|
||||||
|
})
|
||||||
|
})
|
|
@ -1,25 +1,11 @@
|
||||||
import {formatISO, format} from 'date-fns'
|
|
||||||
|
|
||||||
import {TaskFactory} from '../../factories/task'
|
import {TaskFactory} from '../../factories/task'
|
||||||
import {ListFactory} from '../../factories/list'
|
import {prepareLists} from './prepareLists'
|
||||||
import {UserListFactory} from '../../factories/users_list'
|
|
||||||
import {UserFactory} from '../../factories/user'
|
|
||||||
import {NamespaceFactory} from '../../factories/namespace'
|
|
||||||
import {BucketFactory} from '../../factories/bucket'
|
|
||||||
|
|
||||||
import '../../support/authenticateUser'
|
import '../../support/authenticateUser'
|
||||||
|
|
||||||
describe('Lists', () => {
|
describe('Lists', () => {
|
||||||
let lists
|
let lists
|
||||||
|
prepareLists((newLists) => (lists = newLists))
|
||||||
beforeEach(() => {
|
|
||||||
UserFactory.create(1)
|
|
||||||
NamespaceFactory.create(1)
|
|
||||||
lists = ListFactory.create(1, {
|
|
||||||
title: 'First List'
|
|
||||||
})
|
|
||||||
TaskFactory.truncate()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Should create a new list', () => {
|
it('Should create a new list', () => {
|
||||||
cy.visit('/')
|
cy.visit('/')
|
||||||
|
@ -56,7 +42,7 @@ describe('Lists', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should rename the list in all places', () => {
|
it('Should rename the list in all places', () => {
|
||||||
const tasks = TaskFactory.create(5, {
|
TaskFactory.create(5, {
|
||||||
id: '{increment}',
|
id: '{increment}',
|
||||||
list_id: 1,
|
list_id: 1,
|
||||||
})
|
})
|
||||||
|
@ -112,429 +98,4 @@ describe('Lists', () => {
|
||||||
cy.location('pathname')
|
cy.location('pathname')
|
||||||
.should('equal', '/')
|
.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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
16
cypress/integration/list/prepareLists.js
Normal file
16
cypress/integration/list/prepareLists.js
Normal file
|
@ -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()
|
||||||
|
})
|
||||||
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
.box,
|
.box,
|
||||||
.card,
|
.card,
|
||||||
.switch-view,
|
.switch-view,
|
||||||
.table-view .button,
|
.list-table .button,
|
||||||
.filter-container .button,
|
.filter-container .button,
|
||||||
.search .button {
|
.search .button {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ListWrapper>
|
<ListWrapper class="list-gantt">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="gantt-options p-4">
|
<div class="gantt-options p-4">
|
||||||
<fancycheckbox class="is-block" v-model="showTaskswithoutDates">
|
<fancycheckbox class="is-block" v-model="showTaskswithoutDates">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ListWrapper>
|
<ListWrapper class="list-kanban">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="filter-container" v-if="isSavedFilter">
|
<div class="filter-container" v-if="isSavedFilter">
|
||||||
<div class="items">
|
<div class="items">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ListWrapper>
|
<ListWrapper class="list-list">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div
|
<div
|
||||||
class="filter-container"
|
class="filter-container"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<ListWrapper>
|
<ListWrapper class="list-table">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="filter-container">
|
<div class="filter-container">
|
||||||
<div class="items">
|
<div class="items">
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #default>
|
<template #default>
|
||||||
<div :class="{'is-loading': loading}" class="table-view loader-container">
|
<div :class="{'is-loading': loading}" class="loader-container">
|
||||||
<card :padding="false" :has-content="false">
|
<card :padding="false" :has-content="false">
|
||||||
<div class="has-horizontal-overflow">
|
<div class="has-horizontal-overflow">
|
||||||
<table class="table has-actions is-hoverable is-fullwidth mb-0">
|
<table class="table has-actions is-hoverable is-fullwidth mb-0">
|
||||||
|
|
Loading…
Reference in a new issue