Reduce your test automation execution time by login to your app using aws amplify & Cypress.io
Is your application hosted on AWS cloud & are you responsible for test automation of your application ? then this story is for you !!
Users are created in the AWS cognito User pool and eventually stored in the Database.
Packages needs to be installed : @aws-amplify/auth, @aws-sdk/client-cognito-identity-provider, @aws-sdk/client-rds-data, aws-sdk and @faker-js/faker
let us use the aws sandbox domain name <@simulator.amazonses.com> to create test automation users in the database.
import {
AdminCreateUserCommand,
AdminGetUserCommand,
AdminSetUserPasswordCommand,
CognitoIdentityProviderClient,
} from '@aws-sdk/client-cognito-identity-provider';
import { ExecuteStatementCommand, ExecuteStatementCommandOutput, RDSDataClient } from '@aws-sdk/client-rds-data';
import { faker } from '@faker-js/faker';
import { Auth } from '@aws-amplify/auth';
const userPoolId = process.env.cognitoUserPoolId;
const clientId = process.env.cognitoWebClient;
const dbDatabase = process.env.envAcct;
const { dbClusterArn } = process.env;
const dbClusterSecretArn = process.env.dbSecretArn;
// all the required values for aws configuration should come from environment variables.
const awsConfig = {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
sessionToken: process.env.AWS_SESSION_TOKEN,
region: process.env.AWS_REGION,
UserPoolId: process.env.cognitoUserPoolId,
ClientId: process.env.cognitoWebClient,
};
const awsConfigAuthLogin = {
aws_user_pools_id: userPoolId,
aws_user_pools_web_client_id: clientId,
};
/**
* Create the Cognito IDP client
*/
const cognitoClient = new CognitoIdentityProviderClient(awsConfig);
/**
* Create the RDS Client
*/
const rdsDataClient = new RDSDataClient({
apiVersion: '2018-08-01',
...awsConfig,
});
Auth.configure(awsConfigAuthLogin);
export const createActiveUser = async ({
password,
userRole,
userTeam,
userEmail,
}: {
password: string;
userRole: string;
userTeam: string;
userEmail?: string;
}) => {
const uniqueID = faker.datatype.number({ min: 0, max: 99999999 });
const role = userRole.replace(' ', '_').toLowerCase();
const team = userTeam.replace(' ', '_').toLowerCase();
const activeUserEmail = userEmail || `success+cy-${role}-${team}-active-${uniqueID}@simulator.amazonses.com`;
const firstName = faker.name.firstName();
const lastName = faker.name.lastName();
const params = {
UserPoolId: userPoolId,
Username: activeUserEmail,
MessageAction: 'SUPPRESS',
UserAttributes: [
{
Name: 'email',
Value: `${activeUserEmail}`,
},
{
Name: 'email_verified',
Value: 'true',
},
],
};
const command = new AdminCreateUserCommand(params);
const result = await cognitoClient.send(command);
createdUsernames.push(result?.User?.Username);
// Set a permanent password
const pwcommand = new AdminSetUserPasswordCommand({
UserPoolId: userPoolId,
Username: result?.User?.Username,
Permanent: true,
Password: password,
});
await cognitoClient.send(pwcommand);
const sqlParamsCreateUser = {
secretArn: dbClusterSecretArn,
resourceArn: dbClusterArn,
sql: `INSERT INTO users (username, first_name, last_name, email_address) VALUES (:USERNAME, :FIRST_NAME, :LAST_NAME, :EMAIL) RETURNING *`,
database: dbDatabase,
includeResultMetadata: true,
parameters: [
{ name: 'FIRST_NAME', value: { stringValue: `Test-${firstName}` } },
{ name: 'LAST_NAME', value: { stringValue: `Test-${lastName}` } },
{ name: 'EMAIL', value: { stringValue: activeUserEmail } },
{ name: 'USERNAME', value: { stringValue: result?.User?.Username } },
],
};
const sqlcommand = new ExecuteStatementCommand(sqlParamsCreateUser as any);
const user = await rdsDataClient.send(sqlcommand);
return result;
};
Create a Custom method in commands.js for login, configure a temporary password inside Cypress environment variables.
create a method for login with Auth from aws amplify.
import { Auth } from '@aws-amplify/auth';
export const loginAWS = async ({ userName, password }: { userName: string; password: string }) =>
Auth.signIn(userName, password);
Cypress.Commands.add('login', () => {
cy.task('createActiveUser', { password: Cypress.env('tempPassword'), userRole: role, userTeam: team }).then(
newUser => {
const newUserWithPassword = {
...newUser,
User: { ...newUser.User, password: Cypress.env('tempPassword')},
};
cy.task('loginAWS', {
userName: newUserWithPassword.User.Username,
password: newUserWithPassword.User.password,
role,
}).then(cognitoUser => {
const idToken = cognitoUser.signInUserSession.idToken.jwtToken;
const accessToken = cognitoUser.signInUserSession.accessToken.jwtToken;
const makeKey = name =>
`CognitoIdentityServiceProvider.${cognitoUser.pool.clientId}.${cognitoUser.username}.${name}`;
cy.setLocalStorage(makeKey('accessToken'), accessToken);
cy.setLocalStorage(makeKey('idToken'), idToken);
cy.setLocalStorage(
`CognitoIdentityServiceProvider.${cognitoUser.pool.clientId}.LastAuthUser`,
cognitoUser.username,
);
});
cy.saveLocalStorage();
},
);
});
});
use the login() method in the step definition and it will be automatically redirected to the landing page.
Given(/^I am logged in to the application$/, () => {
cy.login();
cy.visit('/');
});
once the user is logged in, session has to be stored in the local storage for successive logins. JWT token can also extracted from the response once logged in to app.