cypress/integration/ete/sign_in.1.cy.ts (768 lines of code) (raw):

import { randomMailosaurEmail, randomPassword, } from '../../support/commands/testUser'; const returnUrl = 'https://www.theguardian.com/world/2013/jun/09/edward-snowden-nsa-whistleblower-surveillance'; describe('Sign in flow, Okta enabled', () => { context('Page tests', () => { 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('/signin'); 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('/signin'); 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('/signin'); 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('/signin'); 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('/signin?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('/signin?clientId=jobs'); cy.contains('For information about how we use your data') .contains('Guardian Jobs privacy policy') .click(); cy.url().should('eq', guardianJobsPrivacyPolicyUrl); }); it('navigates to reset password', () => { cy.visit('/signin?usePasswordSignIn=true'); cy.contains('Reset password').click(); cy.contains('Reset password'); }); it('navigates to registration', () => { cy.visit('/signin'); cy.contains('Create a free account').click(); cy.contains('Continue with Google'); cy.contains('Continue with Apple'); cy.contains('Continue with email'); }); it('removes encryptedEmail parameter from query string', () => { const encryptedEmailParam = 'encryptedEmail=bhvlabgflbgyil'; cy.visit(`/signin?${encryptedEmailParam}`); cy.location('search').should('not.contain', encryptedEmailParam); }); it('removes encryptedEmail parameter and preserves all other valid parameters', () => { const encryptedEmailParam = 'encryptedEmail=bhvlabgflbgyil'; cy.visit( `/signin?returnUrl=${encodeURIComponent( returnUrl, )}&${encryptedEmailParam}&refViewId=12345`, ); cy.location('search').should('not.contain', encryptedEmailParam); cy.location('search').should('contain', 'refViewId=12345'); cy.location('search').should('contain', encodeURIComponent(returnUrl)); }); it('persists the clientId when navigating away', () => { cy.visit('/signin?clientId=jobs'); cy.contains('Create a free account').click(); cy.url().should('contain', 'clientId=jobs'); }); it('applies form validation to email and password input fields', () => { cy.visit('/signin?usePasswordSignIn=true'); cy.get('form').within(() => { cy.get('input:invalid').should('have.length', 2); cy.get('input[name=email]').type('not an email'); cy.get('input:invalid').should('have.length', 2); cy.get('input[name=email]').type('emailaddress@inavalidformat.com'); cy.get('input:invalid').should('have.length', 1); cy.get('input[name=password]').type('password'); cy.get('input:invalid').should('have.length', 0); }); }); }); context('Okta Classic API Sign In', () => { it('shows a message when credentials are invalid', () => { cy.visit('/signin?useOktaClassic=true'); cy.get('input[name=email]').type('invalid@doesnotexist.com'); cy.get('input[name=password]').type('password'); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Email and password don’t match'); }); it('correctly signs in an existing user', () => { // 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); }); cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.visit('/signin?useOktaClassic=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', 'https://m.code.dev-theguardian.com/'); }); }); it('respects the returnUrl query param', () => { // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', returnUrl, (req) => { req.reply(200); }); cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.visit( `/signin?returnUrl=${encodeURIComponent(returnUrl)}&useOktaClassic=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('eq', returnUrl); }); }); it('hits access token rate limit and recovers token after timeout', () => { // 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); }); cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.visit('/signin?useOktaClassic=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', 'https://m.code.dev-theguardian.com/'); // We visit reauthenticate here because if we visit /signin or // /register, the logged in user guard will redirect us away before // the ratelimiter has a chance to work cy.visit('/reauthenticate'); cy.contains('Sign'); Cypress._.times(6, () => cy.reload()); cy.contains('Rate limit exceeded'); }); }); it('Sends a user with an unvalidated email a reset password email on sign in', () => { cy .createTestUser({ isUserEmailValidated: false, }) ?.then(({ emailAddress, finalPassword }) => { const timeRequestWasMade = new Date(); cy.visit('/signin?useOktaClassic=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', '/signin/email-sent'); cy.contains( 'For security reasons we need you to change your password.', ); cy.contains(emailAddress); cy.contains('send again'); cy.contains('try another address'); // Ensure the user's authentication cookies are not set cy.getCookie('idx').then((idxCookie) => { expect(idxCookie).to.not.exist; cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /reset-password\/([^"]*)/, ).then(({ links, body, token }) => { 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'), ); expect(resetPasswordLink?.href ?? '').to.have.string( 'reset-password', ); cy.visit(`/reset-password/${token}`); cy.contains(emailAddress); cy.contains('Create new password'); }); }); }); }); it('sets emailValidated flag on oauth callback', () => { // this is a specific test case for new user registrations in Okta // In Okta new social registered users are added to the GuardianUser-EmailValidated group // by default, but the custom emailValidated field is not defined/set to false // this causes problems in legacy code, where the emailValidated flag is not set but the group is // so we need to set the flag to true when the user is added to the group // we do this on the oauth callback route /oauth/authorization-code/callback // where we update the user profile with the emailValidated flag if the user is in the GuardianUser-EmailValidated group but the emailValidated is falsy // This test checks this behaviour by first getting a user into this state // i.e user.profile.emailValidated = false, and user groups has GuardianUser-EmailValidated // first we have to get the id of the GuardianUser-EmailValidated group cy.findEmailValidatedOktaGroupId().then((groupId) => { // next we create a test user cy.createTestUser({}).then(({ emailAddress, finalPassword }) => { // we get the user profile object from Okta cy.getTestOktaUser(emailAddress).then((user) => { const { id, profile } = user; // check the user profile has the emailValidated flag set to false expect(profile.emailValidated).to.be.false; // next check the user groups cy.getOktaUserGroups(id).then((groups) => { // make sure the user is not in the GuardianUser-EmailValidated group const group = groups.find((g) => g.id === groupId); expect(group).not.to.exist; // and add them to the group if this is the case cy.addOktaUserToGroup(id, groupId); // at this point the user is in the correct state // so we attempt to sign them 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'); // at this point the oauth callback route will have run, so we can recheck the user profile to see if the emailValidated flag has been set cy.getTestOktaUser(id).then((user) => { const { profile } = user; expect(profile.emailValidated).to.be.true; }); // and the user should also be in the group cy.getOktaUserGroups(id).then((groups) => { const group = groups.find((g) => g.id === groupId); expect(group).to.exist; }); }); }); }); }); }); }); context('Okta IDX API Sign In with Password', () => { it('ACTIVE user - email + password authenticators - successfully sign in', () => { // 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); }); cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.visit('/signin?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', 'https://m.code.dev-theguardian.com/'); }); }); it('ACTIVE user - email + password authenticators - successfully sign in - preserve returnUrl', () => { // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept('GET', returnUrl, (req) => { req.reply(200); }); cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.visit( `/signin?returnUrl=${encodeURIComponent(returnUrl)}&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('eq', returnUrl); }); }); it('ACTIVE user - email + password authenticators - successfully sign in - preserve fromURI', () => { const encodedReturnUrl = encodeURIComponent(returnUrl); const appClientId = 'appClientId1'; const fromURI = '/oauth2/v1/authorize'; // Intercept the external redirect page. // We just want to check that the redirect happens, not that the page loads. cy.intercept( 'GET', `https://${Cypress.env('BASE_URI')}${decodeURIComponent(fromURI)}`, (req) => { req.reply(200); }, ); cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.visit( `/signin?returnUrl=${encodeURIComponent(returnUrl)}&usePasswordSignIn=true`, ); cy.visit( `/signin?returnUrl=${encodedReturnUrl}&appClientId=${appClientId}&fromURI=${fromURI}&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(); // fromURI redirect cy.url().should('contain', decodeURIComponent(fromURI)); }); }); it('ACTIVE user - password authenticator only - send OTP reset password security email', () => { const emailAddress = randomMailosaurEmail(); cy.visit(`/register/email`); const timeRequestWasMade = new Date(); cy.get('input[name=email]').type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Enter your code'); cy.contains(emailAddress); cy.checkForEmailAndGetDetails(emailAddress, 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'); // make sure we don't use a passcode // we instead reset their password using classic flow to set a password cy.visit('/reset-password?useOktaClassic=true'); const timeRequestWasMade = new Date(); cy.get('input[name=email]').clear().type(emailAddress); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, timeRequestWasMade, /\/set-password\/([^"]*)/, ).then(({ links, body }) => { expect(body).to.have.string('Welcome back'); expect(body).to.have.string('Create password'); expect(links.length).to.eq(2); const setPasswordLink = links.find((s) => s.text?.includes('Create password'), ); cy.visit(setPasswordLink?.href as string); const password = randomPassword(); cy.get('input[name=password]').type(password); cy.get('[data-cy="main-form-submit-button"]') .click() .should('be.disabled'); cy.contains('Password created'); cy.contains(emailAddress.toLowerCase()); // setup complete, now sign in cy.visit('/signin?usePasswordSignIn=true'); cy.contains('Sign in with a different email').click(); cy.get('input[name=email]').clear().type(emailAddress); cy.get('input[name=password]').type(password); const timeRequestWasMade = new Date(); cy.get('[data-cy="main-form-submit-button"]').click(); cy.checkForEmailAndGetDetails( emailAddress, 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', '/signin/email-sent'); cy.contains('Enter your verification code'); cy.contains( 'For security reasons we need you to change your password.', ); cy.contains('Submit verification code'); cy.get('input[name=code]').clear().type(code!); cy.url().should('contain', '/set-password'); cy.get('input[name="password"]').type(randomPassword()); cy.get('button[type="submit"]').click(); cy.url().should('contain', '/set-password/complete'); }); }); }, ); }); it('ACTIVE user - email + password authenticators - shows authentication error when password incorrect', () => { // 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); }); cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.visit('/signin?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.contains('Email and password don’t match'); }); }); it('NON-EXISTENT user - shows authentication error in all scenarios', () => { cy.visit('/signin?usePasswordSignIn=true'); cy.get('input[name=email]').type('invalid@doesnotexist.com'); cy.get('input[name=password]').type('password'); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Email and password don’t match'); }); it('NON-ACTIVE user - shows authentication error', () => { // 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); }); cy .createTestUser({ isGuestUser: true }) ?.then(({ emailAddress, finalPassword }) => { cy.visit('/signin?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.contains('Email and password don’t match'); }); }); it('SOCIAL user - sets emailValidated flag on oauth callback', () => { // this is a specific test case for new user registrations in Okta // In Okta new social registered users are added to the GuardianUser-EmailValidated group // by default, but the custom emailValidated field is not defined/set to false // this causes problems in legacy code, where the emailValidated flag is not set but the group is // so we need to set the flag to true when the user is added to the group // we do this on the oauth callback route /oauth/authorization-code/callback // where we update the user profile with the emailValidated flag if the user is in the GuardianUser-EmailValidated group but the emailValidated is falsy // This test checks this behaviour by first getting a user into this state // i.e user.profile.emailValidated = false, and user groups has GuardianUser-EmailValidated // first we have to get the id of the GuardianUser-EmailValidated group cy.findEmailValidatedOktaGroupId().then((groupId) => { // next we create a test user cy.createTestUser({}).then(({ emailAddress, finalPassword }) => { // we get the user profile object from Okta cy.getTestOktaUser(emailAddress).then((user) => { const { id, profile } = user; // check the user profile has the emailValidated flag set to false expect(profile.emailValidated).to.be.false; // next check the user groups cy.getOktaUserGroups(id).then((groups) => { // make sure the user is not in the GuardianUser-EmailValidated group const group = groups.find((g) => g.id === groupId); expect(group).not.to.exist; // and add them to the group if this is the case cy.addOktaUserToGroup(id, groupId); // at this point the user is in the correct state // so we attempt to sign them 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'); // at this point the oauth callback route will have run, so we can recheck the user profile to see if the emailValidated flag has been set cy.getTestOktaUser(id).then((user) => { const { profile } = user; expect(profile.emailValidated).to.be.true; }); // and the user should also be in the group cy.getOktaUserGroups(id).then((groups) => { const group = groups.find((g) => g.id === groupId); expect(group).to.exist; }); }); }); }); }); }); it('shows reCAPTCHA errors when the user tries to sign in offline and allows sign in when back online', () => { // 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); }); cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.visit('/signin?usePasswordSignIn=true'); cy.interceptRecaptcha(); cy.get('input[name=email]').type(emailAddress); cy.get('input[name=password]').type(finalPassword); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Google reCAPTCHA verification failed.'); cy.contains('If the problem persists please try the following:'); cy.get('[data-cy="main-form-submit-button"]').click(); cy.contains('Google reCAPTCHA verification failed.').should( 'not.exist', ); cy.url().should('include', 'https://m.code.dev-theguardian.com/'); }); }); }); context('Social sign in', () => { it('redirects correctly for social sign in', () => { cy.visit(`/signin?returnUrl=${encodeURIComponent(returnUrl)}`); cy.get('[data-cy="google-sign-in-button"]').should( 'have.attr', 'href', `/signin/google?returnUrl=${encodeURIComponent(returnUrl)}`, ); cy.get('[data-cy="apple-sign-in-button"]').should( 'have.attr', 'href', `/signin/apple?returnUrl=${encodeURIComponent(returnUrl)}`, ); }); it('shows an error message and information paragraph when accountLinkingRequired error parameter is present', () => { cy.visit('/signin?error=accountLinkingRequired'); cy.contains( 'We could not sign you in with your social account credentials. Please sign in with your email below.', ); cy.contains('Social sign-in unsuccessful'); }); it('does not display social buttons when accountLinkingRequired error parameter is present', () => { cy.visit('/signin?error=accountLinkingRequired'); cy.get('[data-cy="google-sign-in-button"]').should('not.exist'); cy.get('[data-cy="apple-sign-in-button"]').should('not.exist'); }); }); context('Okta session refresh', () => { it('refreshes a valid Okta session', () => { // 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((orignalIdxCookie) => { expect(orignalIdxCookie).to.exist; // we want to check the cookie is being set as a persistent cookie and not a session cookie, hence the expiry check expect(orignalIdxCookie?.expiry).to.exist; // Refresh our user session cy.visit( `/signin/refresh?returnUrl=${encodeURIComponent( `https://${Cypress.env('BASE_URI')}/welcome/review`, )}`, ); cy.url().should('include', '/welcome/review'); // Get the refreshed session data cy.getCookie('idx').then((newIdxCookie) => { expect(newIdxCookie).to.exist; // `idx` cookie doesn't have same value as original when refreshed, which is different to the Okta Classic `idx` cookie expect(newIdxCookie?.value).to.not.equal(orignalIdxCookie?.value); // we want to check the cookie is being set as a persistent cookie and not a session cookie, hence the expiry check expect(newIdxCookie?.expiry).to.exist; if (newIdxCookie?.expiry && orignalIdxCookie?.expiry) { expect(newIdxCookie?.expiry).to.be.greaterThan( orignalIdxCookie?.expiry, ); } }); }); }, ); }); it('sends a client with the Okta cookie and an invalid Okta session to the redirectUrl', () => { // 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((idxCookie) => { // Close the user's current session in Okta cy.closeCurrentOktaSession({ idx: idxCookie?.value, }).then(() => { // closeCurrentOktaSession blanked the IDX cookie, so we // need to set it back to the old value if (idxCookie) { cy.setCookie('idx', idxCookie.value, { domain: Cypress.env('BASE_URI'), hostOnly: true, httpOnly: true, sameSite: 'no_restriction', secure: true, }); } else { throw new Error('idx cookie not found'); } // Refresh our user session cy.visit( `/signin/refresh?returnUrl=${encodeURIComponent( `https://${Cypress.env('BASE_URI')}/reset-password`, )}`, ); cy.url().should('include', '/reset-password'); }); }); }, ); }); it('sends a client without Okta cookies to /signin', () => { // 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'); // Delete all cookies (Okta and IDAPI) cy.clearCookies(); // Visit the refresh endpoint cy.visit( `/signin/refresh?returnUrl=${encodeURIComponent( `https://${Cypress.env('BASE_URI')}/welcome/review`, )}`, ); cy.url().should('include', '/signin'); cy.getCookie('idx').should('not.exist'); cy.getCookie('sc_gu_u').should('not.exist'); cy.getCookie('sc_gu_la').should('not.exist'); }, ); }); it('leaves the last access cookie unchanged when refreshing a valid Okta session', () => { // 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('SC_GU_LA').then((originalLastAccessCookie) => { cy.getCookie('SC_GU_U').then((originalSecureIdapiCookie) => { expect(originalLastAccessCookie).to.exist; expect(originalSecureIdapiCookie).to.exist; // Refresh our user session cy.visit( `/signin/refresh?returnUrl=${encodeURIComponent( `https://${Cypress.env('BASE_URI')}/welcome/review`, )}`, ); cy.url().should('include', '/welcome/review'); // Expect the last access cookie to be unchanged cy.getCookie('SC_GU_LA').then((lastAccessCookie) => { expect(lastAccessCookie).to.exist; expect(lastAccessCookie?.value).to.equal( originalLastAccessCookie?.value, ); expect(lastAccessCookie?.expiry).to.equal( originalLastAccessCookie?.expiry, ); }); // Expect other Idapi cookies to have changed cy.getCookie('SC_GU_U').then((secureIdapiCookie) => { expect(secureIdapiCookie).to.exist; expect(secureIdapiCookie?.value).not.to.equal( originalSecureIdapiCookie?.value, ); if ( secureIdapiCookie?.expiry && originalSecureIdapiCookie?.expiry ) { expect(secureIdapiCookie?.expiry).to.be.greaterThan( originalSecureIdapiCookie?.expiry, ); } }); }); }); }, ); }); }); 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 sign in again cy.visit( `/signin?returnUrl=${encodeURIComponent( `https://${Cypress.env('BASE_URI')}/welcome/review`, )}`, ); cy.url().should('include', '/signin'); 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'); }); }, ); }); }); context('Okta missing legacyIdentityId', () => { it('Adds the missing legacyIdentityId to the user on authentication', () => { cy .createTestUser({ isUserEmailValidated: true, }) ?.then(({ emailAddress, finalPassword }) => { cy.getTestOktaUser(emailAddress).then((user) => { const originalLegacyIdentityId = user.profile.legacyIdentityId; expect(originalLegacyIdentityId).to.not.be.undefined; // Remove the legacyIdentityId from the user cy.updateOktaTestUserProfile(emailAddress, { legacyIdentityId: null, }).then(() => { cy.getTestOktaUser(emailAddress).then((user) => { expect(user.profile.legacyIdentityId).to.be.undefined; const postSignInReturnUrl = `https://${Cypress.env( 'BASE_URI', )}/welcome/review`; const visitUrl = `/signin?returnUrl=${encodeURIComponent( postSignInReturnUrl, )}&usePasswordSignIn=true`; cy.visit(visitUrl); 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'); cy.getTestOktaUser(emailAddress).then((user) => { expect(user.profile.legacyIdentityId).to.eq( originalLegacyIdentityId, ); }); }); }); }); }); }); }); });