Patrick Clancey
Patrick Clancey

Reputation: 1370

Adding basic auth to all requests in Cypress

I'm a Cypress newbie and need to add basic auth to all cy.visit() calls. The auth credentials are dependent on the deployment (i.e. they are specific to the 'baseUrl' which we set in the environment config files).

Currently, I have;

cy.visit("/", {
  auth: {
    username: '...',
    password: '...'
  }
});

What I want is to move the 'auth' object to the evg config files so I only need cy.visit("/") in the specs.

Upvotes: 2

Views: 15289

Answers (5)

Matt
Matt

Reputation: 27016

The topic is more complex than it might seem to be at first sight. For example

  • How to configure tests to run in different environments (DEV, UAT, PROD)?
  • How to avoid that passwords are revealed (e.g. in the Cypress log) when the test runs?

are a few but there are even more important questions coming up when you dig deeper into this topic. Below I summarized the most important ones and provided some links so you're able to deep dive into the topic.


I found very useful tips in Dr. Gleb Bahmutov's article "Keep passwords secret in E2E tests" regarding how to write code in Cypress that logs in a user in but does not write the password into the log. It also gives hints how to configure and where to store passwords safely.

Key topics in this article are (only short examples given here, there is so much more in the article):

  • Do not hardcode passwords. Use environment variables, e.g.
    const password = Cypress.env('password')
    Then there are several ways where and how to store the value, one is using the cypress.env.json file (as described here). You can find more ways in the link at the end of this answer.

  • Visible password. Avoid logging it by adding the log: false parameter, e.g.
    cy.get('[name=password]').type(password, {log: false})
    If you want to hide a non-password field on screen during the running test, such as the email address etc., add .invoke('attr', 'type', 'password') after the .get(...) statement and before typing, which will mask it on screen

  • Validate password, e.g.
    if (typeof password !== 'string' || !password) { throw new Error('Missing password value, set using CYPRESS_password=...') }

  • Avoid UI login (advanced topic)
    "Find the recipe that matches this method among Cypress Logging in recipes"

  • Continuous integration (advanced topic)
    This topic covers how to use E2E testing in a CICD pipeline.

  • Plugins
    How can they be dangerous? They could reveal your password.

  • Conclusions
    "Keeping sensitive information out of public logs, screenshots and videos is a very important and ongoing concern. Make sure that every commit even if it only changes the tests goes through code review."


More hints regarding about correcty define and use environment variables in tests:

Upvotes: 0

Pankwood
Pankwood

Reputation: 1878

This is how I handled Basic Auth with Cypress using cy.request:

cy.request({
        method:'POST',
        url:'myURL',
        body: {
            Name: name,
            userId: userId,
            languageId: languageId
          },
          headers: {
            authorization: 'Basic lasdkfjlsdyZHRoYXRpa25vdzp'
          },
    }).then(response => {
       expect(response.status).to.equal(201)
        })
    })

Basically, the "headers" object inside the cy.request do the magic.

Upvotes: 0

Vitalina Zdrobău
Vitalina Zdrobău

Reputation: 73

If you plan to reuse the authentification then is better to create a separate method for authentication e.g.:

1. Create a new custom command in `cypress/support/commands.js, since it is loaded before any test files are evaluated via an import statement in your supportFile (cypress/support/index.js by default).

Cypress.Commands.add('login', () => {
    // (you can use the authentification via API request)
    return cy
        .request({
            method: 'POST',
            url: your_url,
            form: true,
            body: {
                username: Cypress.env('username'),
                password: Cypress.env('password'),
                grant_type: 'password',
                client_id: your_clientId,
                client_secret: your_clientSecret,
                scope: 'openid',
            },
        })
})

2. Then use it in your test:

describe('My Test Name', () => {

    before(() => {
        cy.login();
    });

    it('should visit my base URL', () => {
        cy.visit('/');
    });
});

Note 1: Check how to set the environment variables here: Cypress.io: Environments Variables

Note 2: Check how to use the custom commands here: Custom Commands - Correct Usage

Upvotes: 2

Beto Aveiga
Beto Aveiga

Reputation: 3690

If you have HTTP basic auth for all pages add this code to your cypress/support/commands.js:

Cypress.Commands.overwrite('visit',  (originalFn, url, options) => {

options = options || {}

options.auth = {
  username: 'replace_this_with_the_username',
  password: 'replace_this_with_the_password'
}

return originalFn(url, options);
});

Upvotes: 2

Rosen Mihaylov
Rosen Mihaylov

Reputation: 1425

EDIT: since your syntax is correct - I will just share a way I use to do it in my tasks.

If your auth is working correctly you can make custom command - visitAndAuthorise like this for example:

Cypress.Commands.add("shopAdmin_visitAndLogin", (url) => {
    cy.log('shopAdmin_visitAndLogin')
    cy.visit(url)
    cy.get('[data-qa="emailInput"]')
        .type(Cypress.env('credentials').email)
    cy.get('[data-qa="passwordInput"]')
        .type(Cypress.env('credentials').password)
    cy.get('[data-qa="loginButton"]')
        .click()
    cy.get('[data-qa="logOutButton"]')
        .should('be.visible')
})

And your cypress.env.json file would need to include an object for the credentials like this:

{
   "credentials": {
      "email": "[email protected]",
      "password": "myPassword"
   }
}

Or following your syntax:

Cypress.Commands.add("shopAdmin_visitAndLogin", (url) => {
    cy.log('shopAdmin_visitAndLogin')
    cy.visit(url, {
auth: {
    username: Cypress.env('credentials').username,
    password: Cypress.env('credentials').password
  }})
})

Upvotes: 1

Related Questions