Skip to content

Commit

Permalink
Describe E2E 'Manager creates new OOSB record' journey
Browse files Browse the repository at this point in the history
We start a new `/e2e/tests/v2Manage.spec` file to compartmentalise these
user journeys, starting with:

> Future manager marks a bed as out of service in the V2 Manage area
>
>   Given I am signed in as a future manager
>   And I am on the list of premises page
>
>   When choose to view the detail of a particular premises
>   Then I should see the premises page
>
>   When I choose to manage its beds
>   And I pick a particular bed to manage
>   Then I see the V2 Bed page
>   And I should be able to mark a bed as out of service
>
>   When I fill in and submit the v2 Manage out-of-service-bed form
>   Then I am redirected back to the V2 bed page
>   And I see the success message on the 'history' pane of the bed page

The differences in v2/v1 behaviour are achieved with:

- a new `v2BedLink()` 'Manage (bed)' link used on the premises' bed list to
  link to the new v2 bed page

- a new `v2BedActions()` widget which offers FUTURE_MANAGER the
  link to the new v2 "create out of service bed" form from the v2
  bed page
  • Loading branch information
edavey committed Jul 4, 2024
1 parent 7260529 commit f3dd1ca
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 10 deletions.
25 changes: 25 additions & 0 deletions e2e/pages/manage/v2BedPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Page, expect } from '@playwright/test'
import { BasePage } from '../basePage'

export class V2BedPage extends BasePage {
static async initialize(page: Page, premisesName: string) {
await expect(page.locator('h1')).toContainText('View bed information')
await expect(page.locator('.moj-identity-bar__title')).toContainText(premisesName)
return new V2BedPage(page)
}

async clickActions() {
await this.page.getByRole('button', { name: 'Actions' }).click()
}

async clickMarkBedAsOutOfService() {
await this.clickActions()
await this.page.getByRole('menuitem', { name: 'Create out of service bed record' }).click()
}

async showsOutOfServiceBedRecordedSuccessMessage() {
await expect(this.page.locator('.govuk-notification-banner')).toContainText(
'The out of service bed has been recorded',
)
}
}
67 changes: 67 additions & 0 deletions e2e/pages/manage/v2MarkBedAsOutOfServicePage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Page, expect } from '@playwright/test'
import { getDate, getMonth, getYear } from 'date-fns'
import { faker } from '@faker-js/faker/locale/en_GB'
import { BasePage } from '../basePage'

export class V2MarkBedAsOutOfServicePage extends BasePage {
startDate: Date

static async initialize(page: Page, title?: string) {
if (title) {
await expect(page.locator('h1')).toContainText(title)
}
const instance = new V2MarkBedAsOutOfServicePage(page)
instance.startDate = faker.date.soon({ days: 600 })
return instance
}

endDate() {
const endDate = new Date(this.startDate)
endDate.setDate(endDate.getDate() + 2)
return endDate
}

async enterOutOfServiceFromDate() {
const { startDate } = this
await this.page
.getByRole('group', { name: 'Out of service from' })
.getByLabel('Day')
.fill(getDate(startDate).toString())
await this.page
.getByRole('group', { name: 'Out of service from' })
.getByLabel('Month')
.fill(getMonth(startDate).toString())
await this.page
.getByRole('group', { name: 'Out of service from' })
.getByLabel('Year')
.fill(getYear(startDate).toString())
}

async enterOutOfServiceToDate() {
const endDate = this.endDate()
await this.page
.getByRole('group', { name: 'Out of service to' })
.getByLabel('Day')
.fill(getDate(endDate).toString())
await this.page
.getByRole('group', { name: 'Out of service to' })
.getByLabel('Month')
.fill(getMonth(endDate).toString())
await this.page
.getByRole('group', { name: 'Out of service to' })
.getByLabel('Year')
.fill(getYear(endDate).toString())
}

async completeForm() {
await this.enterOutOfServiceFromDate()
await this.enterOutOfServiceToDate()
await this.checkRadio('Planned Refurbishment')
await this.page.getByLabel('Work order reference number').fill('123456789')
await this.page
.getByLabel(
'Provide detail about why the bed is out of service. If FM works are required you should update this record with any progress on that work.',
)
.fill('Reasons for bed being out of service')
}
}
52 changes: 52 additions & 0 deletions e2e/tests/v2Manage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { test } from '../test'
import { visitDashboard } from '../steps/apply'
import { PremisesListPage } from '../pages/manage/premisesListPage'
import { PremisesPage } from '../pages/manage/premisesPage'
import { BedsPage } from '../pages/manage/bedsPage'
import { V2BedPage } from '../pages/manage/v2BedPage'
import { V2MarkBedAsOutOfServicePage } from '../pages/manage/v2MarkBedAsOutOfServicePage'
import { signIn } from '../steps/signIn'

test.describe.configure({ mode: 'parallel' })

const premisesName = 'Test AP 10'

test('Future manager marks a bed as out of service in the V2 Manage area', async ({ page, futureManager }) => {
// Given I am signed in as a future manager
await signIn(page, futureManager)

// And I am on the list of premises page
const dashboard = await visitDashboard(page)
await dashboard.clickManage()
const premisesListPage = await PremisesListPage.initialize(page, 'List of Approved Premises')

// When choose to view the detail of a particular premises
await premisesListPage.choosePremises(premisesName)

// Then I should see the premises page
const premisesPage = await PremisesPage.initialize(page, premisesName)

// When I choose to manage its beds
await premisesPage.viewRooms()
const manageBedsPage = await BedsPage.initialize(page, 'Manage beds')

// And I pick a particular bed to manage
await manageBedsPage.viewAvailableBed()

// Then I see the V2 Bed page
const v2BedPage = await V2BedPage.initialize(page, premisesName)

// And I should be able to mark a bed as out of service
await v2BedPage.clickMarkBedAsOutOfService()

// When I fill in and submit the v2 Manage out-of-service-bed form
const v2MarkBedAsOutOfServicePage = await V2MarkBedAsOutOfServicePage.initialize(page, 'Mark a bed as out of service')
await v2MarkBedAsOutOfServicePage.completeForm()
await v2MarkBedAsOutOfServicePage.clickSave()

// Then I am redirected back to the V2 bed page
const revisitedV2BedPage = await V2BedPage.initialize(page, premisesName)

// And I see the success message on the 'history' pane of the bed page
await revisitedV2BedPage.showsOutOfServiceBedRecordedSuccessMessage()
})
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,8 @@ export class OutOfServiceBedCreatePage extends Page {
cy.get('input[name="outOfServiceBed[referenceNumber]"]').type(outOfServiceBed.referenceNumber)
}

if (outOfServiceBed.notes) {
cy.get('[name="outOfServiceBed[notes]"]').type(outOfServiceBed.notes)
}
cy.get(`input[name="outOfServiceBed[reason]"][value="${outOfServiceBed.reason.id}"]`).check()
cy.get('[name="outOfServiceBed[notes]"]').type(outOfServiceBed.notes)
}

public clickSubmit(): void {
Expand Down
14 changes: 12 additions & 2 deletions integration_tests/tests/v2Manage/outOfServiceBeds.cy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import DashboardPage from '../../pages/dashboard'
import {
bedDetailFactory,
bookingFactory,
extendedPremisesSummaryFactory,
outOfServiceBedCancellationFactory,
Expand All @@ -12,6 +13,7 @@ import {
OutOfServiceBedListPage,
OutOfServiceBedShowPage,
} from '../../pages/manage/outOfServiceBeds'
import BedShowPage from '../../pages/v2Manage/bed/bedShow'
import Page from '../../pages/page'
import { signIn } from '../signIn'
import { OutOfServiceBedIndexPage } from '../../pages/v2Manage/outOfServiceBeds'
Expand All @@ -38,6 +40,10 @@ context('OutOfServiceBeds', () => {
})
cy.task('stubOutOfServiceBedCreate', { premisesId: premises.id, outOfServiceBed })

// stub ultimate API call when redirecting to bed page
const bedDetail = bedDetailFactory.build({ id: outOfServiceBed.bed.id })
cy.task('stubBed', { premisesId: premises.id, bedDetail })

const page = OutOfServiceBedCreatePage.visit(premises.id, outOfServiceBed.bed.id)

// And I fill out the form
Expand All @@ -56,10 +62,14 @@ context('OutOfServiceBeds', () => {
expect(requestBody.endDate).equal(outOfServiceBed.endDate)
expect(requestBody.notes).equal(outOfServiceBed.notes)
expect(requestBody.referenceNumber).equal(outOfServiceBed.referenceNumber)
expect(requestBody.reason).equal(outOfServiceBed.reason.id)
})

// And I should be navigated to the premises detail page and see the confirmation message
page.shouldShowBanner('The out of service bed has been recorded')
// And I should be redirected to the v2 bed page
const v2BedPage = Page.verifyOnPage(BedShowPage)

// And I should see the confirmation message
v2BedPage.shouldShowBanner('The out of service bed has been recorded')
})

it('should show errors', () => {
Expand Down
6 changes: 4 additions & 2 deletions server/controllers/manage/outOfServiceBedsController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ describe('OutOfServiceBedsController', () => {
})

describe('create', () => {
it('creates a outOfService bed and redirects to the premises page', async () => {
it('creates a outOfService bed and redirects to the v2 bed page', async () => {
const requestHandler = outOfServiceBedController.create()

request.params = {
Expand All @@ -118,7 +118,9 @@ describe('OutOfServiceBedsController', () => {
bedId: request.params.bedId,
})
expect(request.flash).toHaveBeenCalledWith('success', 'The out of service bed has been recorded')
expect(response.redirect).toHaveBeenCalledWith(paths.premises.show({ premisesId: request.params.premisesId }))
expect(response.redirect).toHaveBeenCalledWith(
paths.v2Manage.premises.beds.show({ premisesId: request.params.premisesId, bedId: outOfServiceBed.bed.id }),
)
})

describe('when errors are raised', () => {
Expand Down
2 changes: 1 addition & 1 deletion server/controllers/manage/outOfServiceBedsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default class OutOfServiceBedsController {
await this.outOfServiceBedService.createOutOfServiceBed(req.user.token, premisesId, outOfServiceBed)

req.flash('success', 'The out of service bed has been recorded')
return res.redirect(paths.premises.show({ premisesId }))
return res.redirect(paths.v2Manage.premises.beds.show({ premisesId, bedId }))
} catch (error) {
const redirectPath = paths.v2Manage.outOfServiceBeds.new({ premisesId, bedId })

Expand Down
2 changes: 1 addition & 1 deletion server/testutils/factories/outOfServiceBed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const outOfServiceBedFactory = Factory.define<OutOfServiceBed>(() => ({
apArea: namedIdFactory.build(),
reason: cas1ReferenceDataFactory.outOfServiceBedReason().build(),
referenceNumber: faker.helpers.arrayElement([faker.string.uuid(), undefined]),
notes: faker.helpers.arrayElement([faker.lorem.sentence(), undefined]),
notes: faker.lorem.sentence(),
daysLostCount: faker.number.int({ min: 1, max: 100 }),
temporality: faker.helpers.arrayElement(['past', 'current', 'future'] as const),
status: faker.helpers.arrayElement(['active', 'cancelled'] as const),
Expand Down
15 changes: 15 additions & 0 deletions server/utils/bedUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
statusRow,
title,
v1BedLink,
v2BedActions,
v2BedLink,
} from './bedUtils'
import { DateFormats } from './dateUtils'
Expand Down Expand Up @@ -187,6 +188,20 @@ describe('bedUtils', () => {
})
})

describe('v2BedActions', () => {
it('returns the actions for the V2 bed manage page', () => {
expect(v2BedActions(bedDetail, premisesId)).toEqual({
items: [
{
text: 'Create out of service bed record',
classes: 'govuk-button--secondary',
href: paths.v2Manage.outOfServiceBeds.new({ premisesId, bedId: bedDetail.id }),
},
],
})
})
})

describe('encodeOverbooking', () => {
it('encodes an overbooking entry to Base64', () => {
const overbooking = bedOccupancyEntryOverbookingUiFactory.build()
Expand Down
12 changes: 12 additions & 0 deletions server/utils/bedUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ export const bedActions = (bed: BedDetail, premisesId: string) => {
}
}

export const v2BedActions = (bed: BedDetail, premisesId: string) => {
return {
items: [
{
text: 'Create out of service bed record',
classes: 'govuk-button--secondary',
href: paths.v2Manage.outOfServiceBeds.new({ premisesId, bedId: bed.id }),
},
],
}
}

const bedLinkForUser = (bed: BedSummary, premisesId: string, user?: UserDetails): string => {
if (user && user.roles?.includes('future_manager')) {
return v2BedLink(bed, premisesId)
Expand Down
1 change: 1 addition & 0 deletions server/views/outOfServiceBeds/new.njk
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
{{ govukTextarea({
id: "notes",
name: "outOfServiceBed[notes]",
value: outOfServiceBed.notes,
label: {
text: "Provide detail about why the bed is out of service. If FM works are required you should update this record with any progress on that work.",
classes: "govuk-fieldset__legend--s"
Expand Down
5 changes: 4 additions & 1 deletion server/views/v2Manage/premises/beds/show.njk
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{% from "govuk/components/notification-banner/macro.njk" import govukNotificationBanner %}
{% from "govuk/components/table/macro.njk" import govukTable %}
{% from "govuk/components/back-link/macro.njk" import govukBackLink %}

Expand All @@ -18,13 +19,15 @@
{% block content %}
<div class="govuk-grid-row">
<div class="govuk-grid-column-full-width">
{% include "../../../_messages.njk" %}

{% if UserUtils.hasManagerRole(user) %}
{{
mojIdentityBar({
title: {
html: '<span class="govuk-caption-l">' + premises.name + '</span> <h1 class="govuk-heading-l"><span class="govuk-caption-l">Room ' + bed.roomName + ', Bed ' + bed.name + '</span>' + pageHeading + '</h1>'
},
menus: [BedUtils.bedActions(bed, premises.id)]
menus: [BedUtils.v2BedActions(bed, premises.id)]
})
}}
{% else %}
Expand Down

0 comments on commit f3dd1ca

Please sign in to comment.