cypress/integration/ete/registration_2.6.cy.ts (956 lines of code) (raw):

import { randomMailosaurEmail, randomPassword, } from '../../support/commands/testUser'; import { Status } from '../../../src/server/models/okta/User'; describe('Registration flow - Split 2/2', () => { context( 'Existing users asking for an email to be resent after attempting to register with Okta - useOktaClassic', () => { it('should resend a STAGED user a set password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: true, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.STAGED); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); // Wait for the first email to arrive... cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); // ...before waiting for the second email to arrive cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Create password'); expect(links.length).to.eq(2); const setPasswordLink = links.find((s) => s.text?.includes('Create password'), ); expect(setPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(setPasswordLink?.href as string); cy.contains('Create password'); cy.contains(emailAddress); }); }); }); }); }); it('should resend a PROVISIONED user a set password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: true, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.activateTestOktaUser(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.PROVISIONED); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Create password'); expect(links.length).to.eq(2); const setPasswordLink = links.find((s) => s.text?.includes('Create password'), ); expect(setPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(setPasswordLink?.href as string); cy.contains('Create password'); cy.contains(emailAddress); }); }); }); }); }); }); it('should send an ACTIVE user a reset password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.ACTIVE); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Sign in'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains('Create new password'); cy.contains(emailAddress); }); }); }); }); }); it('should send a RECOVERY user a reset password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.resetOktaUserPassword(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.RECOVERY); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('Password reset'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains('Create new password'); cy.contains(emailAddress); }); }); }); }); }); }); it('should send a PASSWORD_EXPIRED user a reset password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.expireOktaUserPassword(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.PASSWORD_EXPIRED); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('Password reset'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains('Create new password'); cy.contains(emailAddress); }); }); }); }); }); }); }, ); context('Welcome Page - Resend (Link expired)', () => { it('send an email for user with no existing account', () => { const encodedReturnUrl = 'https%3A%2F%2Fm.code.dev-theguardian.com%2Ftravel%2F2019%2Fdec%2F18%2Ffood-culture-tour-bethlehem-palestine-east-jerusalem-photo-essay'; const unregisteredEmail = randomMailosaurEmail(); cy.visit(`/welcome/resend?returnUrl=${encodedReturnUrl}`); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(unregisteredEmail); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Enter your code'); cy.contains(unregisteredEmail); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails(unregisteredEmail, timeRequestWasMade).then( ({ body, codes }) => { // email expect(body).to.have.string('Your verification code'); expect(codes?.length).to.eq(1); const code = codes?.[0].value; expect(code).to.match(/^\d{6}$/); // passcode page cy.url().should('include', '/register/email-sent'); cy.contains('Submit verification code'); cy.get('input[name=code]').type(code!); cy.url().should('contain', '/welcome/review'); //we are reloading here to make sure the params are persisted even on page refresh cy.reload(); cy.url().should('contain', encodedReturnUrl); }, ); }); it('should resend a STAGED user a set password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: true, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.STAGED); cy.visit('/welcome/resend?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); // Wait for the first email to arrive... cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); // ...before waiting for the second email to arrive cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Create password'); expect(links.length).to.eq(2); const setPasswordLink = links.find((s) => s.text?.includes('Create password'), ); expect(setPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(setPasswordLink?.href as string); cy.contains('Create password'); cy.contains(emailAddress); }); }); }); }); }); it('should resend a PROVISIONED user a set password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: true, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.activateTestOktaUser(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.PROVISIONED); cy.visit('/welcome/resend?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Create password'); expect(links.length).to.eq(2); const setPasswordLink = links.find((s) => s.text?.includes('Create password'), ); expect(setPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(setPasswordLink?.href as string); cy.contains('Create password'); cy.contains(emailAddress); }); }); }); }); }); }); it('should send an ACTIVE user a reset password email with an activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.ACTIVE); cy.visit('/welcome/resend?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Sign in'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains('Create new password'); cy.contains(emailAddress); }); }); }); }); }); it('should send a RECOVERY user a reset password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.resetOktaUserPassword(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.RECOVERY); cy.visit('/welcome/resend?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('Password reset'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains('Create new password'); cy.contains(emailAddress); }); }); }); }); }); }); it('should send a PASSWORD_EXPIRED user a reset password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.expireOktaUserPassword(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.PASSWORD_EXPIRED); cy.visit('/welcome/resend?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(() => { const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('Password reset'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains('Create new password'); cy.contains(emailAddress); }); }); }); }); }); }); }); context('Okta session exists on /signin', () => { beforeEach(() => { // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', 'https://m.code.dev-theguardian.com/', (req) => { req.reply(200); }); }); it('shows the signed in as page', () => { // Create a validated test user cy.createTestUser({ isUserEmailValidated: true }).then( ({ emailAddress, finalPassword }) => { // Sign our new user in cy.visit( `/signin?returnUrl=${encodeURIComponent( `https://${Cypress.env('BASE_URI')}/welcome/review`, )}&usePasswordSignIn=true`, ); cy.get('input[name=email]').type(emailAddress); cy.get('input[name=password]').type(finalPassword); cy.get('[data-cy="main-form-submit-button"]').click(); cy.url().should('include', '/welcome/review'); // Get the current session data cy.getCookie('idx').then((originalIdxCookie) => { expect(originalIdxCookie).to.exist; // Visit register again cy.visit( `/register/email?returnUrl=${encodeURIComponent( `https://${Cypress.env('BASE_URI')}/welcome/review`, )}`, ); cy.url().should('include', '/register'); cy.contains('Sign in to the Guardian'); cy.contains('You are signed in with'); cy.contains(emailAddress); cy.contains('Continue') .should('have.attr', 'href') .and( 'include', `https://${Cypress.env( 'BASE_URI', )}/signin/refresh?returnUrl=https%3A%2F%2Fprofile.thegulocal.com%2Fwelcome%2Freview`, ); cy.contains('a', 'Sign in') .should('have.attr', 'href') .and('include', '/signout?returnUrl='); cy.contains('Sign in with a different email'); }); }, ); }); }); // a few tests to check if the Okta Classic flow is still working using the useOktaClassic flag context('Okta Classic Flow - new user', () => { it('create account - successfully registers using an email with no existing account', () => { const encodedReturnUrl = 'https%3A%2F%2Fm.code.dev-theguardian.com%2Ftravel%2F2019%2Fdec%2F18%2Ffood-culture-tour-bethlehem-palestine-east-jerusalem-photo-essay'; const unregisteredEmail = randomMailosaurEmail(); const encodedRef = 'https%3A%2F%2Fm.theguardian.com'; const refViewId = 'testRefViewId'; const clientId = 'jobs'; // these params should *not* persist between initial registration and welcome page // despite the fact that they PersistableQueryParams, as these are set by the Okta SDK sign in method // and subsequent interception, and not by gateway const appClientId = 'appClientId1'; const fromURI = 'fromURI1'; cy.visit( `/register/email?returnUrl=${encodedReturnUrl}&ref=${encodedRef}&refViewId=${refViewId}&clientId=${clientId}&appClientId=${appClientId}&fromURI=${fromURI}&useOktaClassic=true`, ); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(unregisteredEmail); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(unregisteredEmail); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( unregisteredEmail, timeRequestWasMade, /welcome\/([^"]*)/, ).then(({ body, token }) => { expect(body).to.have.string('Complete registration'); cy.visit(`/welcome/${token}`); cy.contains('Complete creating account'); cy.get('form') .should('have.attr', 'action') .and('match', new RegExp(encodedReturnUrl)) .and('match', new RegExp(refViewId)) .and('match', new RegExp(encodedRef)) .and('match', new RegExp(clientId)) .and('not.match', new RegExp(appClientId)) .and('not.match', new RegExp(fromURI)); //we are reloading here to make sure the params are persisted even on page refresh cy.reload(); cy.get('input[name="firstName"]').type('First Name'); cy.get('input[name="secondName"]').type('Last Name'); cy.get('input[name="password"]').type(randomPassword()); cy.get('button[type="submit"]').click(); cy.url().should('contain', encodedReturnUrl); cy.url().should('contain', refViewId); cy.url().should('contain', encodedRef); cy.url().should('contain', clientId); cy.url().should('not.contain', appClientId); cy.url().should('not.contain', fromURI); // test the registration platform is set correctly cy.getTestOktaUser(unregisteredEmail).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.ACTIVE); expect(oktaUser.profile.registrationPlatform).to.eq('profile'); }); }); }); it('create account - successfully registers using an email with no existing account, and has a prefixed activation token when using a native app', () => { cy.intercept('GET', 'https://m.code.dev-theguardian.com/', (req) => { req.reply(200); }); const encodedReturnUrl = 'https%3A%2F%2Fm.code.dev-theguardian.com%2Ftravel%2F2019%2Fdec%2F18%2Ffood-culture-tour-bethlehem-palestine-east-jerusalem-photo-essay'; const unregisteredEmail = randomMailosaurEmail(); const encodedRef = 'https%3A%2F%2Fm.theguardian.com'; const refViewId = 'testRefViewId'; const clientId = 'jobs'; // these params should *not* persist between initial registration and welcome page // despite the fact that they PersistableQueryParams, as these are set by the Okta SDK sign in method // and subsequent interception, and not by gateway const appClientId = Cypress.env('OKTA_ANDROID_CLIENT_ID'); const fromURI = 'fromURI1'; cy.visit( `/register/email?returnUrl=${encodedReturnUrl}&ref=${encodedRef}&refViewId=${refViewId}&clientId=${clientId}&appClientId=${appClientId}&fromURI=${fromURI}&useOktaClassic=true`, ); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(unregisteredEmail); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(unregisteredEmail); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( unregisteredEmail, timeRequestWasMade, /welcome\/([^"]*)/, ).then(({ body, token }) => { expect(body).to.have.string('Complete registration'); expect(token).to.have.string('al_'); cy.visit(`/welcome/${token}`); cy.contains('Complete creating account'); cy.get('form') .should('have.attr', 'action') .and('match', new RegExp(encodedReturnUrl)) .and('match', new RegExp(refViewId)) .and('match', new RegExp(encodedRef)) .and('match', new RegExp(clientId)) .and('not.match', new RegExp(appClientId)) .and('not.match', new RegExp(fromURI)); //we are reloading here to make sure the params are persisted even on page refresh cy.reload(); cy.get('form') .should('have.attr', 'action') .and('match', new RegExp(encodedReturnUrl)) .and('match', new RegExp(refViewId)) .and('match', new RegExp(encodedRef)) .and('match', new RegExp(clientId)) .and('not.match', new RegExp(appClientId)) .and('not.match', new RegExp(fromURI)); cy.get('input[name="firstName"]').type('First Name'); cy.get('input[name="secondName"]').type('Last Name'); cy.get('input[name="password"]').type(randomPassword()); cy.get('button[type="submit"]').click(); cy.url().should('contain', '/welcome/al_/complete'); cy.contains(unregisteredEmail); cy.contains('Guardian app'); // test the registration platform is set correctly cy.getTestOktaUser(unregisteredEmail).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.ACTIVE); expect(oktaUser.profile.registrationPlatform).to.eq( 'android_live_app', ); }); }); }); it('welcome expired - send an email for user with no existing account', () => { const encodedReturnUrl = 'https%3A%2F%2Fm.code.dev-theguardian.com%2Ftravel%2F2019%2Fdec%2F18%2Ffood-culture-tour-bethlehem-palestine-east-jerusalem-photo-essay'; const unregisteredEmail = randomMailosaurEmail(); cy.visit( `/welcome/resend?returnUrl=${encodedReturnUrl}&useOktaClassic=true`, ); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(unregisteredEmail); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(unregisteredEmail); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( unregisteredEmail, timeRequestWasMade, /welcome\/([^"]*)/, ).then(({ body, token }) => { expect(body).to.have.string('Complete registration'); cy.visit(`/welcome/${token}`); cy.contains('Complete creating account'); cy.get('form') .should('have.attr', 'action') .and('match', new RegExp(encodedReturnUrl)); //we are reloading here to make sure the params are persisted even on page refresh cy.reload(); cy.get('input[name="password"]').type(randomPassword()); cy.get('button[type="submit"]').click(); cy.url().should('contain', encodedReturnUrl); }); }); }); context( 'Existing users attempting to register with Okta - useOktaClassic', () => { it('should send a STAGED user a set password email with an Okta activation token', () => { // Test users created via IDAPI-with-Okta do not have the activation // lifecycle run at creation, so they don't transition immediately from // STAGED to PROVISIONED (c.f. // https://developer.okta.com/docs/reference/api/users/#create-user) . // This is useful for us as we can test STAGED users first, then test // PROVISIONED users in the next test by activating a STAGED user. Users // created through Gateway-with-Okta do have this lifecycle run, so if we // rebuild these tests to not use IDAPI at all, we need to figure out a // way to test STAGED and PROVISIONED users (probably by just passing an // optional `activate` prop to a createUser function). cy .createTestUser({ isGuestUser: true, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.STAGED); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Create password'); expect(links.length).to.eq(2); const setPasswordLink = links.find((s) => s.text?.includes('Create password'), ); expect(setPasswordLink?.href).not.to.have.string( 'useOkta=true', ); cy.visit(setPasswordLink?.href as string); cy.contains('Create password'); cy.contains(emailAddress); }); }); }); }); it('should send a STAGED user a set password email with an Okta activation token, and has a prefixed activation token when using a native app', () => { // Test users created via IDAPI-with-Okta do not have the activation // lifecycle run at creation, so they don't transition immediately from // STAGED to PROVISIONED (c.f. // https://developer.okta.com/docs/reference/api/users/#create-user) . // This is useful for us as we can test STAGED users first, then test // PROVISIONED users in the next test by activating a STAGED user. Users // created through Gateway-with-Okta do have this lifecycle run, so if we // rebuild these tests to not use IDAPI at all, we need to figure out a // way to test STAGED and PROVISIONED users (probably by just passing an // optional `activate` prop to a createUser function). cy .createTestUser({ isGuestUser: true, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.STAGED); const appClientId = Cypress.env('OKTA_ANDROID_CLIENT_ID'); const fromURI = 'fromURI1'; cy.visit( `/register/email?appClientId=${appClientId}&fromURI=${fromURI}&useOktaClassic=true`, ); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Create password'); expect(links.length).to.eq(2); const setPasswordLink = links.find((s) => s.text?.includes('Create password'), ); expect(setPasswordLink?.href ?? '') .to.have.string('al_') .and.not.to.have.string('useOkta=true'); cy.visit(setPasswordLink?.href as string); cy.contains('Create password'); cy.contains(emailAddress); }); }); }); }); it('should send a PROVISIONED user a set password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: true, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.activateTestOktaUser(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.PROVISIONED); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Create password'); expect(links.length).to.eq(2); const setPasswordLink = links.find((s) => s.text?.includes('Create password'), ); expect(setPasswordLink?.href).not.to.have.string( 'useOkta=true', ); cy.visit(setPasswordLink?.href as string); cy.contains('Create password'); cy.contains(emailAddress); }); }); }); }); }); it('should send an ACTIVE UNvalidated user with a password a security email with activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: false, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.ACTIVE); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); // Make sure that we don't get sent to the 'security reasons' page cy.url().should('include', '/register/email-sent'); cy.contains( 'For security reasons we need you to change your password.', ).should('not.exist'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string( 'Because your security is extremely important to us, we have changed our password policy.', ); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(2); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); cy.visit(resetPasswordLink?.href as string); cy.contains(emailAddress); cy.contains('Create new password'); }); }); }); }); it('should send an ACTIVE validated user WITH a password a reset password email with an activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.ACTIVE); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Sign in'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains(emailAddress); cy.contains('Create new password'); }); }); }); }); it('should send an ACTIVE validated user WITH a password a reset password email with an activation token, and prefixed activation token if using native app', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.ACTIVE); const appClientId = Cypress.env('OKTA_ANDROID_CLIENT_ID'); const fromURI = 'fromURI1'; cy.visit( `/register/email?appClientId=${appClientId}&fromURI=${fromURI}&useOktaClassic=true`, ); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('This account already exists'); expect(body).to.have.string('Sign in'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '') .to.have.string('al_') .and.not.to.have.string('useOkta=true'); cy.visit(resetPasswordLink?.href as string); cy.contains(emailAddress); cy.contains('Create new password'); }); }); }); }); it('should send a RECOVERY user a reset password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.resetOktaUserPassword(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.RECOVERY); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('Password reset'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains('Create new password'); cy.contains(emailAddress); }); }); }); }); }); it('should send a PASSWORD_EXPIRED user a reset password email with an Okta activation token', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.expireOktaUserPassword(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.PASSWORD_EXPIRED); cy.visit('/register/email?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Check your inbox'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('Password reset'); expect(body).to.have.string('Reset password'); expect(links.length).to.eq(3); const resetPasswordLink = links.find((s) => s.text?.includes('Reset password'), ); expect(resetPasswordLink?.href ?? '').not.to.have.string( 'useOkta=true', ); cy.visit(resetPasswordLink?.href as string); cy.contains('Create new password'); cy.contains(emailAddress); }); }); }); }); }); it('should display an error if a SUSPENDED user attempts to register', () => { cy .createTestUser({ isGuestUser: false, isUserEmailValidated: true, }) ?.then(({ emailAddress }) => { cy.suspendOktaUser(emailAddress).then(() => { cy.getTestOktaUser(emailAddress).then((oktaUser) => { expect(oktaUser.status).to.eq(Status.SUSPENDED); cy.visit('/register/email?useOktaClassic=true'); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains( 'There was a problem registering, please try again.', ); }); }); }); }); }, ); context('Extra checks', () => { it('should navigate back to the correct page when change email is clicked', () => { cy.visit('/register/email-sent'); cy.contains('try another address').click(); cy.contains('Create your account'); cy.title().should('eq', 'Register With Email | The Guardian'); }); it('should render properly if the encrypted email cookie is not set', () => { cy.visit('/register/email-sent'); cy.contains('try another address'); cy.contains('Check your inbox'); }); it('shows reCAPTCHA errors when the request fails', () => { cy.setCookie('cypress-mock-state', '1'); // passcode send again timer cy .createTestUser({ isUserEmailValidated: false, }) ?.then(({ emailAddress }) => { cy.visit('/register/email'); cy.get('input[name=email]').type(emailAddress); const timeRequestWasMadeInitialEmail = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Enter your code'); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMadeInitialEmail, ); cy.interceptRecaptcha(); cy.wait(1000); // wait for the send again button to be enabled cy.contains('send again').click(); cy.contains('Google reCAPTCHA verification failed.'); cy.contains('If the problem persists please try the following:'); const timeRequestWasMade = new Date(); cy.wait(1000); // wait for the send again button to be enabled cy.contains('send again').click(); cy.contains('Google reCAPTCHA verification failed.').should( 'not.exist', ); cy.contains('Enter your code'); cy.contains(emailAddress); cy.checkForEmailAndGetDetails(emailAddress, timeRequestWasMade); }); }); it('persists the clientId when navigating away', () => { cy.visit('/register?clientId=jobs'); cy.contains('Sign in').click(); cy.url().should('contain', 'clientId=jobs'); }); it('does not proceed when no email provided', () => { cy.visit('/register/email'); cy.get('[data-cy="main-form-submit-button"]').click(); // check that form isn't submitted cy.url().should('not.contain', 'returnUrl'); cy.contains('Please enter your email.'); }); it('does not proceed when invalid email provided', () => { cy.visit('/register/email'); const invalidEmail = 'invalid.email.com'; cy.get('input[name=email]').type(invalidEmail); cy.get('[data-cy="main-form-submit-button"]').click(); // check that form isn't submitted cy.url().should('not.contain', 'returnUrl'); cy.contains('Please enter a valid email format.'); }); it('Continue with Google button links to /signin/google', () => { cy.visit('/register'); cy.contains('Continue with Google') .should('have.attr', 'href') .and('include', '/signin/google'); }); it('Continue with Apple button links to /signin/apple', () => { cy.visit('/register'); cy.contains('Continue with Apple') .should('have.attr', 'href') .and('include', '/signin/apple'); }); it('Continue with Email button links to /register/email', () => { cy.visit('/register'); cy.contains('Continue with email') .should('have.attr', 'href') .and('include', '/register/email'); }); }); context('Terms and Conditions links', () => { it('links to the Google terms of service page', () => { const googleTermsUrl = 'https://policies.google.com/terms'; // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', googleTermsUrl, (req) => { req.reply(200); }); cy.visit('/register/email'); cy.contains('terms of service').click(); cy.url().should('eq', googleTermsUrl); }); it('links to the Google privacy policy page', () => { const googlePrivacyPolicyUrl = 'https://policies.google.com/privacy'; // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', googlePrivacyPolicyUrl, (req) => { req.reply(200); }); cy.visit('/register/email'); cy.contains('This service is protected by reCAPTCHA and the Google') .contains('privacy policy') .click(); cy.url().should('eq', googlePrivacyPolicyUrl); }); it('links to the Guardian terms and conditions page', () => { const guardianTermsOfServiceUrl = 'https://www.theguardian.com/help/terms-of-service'; // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', guardianTermsOfServiceUrl, (req) => { req.reply(200); }); cy.visit('/register'); cy.contains('terms and conditions').click(); cy.url().should('eq', guardianTermsOfServiceUrl); }); it('links to the Guardian privacy policy page', () => { const guardianPrivacyPolicyUrl = 'https://www.theguardian.com/help/privacy-policy'; // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', guardianPrivacyPolicyUrl, (req) => { req.reply(200); }); cy.visit('/register'); cy.contains('For information about how we use your data') .contains('privacy policy') .click(); cy.url().should('eq', guardianPrivacyPolicyUrl); }); it('links to the Guardian jobs terms and conditions page when jobs clientId set', () => { const guardianJobsTermsOfServiceUrl = 'https://jobs.theguardian.com/terms-and-conditions/'; // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', guardianJobsTermsOfServiceUrl, (req) => { req.reply(200); }); cy.visit('/register?clientId=jobs'); cy.contains('Guardian Jobs terms and conditions').click(); cy.url().should('eq', guardianJobsTermsOfServiceUrl); }); it('links to the Guardian jobs privacy policy page when jobs clientId set', () => { const guardianJobsPrivacyPolicyUrl = 'https://jobs.theguardian.com/privacy-policy/'; // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', guardianJobsPrivacyPolicyUrl, (req) => { req.reply(200); }); cy.visit('/register?clientId=jobs'); cy.contains('For information about how we use your data') .contains('Guardian Jobs privacy policy') .click(); cy.url().should('eq', guardianJobsPrivacyPolicyUrl); }); }); it('persists the clientId when navigating away', () => { cy.visit('/register?clientId=jobs'); cy.contains('Sign in').click(); cy.url().should('contain', 'clientId=jobs'); }); it('does not proceed when no email provided', () => { cy.visit('/register/email'); cy.get('[data-cy="main-form-submit-button"]').click(); // check that form isn't submitted cy.url().should('not.contain', 'returnUrl'); cy.contains('Please enter your email.'); }); });