80 lines
3.0 KiB
TypeScript
80 lines
3.0 KiB
TypeScript
import {test, expect} from '../../support/fixtures'
|
|
import {ProjectFactory} from '../../factories/project'
|
|
import {TaskFactory} from '../../factories/task'
|
|
|
|
test.describe('Task recurrence', () => {
|
|
test.beforeEach(async () => {
|
|
await ProjectFactory.create(1, {id: 1})
|
|
})
|
|
|
|
test('sets repeat-every-day via preset button', async ({authenticatedPage: page}) => {
|
|
const [task] = await TaskFactory.create(1, {
|
|
id: 1,
|
|
project_id: 1,
|
|
due_date: new Date(Date.now() + 86_400_000).toISOString(),
|
|
}, false)
|
|
await page.goto(`/tasks/${task.id}`)
|
|
|
|
// Reveal the RepeatAfter component (hidden until the user activates it)
|
|
await page.getByRole('button', {name: 'Set Repeating Interval'}).click()
|
|
|
|
const save = page.waitForResponse(r =>
|
|
r.url().includes(`/tasks/${task.id}`) && r.request().method() === 'POST',
|
|
)
|
|
await page.getByRole('button', {name: 'Every Day'}).click()
|
|
const r = await save
|
|
const body = r.request().postDataJSON()
|
|
expect(body.repeat_after).toBe(86400)
|
|
})
|
|
|
|
test('completing a recurring task reopens with advanced due date', async ({
|
|
authenticatedPage: page, apiContext, userToken,
|
|
}) => {
|
|
const originalDue = new Date(Date.now() + 86_400_000)
|
|
const [task] = await TaskFactory.create(1, {
|
|
id: 1,
|
|
project_id: 1,
|
|
due_date: originalDue.toISOString(),
|
|
repeat_after: 86400,
|
|
}, false)
|
|
|
|
await page.goto(`/tasks/${task.id}`)
|
|
|
|
const completed = page.waitForResponse(r =>
|
|
r.url().includes(`/tasks/${task.id}`) && r.request().method() === 'POST',
|
|
)
|
|
await page.locator('.task-view .action-buttons .button').filter({hasText: 'Mark task done!'}).click()
|
|
await completed
|
|
|
|
// Fetch fresh state from the API to verify the backend regenerated the task.
|
|
const resp = await apiContext.get(`tasks/${task.id}`, {
|
|
headers: {Authorization: `Bearer ${userToken}`},
|
|
})
|
|
expect(resp.ok()).toBe(true)
|
|
const refreshed = await resp.json()
|
|
expect(refreshed.done).toBe(false)
|
|
const newDue = new Date(refreshed.due_date).getTime()
|
|
// addRepeatIntervalToTime: when the original due date is still in the
|
|
// future, the backend advances it by exactly one interval (86400s here).
|
|
// Tolerance of <5s absorbs sub-second timestamp round-tripping between
|
|
// the JS Date → ISO string → backend time.Time → JSON response path.
|
|
expect(newDue - originalDue.getTime()).toBeCloseTo(86_400_000, -4)
|
|
})
|
|
|
|
test('monthly repeat mode hides the amount field', async ({authenticatedPage: page}) => {
|
|
const [task] = await TaskFactory.create(1, {id: 1, project_id: 1}, false)
|
|
await page.goto(`/tasks/${task.id}`)
|
|
|
|
// Reveal the RepeatAfter component (hidden until the user activates it)
|
|
await page.getByRole('button', {name: 'Set Repeating Interval'}).click()
|
|
|
|
await expect(page.locator('#repeatMode')).toBeVisible()
|
|
// Amount input is visible in the default repeat mode
|
|
await expect(page.locator('input[placeholder*="amount" i]')).toHaveCount(1)
|
|
|
|
await page.locator('#repeatMode').selectOption({label: 'Monthly'})
|
|
|
|
await expect(page.locator('input[placeholder*="amount" i]')).toHaveCount(0)
|
|
})
|
|
})
|