I have a cypress.config.ts-file looking like this:

import {defineConfig} from "cypress";

export default defineConfig(
    {
        e2e: {
            baseUrl: 'http://localhost:3000',
        }
    }
    ...
    ...

Problem 1: The application I'm building has to use different ports for different features. Example:

Problem 2: Cypress automatically adds trailing slash to baseUrl, so I can't add the port myself later (inside the individual test), without making some string-manipulation-gymnastics.

So how do I set this up, so I, in the beginning of a test, can define which port should be used? Such as this:

// This doesn't work: 

it('Test feature 1', () => {
    Cypress.env('PORT', 3000);
    cy.request('GET', 'feature-1').as('featureOne')
    ...
    ...
});

it('Test feature 2', () => {
    Cypress.env('PORT', 3002);
    cy.request('GET', 'feature-2').as('featureTwo')
    ...
    ...
});

Solution attempt 1: Leave baseUrl as an empty string

If I let me cypress.config.ts be like this:

import {defineConfig} from "cypress";

export default defineConfig(
    {
        e2e: {
            baseUrl: '',
        }
    }
    ...

Then I can reference the URL fully like this:

it('Test feature 1', () => {
    Cypress.env('PORT', 3000);
    cy.request('GET', 'http://localhost:3000/feature-1').as('featureOne')
    ...
    ...
});

it('Test feature 2', () => {
    Cypress.env('PORT', 3002);
    cy.request('GET', 'http://localhost:3002/feature-2').as('featureTwo')
    ...
    ...
});

It works. But it seems silly.


Solution attempt 2: Fiddle around with cypress.config.ts

I imagined being able to do something like this:

const PORT = process.env.PORT || 3000

export default defineConfig(
    {
        e2e: {
            baseUrl: 'http://localhost' + PORT, 
        }
    }
    ...
    ...

This works, but I'm unable to override the PORT inside of the tests (Cypress.env('PORT', 3002);). I don't know if it's because it runs too late.

So in total, this doesn't work. But it would be smart if it did. :-)

3

There are 3 best solutions below

0
On BEST ANSWER

The switch command is a bit old-fashioned, it is generally considered better to use a mapping object.

If you want to start with something like this in your test

it('tests with staging url', () => {
  cy.setBaseUrl('staging')
  // test code here
})

then the custom command setBaseUrl could look like this

Cypress.Commands.add('setBaseUrl', 
  {prevSubject:false}, 
  (key = 'default') => {
    const baseUrl = Cypress.config('baseUrl') || 'http://localhost:3000/'
    const host = baseUrl.split(':').slice(0,2).join(':')

   const portMapping = {
      'default': 3000,
      'staging': 3001,
      'production': 3002,
      ...Cypress.env('ports')
    }
    const port = portMapping[key]
    if (!port) {
      throw new Error (`Incorrect port, should be one of "${Object.keys(portMapping).join(', ')}"`)
    }

    const newBaseUrl = `${host}:${port}/`
    return Cypress.config('baseUrl', newBaseUrl)
  }
)
  • baseUrl can be set in cypress.config.js, if not it is 'http://localhost:3000/'
  • default port is 3000
  • if you ask for an unknown port in the test, an error is thrown

Example tests

it('tests with default url', () => {
  cy.setBaseUrl()
    .should('eq', 'http://localhost:3000/')
})

it('tests with staging url', () => {
  cy.setBaseUrl('staging')
    .should('eq', 'http://localhost:3001/')
})

it('tests with production url', () => {
  cy.setBaseUrl('production')
    .should('eq', 'http://localhost:3002/')
})

it('tests with unknown url', () => {
  cy.setBaseUrl('mistake')
    .should('eq', 'http://localhost:3002/')
})

Example overwriting ports at the command line

yarn cypress open --env ports={\"staging\":4001,\"production\":4002}
2
On

You can change the baseUrl to anything you want with Cypress.config('baseUrl', something).

// cypress.config.js
const { defineConfig } = require("cypress");
module.exports = defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
  },
})
it('changes the baseUrl', () => {
  Cypress.config('baseUrl', 'http://localhost:3002')
  cy.visit('/');
  cy.url().should('eq', 'http://localhost:3002/')        // passes
})

or

it('changes the baseUrl', () => {
  Cypress.config('baseUrl', 'http://example.com')
  cy.visit('/');
  cy.url().should('eq', 'http://example.com/')         // passes
})
0
On

The solution provided by Charles.de.Pierrefonds lead me to the answer. It was a bit off, compared to what I was actually trying to achieve, since I didn't want to set which environment to test against in the individual test. I want to control that via the cypress.config.ts-file fully, so I easily can run all my tests on staging and then on production straight after, without having to modify the code.

This ended being my solution:

In cypress.config.ts:

export default defineConfig(
    {
        e2e: {
            baseUrl: 'http://localhost:3000',
        }
        ...
        ...

In support/commands.ts:

declare namespace Cypress {
    interface Chainable<Subject = any> {
        setBaseUrlPort(port: number): Chainable<Subject>;
    }
}

Cypress.Commands.add('setBaseUrlPort',
  {prevSubject:false},
  (port:number = 3000) => {
    const baseUrl = Cypress.config('baseUrl') || 'http://localhost:3000/';
    const host = baseUrl.split(':').slice(0,2).join(':');

    const newBaseUrl = `${host}:${port}/`
    return Cypress.config('baseUrl', newBaseUrl)
  }
)

Example test:

it('Test feature 1', () => {
    cy.setBaseUrlPort(3002);

    // baseUrl is automatically prefixed in the request under here,
    // and it resolves to: http://localhost:3002, 
    // in spite of it being http://localhost:3000 in cypress.config.ts
    cy.request('GET', 'feature-1').as('featureOne') 
    cy.get('@featureOne').should((response) => {
        expect(response.status).to.eq(200);
    }
});

To summarize

  • The baseUrl is controlled in the cypress.config.ts-file.
  • The port can be overridden in the individual test