test set layout browsing
This commit is contained in:
parent
936855efab
commit
eb7ac7d261
8 changed files with 619 additions and 3 deletions
|
|
@ -24,6 +24,13 @@ describe('guest authentication pages', () => {
|
|||
cy.location('search').should('include', 'redirect=/dashboard')
|
||||
})
|
||||
|
||||
it('redirects guests away from a protected set layout', () => {
|
||||
cy.visit('/sets/41')
|
||||
|
||||
cy.location('pathname').should('equal', '/login')
|
||||
cy.location('search').should('include', 'redirect=/sets/41')
|
||||
})
|
||||
|
||||
it('shows the login form and links to signup', () => {
|
||||
cy.visit('/login')
|
||||
|
||||
|
|
|
|||
183
frontend/website/cypress/e2e/set-layout.cy.ts
Normal file
183
frontend/website/cypress/e2e/set-layout.cy.ts
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
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: 5, name: 'Noah', kind: 'portion', children: [] },
|
||||
],
|
||||
},
|
||||
{ id: 2, name: 'Exodus', kind: 'book', children: [] },
|
||||
],
|
||||
}
|
||||
|
||||
function interceptAuthenticatedUser(): void {
|
||||
cy.intercept('GET', '**/api/me', {
|
||||
statusCode: 200,
|
||||
body: { user: authenticatedUser },
|
||||
}).as('me')
|
||||
}
|
||||
|
||||
describe('set element layout', () => {
|
||||
beforeEach(() => {
|
||||
interceptAuthenticatedUser()
|
||||
})
|
||||
|
||||
it('opens a set from the dashboard and shows its full hierarchy', () => {
|
||||
cy.intercept('GET', '**/api/sets', {
|
||||
statusCode: 200,
|
||||
body: { sets: [{ id: 41, name: 'Bible' }] },
|
||||
}).as('sets')
|
||||
cy.intercept('GET', '**/api/sets/41', (request) => {
|
||||
expect(request.headers.accept).to.equal('application/json')
|
||||
request.reply({ statusCode: 200, body: bibleLayout })
|
||||
}).as('layout')
|
||||
|
||||
cy.visit('/dashboard')
|
||||
cy.wait('@me')
|
||||
cy.wait('@sets')
|
||||
cy.contains('a', 'Bible').click()
|
||||
cy.wait('@layout')
|
||||
|
||||
cy.location('pathname').should('equal', '/sets/41')
|
||||
cy.get('h1').should('have.text', 'Bible')
|
||||
cy.contains('a', 'Back to sets').should('have.attr', 'href', '/dashboard')
|
||||
cy.get('ol[aria-label="Bible element layout"] > li').then(($nodes) => {
|
||||
expect([...$nodes].map((node) => node.dataset.elementId)).to.deep.equal([
|
||||
'1',
|
||||
'2',
|
||||
])
|
||||
})
|
||||
cy.get('[data-element-id="1"] > .element-node__card')
|
||||
.should('contain.text', 'Genesis')
|
||||
.and('contain.text', 'book')
|
||||
cy.get('[data-element-id="1"] > ol > li').then(($nodes) => {
|
||||
expect([...$nodes].map((node) => node.dataset.elementId)).to.deep.equal([
|
||||
'3',
|
||||
'5',
|
||||
])
|
||||
})
|
||||
cy.get('[data-element-id="3"] > ol > li')
|
||||
.should('have.length', 1)
|
||||
.and('have.attr', 'data-element-id', '4')
|
||||
cy.contains('.element-node__card', 'Chapter 1')
|
||||
.should('be.visible')
|
||||
.and('contain.text', 'chapter')
|
||||
})
|
||||
|
||||
it('shows loading and empty layout states', () => {
|
||||
cy.intercept('GET', '**/api/sets/41', {
|
||||
delay: 500,
|
||||
statusCode: 200,
|
||||
body: { set: { id: 41, name: 'Empty set' }, elements: [] },
|
||||
}).as('layout')
|
||||
|
||||
cy.visit('/sets/41')
|
||||
cy.wait('@me')
|
||||
cy.get('[role="status"]').should('have.text', 'Loading set layout...')
|
||||
cy.wait('@layout')
|
||||
|
||||
cy.get('h1').should('have.text', 'Empty set')
|
||||
cy.get('[role="status"]').should(
|
||||
'have.text',
|
||||
'This set does not have any elements yet.',
|
||||
)
|
||||
})
|
||||
|
||||
it('retries after a layout request fails', () => {
|
||||
let requestCount = 0
|
||||
cy.intercept('GET', '**/api/sets/41', (request) => {
|
||||
requestCount += 1
|
||||
request.alias = `layout${requestCount}`
|
||||
|
||||
if (requestCount === 1) {
|
||||
request.reply({ statusCode: 500 })
|
||||
return
|
||||
}
|
||||
|
||||
request.reply({ statusCode: 200, body: bibleLayout })
|
||||
})
|
||||
|
||||
cy.visit('/sets/41')
|
||||
cy.wait('@me')
|
||||
cy.wait('@layout1')
|
||||
|
||||
cy.get('[role="alert"]').should(
|
||||
'contain.text',
|
||||
"We couldn't load this set's layout.",
|
||||
)
|
||||
cy.contains('button', 'Try again').click()
|
||||
cy.wait('@layout2')
|
||||
|
||||
cy.get('h1').should('have.text', 'Bible')
|
||||
})
|
||||
|
||||
it('distinguishes missing sets from malformed responses', () => {
|
||||
cy.intercept('GET', '**/api/sets/41', {
|
||||
statusCode: 404,
|
||||
body: { error: 'set not found' },
|
||||
}).as('missing')
|
||||
|
||||
cy.visit('/sets/41')
|
||||
cy.wait('@me')
|
||||
cy.wait('@missing')
|
||||
|
||||
cy.get('h1').should('have.text', 'Set not found')
|
||||
cy.get('[role="alert"]').should(
|
||||
'contain.text',
|
||||
"The set you're looking for is not available.",
|
||||
)
|
||||
|
||||
cy.intercept('GET', '**/api/sets/42', {
|
||||
statusCode: 200,
|
||||
body: { set: { id: 42, name: 12 }, elements: [] },
|
||||
}).as('malformed')
|
||||
cy.visit('/sets/42')
|
||||
cy.wait('@malformed')
|
||||
|
||||
cy.get('[role="alert"]').should(
|
||||
'contain.text',
|
||||
"We couldn't load this set's layout.",
|
||||
)
|
||||
cy.contains('button', 'Try again').should('be.visible')
|
||||
})
|
||||
|
||||
it('keeps a deeply nested layout within a mobile viewport', () => {
|
||||
cy.viewport(390, 844)
|
||||
cy.intercept('GET', '**/api/sets/41', {
|
||||
statusCode: 200,
|
||||
body: bibleLayout,
|
||||
}).as('layout')
|
||||
|
||||
cy.visit('/sets/41')
|
||||
cy.wait('@me')
|
||||
cy.wait('@layout')
|
||||
|
||||
cy.contains('.element-node__card', 'Chapter 1').should('be.visible')
|
||||
cy.document().then((document) => {
|
||||
expect(document.documentElement.scrollWidth).to.be.at.most(
|
||||
document.documentElement.clientWidth,
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -15,7 +15,7 @@ describe('sets dashboard', () => {
|
|||
interceptAuthenticatedUser()
|
||||
})
|
||||
|
||||
it('shows every available set by name', () => {
|
||||
it('shows every available set as a detail link', () => {
|
||||
cy.intercept('GET', '**/api/sets', (request) => {
|
||||
expect(request.headers.accept).to.equal('application/json')
|
||||
request.reply({
|
||||
|
|
@ -46,8 +46,13 @@ describe('sets dashboard', () => {
|
|||
.should('not.contain.text', '41')
|
||||
.and('not.contain.text', '58')
|
||||
.and('not.contain.text', '92')
|
||||
.find('a, button')
|
||||
.should('not.exist')
|
||||
cy.contains('a', 'Bible').should('have.attr', 'href', '/sets/41')
|
||||
cy.contains('a', 'Course').should('have.attr', 'href', '/sets/58')
|
||||
cy.contains('a', 'Fitness Program').should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'/sets/92',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows loading and empty catalog states', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue