TypeScript - How to access constants based on environment? Like Cypress.env() outside of Cypress

Viewed 74

Let's say I have this API test and the URL and Credentials differ between production and development environments:

 before("Get auth token", async () => {
    await spec().post(`${baseUrl}/auth`)
      .withBody(
        {
          email: "testing+standard@test.com",
          password: "test"
        }
      )
      .expectStatus(200)
      .expect((ctx) => {
        expect(ctx.res.body.token).to.be.a("string")
        state.token = ctx.res.body.token
      })
    }
  );

Now with Cypress tests you can have a json config file like this, one for each environment:

{
    "env": {
        "baseUrl": "example",
        "standardUserEmail": "testing+standard@test.com",
        "standardUserPassword": "test"
    }
}

Then access it like so:

cy.request({
      method: "POST",
      url: `${Cypress.env("baseUrl")}/auth`,
    })

How does one achieve something like this without using Cypress? A .env file doesn't solve this problem exactly and I also don't need one as I want the values stored in the repo.

Answer (TypeScript version):

interface Environment {
    baseUrl: string;
    standardUserEmail: string;
    standardUserPassword: string
} 

type Environments = {
    development: Environment
    production: Environment
}

// Define environments with the relevant data as a map
const environments: Environments = {
    development:  {
        baseUrl: 'https://example.com',
        standardUserEmail: 'testing+standard@example.com',
        standardUserPassword: 'example',
    },
    production: {
        baseUrl: '',
        standardUserEmail: '',
        standardUserPassword: '',
    },
}

// Get the environment name from the command line
// or default to development
const getEnvironmentData = (): Environment => {
    const environment = process.env.ENVIRONMENT || 'development';
    console.log(`Using environment: ${environment}`);
    // Get the environment data from the map
    return environments[environment as keyof Environments]
};

// Export the environment data
export = getEnvironmentData()

Then use like this:

import 'mocha';
import { spec, request } from "pactum";
import { expect } from "chai"
import config from "../../config"

describe('Example Test API', function () {
  const state = {
    token: "",
  };

  before("Get auth token", async () => {
     request.setBaseUrl(config.baseUrl)
     await spec().post('/auth')
      .withBody(
        {
          email: config.standardUserEmail,
          password: config.standardUserPassword
        }
      )
      .expectStatus(200)
      .expect((ctx) => {
        expect(ctx.res.body.token).to.be.a("string")
        state.token = ctx.res.body.token
      })
    }
  );
2 Answers

In your first example, looks like you are using PactumJS. If it's that you want to support multiple environments and be able to easily which between them, you can use a combination of environmental variables and a map of your environments, similar to how it was defined in Cypress.

// define your environments with the relevant data as a map
const environments = {
    development: {
        baseUrl: 'http://httpbin.org',
        standardUserEmail: 'dev+test@email.com',
        standardUserPassword: 'dev-test-password',
    },
    staging: {
        baseUrl: 'https://staging.example.com',
        standardUserEmail: 'stg+test@email.com',
        standardUserPassword: 'stg-test-password',
    },
    production: {
        baseUrl: 'https://example.com',
        standardUserEmail: 'prod+test@email.com',
        standardUserPassword: 'prod-test-password',
    },
}

// get the environment name from the command line
// or default to development
const getEnvironmentData = () => {
    const environment = process.env.ENVIRONMENT || 'development';
    console.log('Using environment: ', environment);
    // get the environment data from the map
    const environmentData = environments[environment];
    return environmentData;
};

// export the environment data
module.exports = {
    environmentData: getEnvironmentData(),
};

Once you have defined your map with all of the relevant data, you can reference them in your tests easily.

const { spec, request } = require('pactum');
const { environmentData } = require('../config');

before(() => {
    request.setBaseUrl(environmentData.baseUrl);
    console.log(environmentData.standardUserEmail);
    console.log(environmentData.standardUserPassword);
});

it('should get a response with status code 200', async () => {
    await spec()
        .get('/status/200')
        .expectStatus(200);
});

And finally, you can then easily switch between your environment data by using an environmental variable.

You will be accessing the variable by using process.env.ENVIRONMENT, which will be mapped back to the variable that you specify before your test command. See the image below:

enter image description here

For a working example: Please see the example project I created on GitHub: https://github.com/dimitriharding/pactumjs-with-dynamic-environtments

Related