Setting Up MSAL Authentication for Cypress Tests in Angular

This guide provides specific steps to set up a Microsoft Authentication Library (MSAL) login for Cypress testing in Angular applications.

Pawan Ghising

3/11/20252 min read

Step 1: Install Required Dependencies

First, ensure you have Cypress installed in your Angular project:

npm install cypress --save-dev

Step 2: Configure Cypress

Create or update your cypress.config.ts file with the following configuration:

import { defineConfig } from 'cypress';

export default defineConfig({

e2e: {

setupNodeEvents(on, config) {

const environmentName = config.env.ENVIRONMENT || 'local';

console.log(`Running tests in ${environmentName} environment`);

// Load environment-specific configurations

const environments = {

local: {

baseUrl: 'http://localhost:4200',

aad_username: 'test@yourdomain.com',

aad_password: 'your-secure-password'

},

dev: {

baseUrl: 'https://dev.yourapplication.com',

// Dev credentials

},

// Other environments

};

const environmentConfig = environments[environmentName] || environments.local;

config.baseUrl = environmentConfig.baseUrl;

config.env = {

...config.env,

...environmentConfig,

};

return config;

},

baseUrl: 'http://localhost:4200',

supportFile: 'cypress/support/commands.ts',

specPattern: 'cypress/e2e/**/*.cy.ts',

viewportWidth: 1280,

viewportHeight: 720,

video: false,

screenshotOnRunFailure: true,

defaultCommandTimeout: 6000,

retries: {

runMode: 2,

openMode: 0,

},

experimentalModifyObstructiveThirdPartyCode: true,

chromeWebSecurity: false // Required for cross-domain operations with Microsoft login

},

});

Step 3: Create MSAL Login Command

In your cypress/support/commands.ts file, add the custom login command:

// Import Cypress types /// <reference types="cypress" /> declare global { namespace Cypress { interface Chainable { loginToAAD(username: string, password: string): Chainable<void>; } } } // MSAL Authentication command Cypress.Commands.add('loginToAAD', (username, password) => { cy.session( [username, password], () => { // Visit your app's login page cy.visit('/login'); // Handle the redirect to Microsoft login cy.origin('login.microsoftonline.com', { args: { username, password } }, ({ username, password }) => { // Enter email cy.get('input[type="email"]').should('be.visible').clear().type(username); cy.get('input[type="submit"]').click(); // Handle password page (may not appear if using a remembered account) cy.get('input[type="password"]').should('be.visible').clear().type(password, { log: false }); cy.get('input[type="submit"]').click(); // Handle "Stay signed in?" prompt cy.get('#idSIButton9').click(); } ); // Verify we have successfully logged in by checking the URL cy.url().should('not.include', 'login.microsoftonline.com'); }, { validate: () => { // Confirm the session is still valid by navigating to a protected route cy.visit('/'); cy.url().should('not.include', 'login.microsoftonline.com'); }, cacheAcrossSpecs: true } ); }); // Make sure this is exported export {};

Step 4: Securely Store Credentials

For local development, store credentials in your environment config. For CI/CD pipelines, use environment variables:

# In your CI/CD pipeline CYPRESS_aad_username=your-test-account@domain.com CYPRESS_aad_password=your-secure-password

Step 5: Use Authentication in Tests

Now use the command in your test files:

describe('Protected Route Tests', () => { beforeEach(() => { // Log in before each test cy.loginToAAD(Cypress.env('aad_username'), Cypress.env('aad_password')); // Navigate to the page under test cy.visit('/events'); }); it('displays the events page correctly', () => { // Your test code here cy.get('[data-cy=events-table]').should('be.visible'); }); });

Step 6: Handle Authentication Timeouts and Retries

If you encounter authentication timeouts, adjust the Cypress timeout settings:

// In cypress.config.ts defaultCommandTimeout: 10000, // Increase timeout for slow auth processes pageLoadTimeout: 30000,

Step 7: Debug Authentication Issues

For debugging authentication issues:

Cypress.Commands.add('loginToAAD', (username, password) => { // Add debug logs cy.log(`Attempting to log in with ${username}`); cy.session( [username, password], () => { // Existing login code // ... // Add screenshots for debugging cy.screenshot('after-login-attempt'); }, { // Existing validation } ); });

Step 8: Optimize Authentication Performance

To speed up your test suite:

  1. Use cacheAcrossSpecs: true to reuse authentication across tests

  2. Create a custom setup for test data to avoid repetitive login operations

  3. Consider grouping tests that require authentication to minimize login operations

Troubleshooting Common Issues

  1. Cross-Origin Errors: Ensure chromeWebSecurity: false is set in your Cypress config

  2. Dynamic UI Changes: Add appropriate waits if Microsoft's login UI changes dynamically

  3. Conditional Elements: Handle cases where certain login screens may or may not appear

  4. MFA Requirements: For accounts with MFA, consider creating dedicated test accounts without MFA

By following these steps, you'll have a robust MSAL authentication setup for your Cypress tests in Angular.