238 lines
6.4 KiB
TypeScript
238 lines
6.4 KiB
TypeScript
const authenticatedUser = {
|
|
id: 7,
|
|
email: 'user@example.com',
|
|
}
|
|
|
|
const browserToday = '2026-08-15'
|
|
|
|
function interceptDashboardRequests(): void {
|
|
cy.intercept('GET', '**/api/me', {
|
|
statusCode: 200,
|
|
body: { user: authenticatedUser },
|
|
}).as('me')
|
|
cy.intercept('GET', '**/api/sets', {
|
|
statusCode: 200,
|
|
body: { sets: [] },
|
|
}).as('sets')
|
|
cy.intercept('GET', '**/api/schedules', {
|
|
statusCode: 200,
|
|
body: { schedules: [] },
|
|
}).as('schedules')
|
|
}
|
|
|
|
describe("today's assignments", () => {
|
|
beforeEach(() => {
|
|
cy.clock(new Date(2026, 7, 15, 0, 30).getTime())
|
|
interceptDashboardRequests()
|
|
})
|
|
|
|
it('uses the browser date and links every assignment to its schedule', () => {
|
|
cy.intercept('GET', `**/api/assignments?date=${browserToday}`, (request) => {
|
|
expect(request.headers.accept).to.equal('application/json')
|
|
request.reply({
|
|
statusCode: 200,
|
|
body: {
|
|
date: browserToday,
|
|
assignments: [
|
|
{
|
|
id: 12,
|
|
scheduledDate: '2026-08-13',
|
|
schedule: {
|
|
id: 73,
|
|
set: { name: 'Bible' },
|
|
},
|
|
element: {
|
|
name: 'Chapter 1',
|
|
kind: 'Chapter_sections-v2',
|
|
path: ['Genesis', 'Creation', 'Chapter 1'],
|
|
},
|
|
},
|
|
{
|
|
id: 13,
|
|
scheduledDate: browserToday,
|
|
schedule: {
|
|
id: 81,
|
|
set: { name: 'Course' },
|
|
},
|
|
element: {
|
|
name: 'Introduction',
|
|
kind: 'lesson',
|
|
path: ['Introduction'],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
})
|
|
}).as('todayAssignments')
|
|
|
|
cy.visit('/dashboard')
|
|
cy.wait('@me')
|
|
cy.wait('@todayAssignments')
|
|
|
|
cy.get('#today-heading').should('have.text', 'Today')
|
|
cy.get('[data-today-date]').should(
|
|
'have.attr',
|
|
'data-today-date',
|
|
browserToday,
|
|
)
|
|
cy.get('ul[aria-label="Today\'s assignments"] > li').should(
|
|
'have.length',
|
|
2,
|
|
)
|
|
cy.get('[data-today-assignment]')
|
|
.first()
|
|
.should('have.attr', 'data-today-assignment', '12')
|
|
cy.get('[data-today-assignment="12"] .today-assignment__overdue').should(
|
|
'have.text',
|
|
'Overdue · Due Aug 13, 2026',
|
|
)
|
|
cy.get('[data-today-assignment="13"] .today-assignment__overdue').should(
|
|
'not.exist',
|
|
)
|
|
cy.contains('a', 'Genesis / Creation / Chapter 1')
|
|
.should('contain.text', 'Bible')
|
|
.and('have.attr', 'href', '/schedules/73')
|
|
cy.contains('a', 'Introduction')
|
|
.should('contain.text', 'Course')
|
|
.and('have.attr', 'href', '/schedules/81')
|
|
cy.get('.today-assignment__kind')
|
|
.first()
|
|
.should('have.text', 'Chapter_sections-v2')
|
|
.and('have.css', 'text-transform', 'none')
|
|
})
|
|
|
|
it('shows loading and empty states', () => {
|
|
cy.intercept('GET', `**/api/assignments?date=${browserToday}`, {
|
|
delay: 2500,
|
|
statusCode: 200,
|
|
body: {
|
|
date: browserToday,
|
|
assignments: [],
|
|
},
|
|
}).as('todayAssignments')
|
|
|
|
cy.visit('/dashboard')
|
|
cy.wait('@me')
|
|
cy.get('.today-assignments [role="status"]').should(
|
|
'contain.text',
|
|
"Loading today's assignments...",
|
|
)
|
|
cy.wait('@todayAssignments')
|
|
|
|
cy.get('.today-assignments [role="status"]').should(
|
|
'contain.text',
|
|
'Nothing is due today.',
|
|
)
|
|
})
|
|
|
|
it('completes an assignment and keeps failures retryable', () => {
|
|
cy.intercept('GET', `**/api/assignments?date=${browserToday}`, {
|
|
statusCode: 200,
|
|
body: {
|
|
date: browserToday,
|
|
assignments: [
|
|
{
|
|
id: 12,
|
|
scheduledDate: browserToday,
|
|
schedule: {
|
|
id: 73,
|
|
set: { name: 'Bible' },
|
|
},
|
|
element: {
|
|
name: 'Chapter 1',
|
|
kind: 'chapter',
|
|
path: ['Genesis', 'Chapter 1'],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
}).as('todayAssignments')
|
|
let requestCount = 0
|
|
cy.intercept('PATCH', '**/api/assignments/12', (request) => {
|
|
requestCount += 1
|
|
request.alias = `completion${requestCount}`
|
|
expect(request.body).to.deep.equal({ completed: true })
|
|
|
|
if (requestCount === 1) {
|
|
request.reply({ delay: 400, statusCode: 500 })
|
|
return
|
|
}
|
|
|
|
request.reply({
|
|
delay: 400,
|
|
statusCode: 200,
|
|
body: {
|
|
assignment: {
|
|
id: 12,
|
|
completedAt: '2026-08-15T12:30:00+00:00',
|
|
},
|
|
},
|
|
})
|
|
})
|
|
|
|
cy.visit('/dashboard')
|
|
cy.wait('@me')
|
|
cy.wait('@todayAssignments')
|
|
|
|
cy.get('[data-today-assignment="12"]').within(() => {
|
|
cy.contains('button', 'Mark complete').click()
|
|
cy.contains('button', 'Completing...').should('be.disabled')
|
|
})
|
|
cy.wait('@completion1')
|
|
cy.get('[data-today-assignment="12"]')
|
|
.should('contain.text', "We couldn't update this assignment.")
|
|
.within(() => {
|
|
cy.contains('button', 'Mark complete').click()
|
|
cy.contains('button', 'Completing...').should('be.disabled')
|
|
})
|
|
cy.wait('@completion2')
|
|
|
|
cy.get('[data-today-assignment="12"]').should('not.exist')
|
|
cy.get('.today-assignments [role="status"]').should(
|
|
'contain.text',
|
|
'Nothing is due today.',
|
|
)
|
|
})
|
|
|
|
it('retries independently after the request fails', () => {
|
|
let requestCount = 0
|
|
cy.intercept(
|
|
'GET',
|
|
`**/api/assignments?date=${browserToday}`,
|
|
(request) => {
|
|
requestCount += 1
|
|
request.alias = `todayAssignments${requestCount}`
|
|
|
|
if (requestCount === 1) {
|
|
request.reply({ statusCode: 500 })
|
|
return
|
|
}
|
|
|
|
request.reply({
|
|
statusCode: 200,
|
|
body: {
|
|
date: browserToday,
|
|
assignments: [],
|
|
},
|
|
})
|
|
},
|
|
)
|
|
|
|
cy.visit('/dashboard')
|
|
cy.wait('@me')
|
|
cy.wait('@todayAssignments1')
|
|
|
|
cy.get('.today-assignments [role="alert"]')
|
|
.should('contain.text', "We couldn't load today's assignments.")
|
|
.within(() => {
|
|
cy.contains('button', 'Try again').click()
|
|
})
|
|
cy.get('#schedules-heading').should('have.text', 'Your schedules')
|
|
cy.wait('@todayAssignments2')
|
|
|
|
cy.get('.today-assignments [role="status"]').should(
|
|
'contain.text',
|
|
'Nothing is due today.',
|
|
)
|
|
})
|
|
})
|