Skip to content

Commit

Permalink
Ensure the email address looks real
Browse files Browse the repository at this point in the history
  • Loading branch information
thewilkybarkid committed Oct 11, 2023
1 parent 6560746 commit f2fce9c
Show file tree
Hide file tree
Showing 28 changed files with 339 additions and 30 deletions.
27 changes: 27 additions & 0 deletions integration/log-in.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,33 @@ test.extend(canLogIn).extend(userIsBlocked)(
},
)

test.extend(canLogIn).extend(areLoggedIn).extend(canChangeEmailAddress)(
'have to give a valid email address',
async ({ javaScriptEnabled, page }) => {
await page.goto('/my-details/change-email-address')
await page.getByLabel('What is your email address?').fill('not an email address')

await page.getByRole('button', { name: 'Save and continue' }).click()

if (javaScriptEnabled) {
await expect(page.getByRole('alert', { name: 'There is a problem' })).toBeFocused()
} else {
await expect(page.getByRole('alert', { name: 'There is a problem' })).toBeInViewport()
}
await expect(page.getByLabel('What is your email address?')).toHaveAttribute('aria-invalid', 'true')
await page.mouse.move(0, 0)
await expect(page).toHaveScreenshot()

await page
.getByRole('link', { name: 'Enter an email address in the correct format, like name@example.com' })
.click()

await expect(page.getByLabel('What is your email address?')).toBeFocused()
await page.mouse.move(0, 0)
await expect(page).toHaveScreenshot()
},
)

test.extend(canLogIn).extend(areLoggedIn)(
'have to say if you are open for requests',
async ({ javaScriptEnabled, page }) => {
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
},
"dependencies": {
"@godaddy/terminus": "^4.12.1",
"@hapi/address": "^5.1.1",
"@js-temporal/polyfill": "^0.4.4",
"@keyv/redis": "^2.8.0",
"anonymus": "^2.1.3",
Expand Down
22 changes: 19 additions & 3 deletions src/email-address.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { isEmailValid } from '@hapi/address'
import * as RTE from 'fp-ts/ReaderTaskEither'
import type * as TE from 'fp-ts/TaskEither'
import { pipe } from 'fp-ts/function'
import * as C from 'io-ts/Codec'
import * as D from 'io-ts/Decoder'
import type { Orcid } from 'orcid-id-ts'
import type { NonEmptyString } from './string'

export type EmailAddress = NonEmptyString & EmailAddressBrand

export interface GetEmailAddressEnv {
getEmailAddress: (orcid: Orcid) => TE.TaskEither<'not-found' | 'unavailable', NonEmptyString>
getEmailAddress: (orcid: Orcid) => TE.TaskEither<'not-found' | 'unavailable', EmailAddress>
}

export interface EditEmailAddressEnv extends GetEmailAddressEnv {
deleteEmailAddress: (orcid: Orcid) => TE.TaskEither<'unavailable', void>
saveEmailAddress: (orcid: Orcid, EmailAddress: NonEmptyString) => TE.TaskEither<'unavailable', void>
saveEmailAddress: (orcid: Orcid, EmailAddress: EmailAddress) => TE.TaskEither<'unavailable', void>
}

export const EmailAddressC = C.fromDecoder(pipe(D.string, D.refine(isEmailAddress, 'EmailAddress')))

export const getEmailAddress = (orcid: Orcid) =>
RTE.asksReaderTaskEither(RTE.fromTaskEitherK(({ getEmailAddress }: GetEmailAddressEnv) => getEmailAddress(orcid)))

Expand All @@ -22,6 +30,14 @@ export const deleteEmailAddress = (orcid: Orcid) =>

export const saveEmailAddress = (
orcid: Orcid,
emailAddress: NonEmptyString,
emailAddress: EmailAddress,
): RTE.ReaderTaskEither<EditEmailAddressEnv, 'unavailable', void> =>
RTE.asksReaderTaskEither(RTE.fromTaskEitherK(({ saveEmailAddress }) => saveEmailAddress(orcid, emailAddress)))

function isEmailAddress(value: string): value is EmailAddress {
return isEmailValid(value)
}

interface EmailAddressBrand {
readonly EmailAddress: unique symbol
}

0 comments on commit f2fce9c

Please sign in to comment.