test set scheduling ui
This commit is contained in:
parent
b812a4b21b
commit
b7fb594c26
5 changed files with 262 additions and 0 deletions
|
|
@ -13,6 +13,10 @@ describe('email confirmation', () => {
|
|||
statusCode: 200,
|
||||
body: { sets: [] },
|
||||
})
|
||||
cy.intercept('GET', '**/api/schedules', {
|
||||
statusCode: 200,
|
||||
body: { schedules: [] },
|
||||
})
|
||||
})
|
||||
|
||||
it('chooses a password, confirms the account, and opens the dashboard', () => {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@ describe('guest authentication pages', () => {
|
|||
cy.location('search').should('include', 'redirect=/sets/41')
|
||||
})
|
||||
|
||||
it('redirects guests away from protected schedule routes', () => {
|
||||
cy.visit('/sets/41/schedules/new')
|
||||
cy.location('pathname').should('equal', '/login')
|
||||
|
||||
cy.visit('/schedules/73')
|
||||
cy.location('pathname').should('equal', '/login')
|
||||
})
|
||||
|
||||
it('shows the login form and links to signup', () => {
|
||||
cy.visit('/login')
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ describe('session authentication', () => {
|
|||
statusCode: 200,
|
||||
body: { sets: [] },
|
||||
})
|
||||
cy.intercept('GET', '**/api/schedules', {
|
||||
statusCode: 200,
|
||||
body: { schedules: [] },
|
||||
})
|
||||
})
|
||||
|
||||
it('restores an authenticated session on a protected route', () => {
|
||||
|
|
|
|||
242
frontend/website/cypress/e2e/set-scheduling.cy.ts
Normal file
242
frontend/website/cypress/e2e/set-scheduling.cy.ts
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
const authenticatedUser = {
|
||||
id: 7,
|
||||
email: 'user@example.com',
|
||||
}
|
||||
|
||||
const bibleLayout = {
|
||||
set: { id: 41, name: 'Bible' },
|
||||
elements: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Genesis',
|
||||
kind: 'book',
|
||||
children: [
|
||||
{
|
||||
id: 3,
|
||||
name: 'Creation',
|
||||
kind: 'portion',
|
||||
children: [
|
||||
{
|
||||
id: 4,
|
||||
name: 'Chapter 1',
|
||||
kind: 'chapter',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Exodus',
|
||||
kind: 'book',
|
||||
children: [
|
||||
{
|
||||
id: 5,
|
||||
name: 'Chapter 1',
|
||||
kind: 'chapter',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const scheduleDetail = {
|
||||
schedule: {
|
||||
id: 73,
|
||||
set: { id: 41, name: 'Bible' },
|
||||
elementKind: 'chapter',
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-12',
|
||||
assignmentCount: 2,
|
||||
days: [
|
||||
{
|
||||
date: '2026-08-10',
|
||||
assignments: [
|
||||
{
|
||||
element: {
|
||||
id: 4,
|
||||
name: 'Chapter 1',
|
||||
kind: 'chapter',
|
||||
path: ['Genesis', 'Creation', 'Chapter 1'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ date: '2026-08-11', assignments: [] },
|
||||
{
|
||||
date: '2026-08-12',
|
||||
assignments: [
|
||||
{
|
||||
element: {
|
||||
id: 5,
|
||||
name: 'Chapter 1',
|
||||
kind: 'chapter',
|
||||
path: ['Exodus', 'Chapter 1'],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
function interceptAuthenticatedUser(): void {
|
||||
cy.intercept('GET', '**/api/me', {
|
||||
statusCode: 200,
|
||||
body: { user: authenticatedUser },
|
||||
}).as('me')
|
||||
}
|
||||
|
||||
describe('set scheduling', () => {
|
||||
beforeEach(() => {
|
||||
interceptAuthenticatedUser()
|
||||
})
|
||||
|
||||
it('creates a schedule from a set and shows every day', () => {
|
||||
cy.intercept('GET', '**/api/sets/41', {
|
||||
statusCode: 200,
|
||||
body: bibleLayout,
|
||||
}).as('layout')
|
||||
cy.intercept('POST', '**/api/schedules', (request) => {
|
||||
expect(request.headers.accept).to.equal('application/json')
|
||||
expect(request.body).to.deep.equal({
|
||||
setId: 41,
|
||||
elementKind: 'chapter',
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-12',
|
||||
})
|
||||
request.reply({ statusCode: 201, body: scheduleDetail })
|
||||
}).as('createSchedule')
|
||||
|
||||
cy.visit('/sets/41')
|
||||
cy.wait('@me')
|
||||
cy.wait('@layout')
|
||||
cy.contains('a', 'Schedule this set')
|
||||
.should('have.attr', 'href', '/sets/41/schedules/new')
|
||||
.click()
|
||||
|
||||
cy.location('pathname').should('equal', '/sets/41/schedules/new')
|
||||
cy.get('h1').should('have.text', 'Schedule Bible')
|
||||
cy.get('#schedule-level option').then(($options) => {
|
||||
expect([...$options].map((option) => option.textContent)).to.deep.equal([
|
||||
'Choose a level',
|
||||
'Book (2)',
|
||||
'Portion (1)',
|
||||
'Chapter (2)',
|
||||
])
|
||||
})
|
||||
cy.get('#schedule-level').select('chapter')
|
||||
cy.get('#schedule-start-date').type('2026-08-10')
|
||||
cy.get('#schedule-target-date').type('2026-08-12')
|
||||
cy.get('form').submit()
|
||||
cy.wait('@createSchedule')
|
||||
|
||||
cy.location('pathname').should('equal', '/schedules/73')
|
||||
cy.get('h1').should('have.text', 'Bible schedule')
|
||||
cy.get('[data-schedule-day]').should('have.length', 3)
|
||||
cy.get('[data-schedule-date="2026-08-10"]')
|
||||
.should('contain.text', 'Genesis / Creation / Chapter 1')
|
||||
.and('contain.text', 'Chapter')
|
||||
cy.get('[data-schedule-date="2026-08-11"]')
|
||||
.should('contain.text', 'Rest day')
|
||||
.and('not.contain.text', 'Chapter 1')
|
||||
cy.get('[data-schedule-date="2026-08-12"]').should(
|
||||
'contain.text',
|
||||
'Exodus / Chapter 1',
|
||||
)
|
||||
})
|
||||
|
||||
it('validates the schedule form before submitting', () => {
|
||||
cy.intercept('GET', '**/api/sets/41', {
|
||||
statusCode: 200,
|
||||
body: bibleLayout,
|
||||
}).as('layout')
|
||||
cy.intercept('POST', '**/api/schedules').as('createSchedule')
|
||||
|
||||
cy.visit('/sets/41/schedules/new')
|
||||
cy.wait('@me')
|
||||
cy.wait('@layout')
|
||||
cy.get('form').submit()
|
||||
|
||||
cy.get('#schedule-level-error')
|
||||
.should('have.text', 'Choose a level to schedule.')
|
||||
.and('be.visible')
|
||||
cy.get('#schedule-start-date-error')
|
||||
.should('have.text', 'Choose a start date.')
|
||||
.and('be.visible')
|
||||
cy.get('#schedule-target-date-error')
|
||||
.should('have.text', 'Choose a target date.')
|
||||
.and('be.visible')
|
||||
cy.get('@createSchedule.all').should('have.length', 0)
|
||||
|
||||
cy.get('#schedule-level').select('chapter')
|
||||
cy.get('#schedule-start-date').type('2026-08-12')
|
||||
cy.get('#schedule-target-date').type('2026-08-10')
|
||||
cy.get('form').submit()
|
||||
cy.get('#schedule-target-date-error').should(
|
||||
'have.text',
|
||||
'Target date cannot be before the start date.',
|
||||
)
|
||||
cy.get('@createSchedule.all').should('have.length', 0)
|
||||
})
|
||||
|
||||
it('loads a persisted schedule directly and handles missing schedules', () => {
|
||||
cy.intercept('GET', '**/api/schedules/73', {
|
||||
statusCode: 200,
|
||||
body: scheduleDetail,
|
||||
}).as('schedule')
|
||||
|
||||
cy.visit('/schedules/73')
|
||||
cy.wait('@me')
|
||||
cy.wait('@schedule')
|
||||
cy.get('h1').should('have.text', 'Bible schedule')
|
||||
cy.contains('2 chapters across 3 days').should('be.visible')
|
||||
|
||||
cy.intercept('GET', '**/api/schedules/74', {
|
||||
statusCode: 404,
|
||||
body: { error: 'schedule not found' },
|
||||
}).as('missingSchedule')
|
||||
cy.visit('/schedules/74')
|
||||
cy.wait('@missingSchedule')
|
||||
cy.get('h1').should('have.text', 'Schedule not found')
|
||||
})
|
||||
|
||||
it('lists the users schedules on the dashboard', () => {
|
||||
cy.intercept('GET', '**/api/sets', {
|
||||
statusCode: 200,
|
||||
body: { sets: [] },
|
||||
}).as('sets')
|
||||
cy.intercept('GET', '**/api/schedules', (request) => {
|
||||
expect(request.headers.accept).to.equal('application/json')
|
||||
request.reply({
|
||||
statusCode: 200,
|
||||
body: {
|
||||
schedules: [
|
||||
{
|
||||
id: 73,
|
||||
set: { id: 41, name: 'Bible' },
|
||||
elementKind: 'chapter',
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-12',
|
||||
assignmentCount: 2,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
}).as('schedules')
|
||||
|
||||
cy.visit('/dashboard')
|
||||
cy.wait('@me')
|
||||
cy.wait('@sets')
|
||||
cy.wait('@schedules')
|
||||
|
||||
cy.get('#schedules-heading').should('have.text', 'Your schedules')
|
||||
cy.get('ul[aria-label="Your schedules"]')
|
||||
.should('contain.text', 'Bible')
|
||||
.and('contain.text', 'Chapter')
|
||||
.and('contain.text', '2 assignments')
|
||||
cy.contains('a', 'Bible').should('have.attr', 'href', '/schedules/73')
|
||||
})
|
||||
})
|
||||
|
|
@ -13,6 +13,10 @@ function interceptAuthenticatedUser(): void {
|
|||
describe('sets dashboard', () => {
|
||||
beforeEach(() => {
|
||||
interceptAuthenticatedUser()
|
||||
cy.intercept('GET', '**/api/schedules', {
|
||||
statusCode: 200,
|
||||
body: { schedules: [] },
|
||||
})
|
||||
})
|
||||
|
||||
it('shows every available set as a detail link', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue