How to log in to cognito Google Oauth using Cypress?
Asked Answered
B

2

0

I want to test an app that only has Google Oauth Login via AWS Cognito. Lots of guides on how to use cypress to programatically login to Cognito using AWS Amplify with a username and password, but cannot find anything on how to do it with Google Oauth.

Im trying to use cypress to click the buttons to authenticate but I think there is a click forgery protection on Google.

I have also been able to use this cypress documentation to login to Google directly and get a jwt into session storage but not sure if there is a way to pass this to Cognito.

Breastpin answered 10/11, 2022 at 23:51 Comment(1)
AWS Amplify Federated signin seems tantalising docs.amplify.aws/lib/auth/advanced/q/platform/js/… but so far have not been able to pass it the google token and get a response.Breastpin
B
-1

I tried many approaches to this including getting oauth token from Google and trying to exchange that manually with Cognito for the token I needed for AWS API Gateway. I also tried cypress-social-logins without success (because of this bug)

Finally I just wrote my own cypress steps to log me into my app with a valid session. NOTE THIS WILL NOT WORK IN A CI/CD because it will probably trigger Google validations and so it is a semi-automated solution.

If in doubt I recommend Tom Roman's answer below about creating a pre-prod environment in cognito that allows username/password login instead of messing about with google login.

// /support/login.js
Cypress.Commands.add('loginByGoogle', () => {
        
        cy.visit('http://localhost:3030')

        cy.origin('https://somecognitouserpool.auth.eu-west-1.amazoncognito.com', () => {
            cy.contains('button', 'Continue with Google')
            .click({force: true}) 
        })
        
        cy.origin('https://accounts.google.com', () => {
            const resizeObserverLoopError = /^[^(ResizeObserver loop limit exceeded)]/;
            Cypress.on('uncaught:exception', (err) => {
                /* returning false here prevents Cypress from failing the test */
                if (resizeObserverLoopError.test(err.message)) {
                return false;
                }
            });
            cy.get('input#identifierId[type="email"]')
            .type(Cypress.env('googleSocialLoginUsername'))
            .get('button[type="button"]').contains('Next')
            .click()
            .get('div#password input[type="password"]')
            .type(Cypress.env('googleSocialLoginPassword'))
            .get('button[type="button"]').contains('Next')
            .click();
        });
    
});
// /e2e/sometest.cy.js
before(() => {
  cy.loginByGoogle();
});

describe('E2E testing', () => {
  it('should now have a session', () => {
  })
});

You also need a .env file (because you don't want to be saving your google credentials into github)

GOOGLE_USERNAME = ''
GOOGLE_PASSWORD = ''

You also need two experimental flags (as of 14th Nov 2022)

// cypress.config.js
const { defineConfig } = require('cypress');
require('dotenv').config()

module.exports = defineConfig({
  env: {
    googleSocialLoginUsername: process.env.GOOGLE_USERNAME,
    googleSocialLoginPassword: process.env.GOOGLE_PASSWORD
  },
  e2e: {
    experimentalSessionAndOrigin: true,
    experimentalModifyObstructiveThirdPartyCode: true
  }
})

Here is my package.json so that you can see the exact packages I am using. In particular I added the flags --headed --no-exit in order to complete 2 factor authentication manually as necessary. I have not yet figured out how to stop Google asking for this every time.

{
  "name": "docs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "http-server . -p 3030",
    "cy:run": "cypress run --headed --no-exit",
    "test": "start-server-and-test start http://localhost:3030 cy:run"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "cypress": "^11.0.1",
    "start-server-and-test": "^1.14.0"
  },
  "dependencies": {
    "dot-env": "^0.0.1",
    "dotenv": "^16.0.3"
  }
}
Breastpin answered 14/11, 2022 at 17:34 Comment(0)
W
1

If you're doing end to end testing, then the simplest way would be to have another non prod staging environment without the Google Oauth login in Cognito, and instead the username password login you mentioned that has working examples.

This is also a good idea, as you shouldn't be using your production user system in testing anyway.

Woodcutter answered 11/11, 2022 at 0:21 Comment(1)
Yeah this is a small app for only 100 business users and we dont want the cost of running a pre-production duplicate.Breastpin
B
-1

I tried many approaches to this including getting oauth token from Google and trying to exchange that manually with Cognito for the token I needed for AWS API Gateway. I also tried cypress-social-logins without success (because of this bug)

Finally I just wrote my own cypress steps to log me into my app with a valid session. NOTE THIS WILL NOT WORK IN A CI/CD because it will probably trigger Google validations and so it is a semi-automated solution.

If in doubt I recommend Tom Roman's answer below about creating a pre-prod environment in cognito that allows username/password login instead of messing about with google login.

// /support/login.js
Cypress.Commands.add('loginByGoogle', () => {
        
        cy.visit('http://localhost:3030')

        cy.origin('https://somecognitouserpool.auth.eu-west-1.amazoncognito.com', () => {
            cy.contains('button', 'Continue with Google')
            .click({force: true}) 
        })
        
        cy.origin('https://accounts.google.com', () => {
            const resizeObserverLoopError = /^[^(ResizeObserver loop limit exceeded)]/;
            Cypress.on('uncaught:exception', (err) => {
                /* returning false here prevents Cypress from failing the test */
                if (resizeObserverLoopError.test(err.message)) {
                return false;
                }
            });
            cy.get('input#identifierId[type="email"]')
            .type(Cypress.env('googleSocialLoginUsername'))
            .get('button[type="button"]').contains('Next')
            .click()
            .get('div#password input[type="password"]')
            .type(Cypress.env('googleSocialLoginPassword'))
            .get('button[type="button"]').contains('Next')
            .click();
        });
    
});
// /e2e/sometest.cy.js
before(() => {
  cy.loginByGoogle();
});

describe('E2E testing', () => {
  it('should now have a session', () => {
  })
});

You also need a .env file (because you don't want to be saving your google credentials into github)

GOOGLE_USERNAME = ''
GOOGLE_PASSWORD = ''

You also need two experimental flags (as of 14th Nov 2022)

// cypress.config.js
const { defineConfig } = require('cypress');
require('dotenv').config()

module.exports = defineConfig({
  env: {
    googleSocialLoginUsername: process.env.GOOGLE_USERNAME,
    googleSocialLoginPassword: process.env.GOOGLE_PASSWORD
  },
  e2e: {
    experimentalSessionAndOrigin: true,
    experimentalModifyObstructiveThirdPartyCode: true
  }
})

Here is my package.json so that you can see the exact packages I am using. In particular I added the flags --headed --no-exit in order to complete 2 factor authentication manually as necessary. I have not yet figured out how to stop Google asking for this every time.

{
  "name": "docs",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "http-server . -p 3030",
    "cy:run": "cypress run --headed --no-exit",
    "test": "start-server-and-test start http://localhost:3030 cy:run"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "cypress": "^11.0.1",
    "start-server-and-test": "^1.14.0"
  },
  "dependencies": {
    "dot-env": "^0.0.1",
    "dotenv": "^16.0.3"
  }
}
Breastpin answered 14/11, 2022 at 17:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.