Search code examples
node.jsenvironment-variablesgithub-actionscypress

Using github actions env vars to run different base Urls in feature and staging for snowflake Cypress test


I have a suite of Cypress tests that all use the same base Url except for one legacy test. The legacy test is using a before hook which has a cy.visit of http://e2etest.dev.my-company.com:8081/company/sign-in. The problem is that this test is running e2etest.dev even when ran against staging.

I created an if statement in the relevant code:

if (Cypress.env('CYPRESS_ENV') === 'test') {
        cy.visit('http://e2etest.dev.my-company.com:8081/company/sign-in');
      } else {
        cy.visit('http://e2etest.staging.my-company.com:8081/company/sign-in');
}

I also have a Github Actions ci.yaml. I do not have an e2e.yaml. The way the ci.yaml works is it takes in the branch name and it runs this:

echo "GITHUB_REF_NAME=${GITHUB_REF_NAME}"
          BUILD_REF="${GITHUB_REF_NAME}"
          FORMATTED_BUILD_REF="$(echo $BUILD_REF | sed 's/[^a-zA-Z0-9]/-/g')"
          VERSION="$(date -u +'%Y%m%d')-$GITHUB_RUN_NUMBER-${GITHUB_SHA:0-7}"
          SERVICE='my-company-pro'
          case "${GITHUB_REF_NAME}" in
            "master")
              BASE_URL="https://e2etest.my-company.com"
              API_HOST="api.my-company.com"
              NAMESPACE="app-prod"
              ;;
            "staging")
              BASE_URL="https://e2etest.staging.my-company.com"
              API_HOST="api.staging.my-company.com"
              NAMESPACE="app-staging"
              CF_WORKER_ENV="staging"
              ;;
            "sandbox")
              BASE_URL="http://e2etest.sandbox.my-company.com"
              API_HOST="api.sandbox.my-company.com"
              NAMESPACE="app-sandbox"
              ;;
            *)
              BASE_URL="https://e2etest.dev.my-company.com:3003"
              API_HOST="api.staging.my-company.com"
              NAMESPACE="app-test"
              CF_WORKER_ENV="test"
              ;;

In the cypress job, I printed out what variables are available and I got this back, indicating I edited the yaml correctly:

Run echo "CF Worker Env: staging" 
CF Worker Env: staging

and

Run echo "CYPRESS_ENV=${CYPRESS_ENV}"
CYPRESS_ENV=staging

These values say test on a feature branch and staging on the staging branch. In Cypress dashboard I can see that on a feature branch, it's going to the if statement for the dev environment and I can see my console.log(Cypress.env('CYPRESS_ENV')) printed out the word test

However, when the test merges into staging in my pipeline it still prints the word test and goes to the dev environment.

Here is my cypress.config.ts

import { defineConfig } from 'cypress';

export default defineConfig({
  chromeWebSecurity: false,
  pageLoadTimeout: 60000,
  blockHosts: '*datadoghq.com',
  projectId: '5cwnfh',
  defaultCommandTimeout: 40000,
  requestTimeout: 40000,
  responseTimeout: 40000,
  execTimeout: 15000,
  taskTimeout: 15000,
  viewportWidth: 1440,
  viewportHeight: 900,
  numTestsKeptInMemory: 0,
  retries: {
    runMode: 2,
  },
  env: {
    COMPANY_API_BASE_URL: 'api.staging.my-company.com',
    CYPRESS_ENV: 'test',
  },
  e2e: {
    fixturesFolder: 'fixtures',
    baseUrl: 'https://e2etest.dev.my-company.com:3003',
    specPattern: 'cypress/e2e/**/*.{ts,tsx}',
  },

  component: {
    devServer: {
      framework: 'next',
      bundler: 'webpack',
    },
  },
});

I think the test is failing in CI because of my CYPRESS_ENV I put in my cypress.config.ts while I was troubleshooting. However, if I take out the CYPRESS_ENV from my config.ts, the test goes to the else block and runs against staging when I run it locally because in the console.log when I'm running locally, it's printing out "undefined"

How do I make Cypress run the 'test' env for CYPRESS_ENV locally, the 'test' env for CYPRESS_ENV when GITHUB_REF is not staging in CI, and the 'staging' env for CYPRESS_ENV when GITHUB_REF is staging in CI?

In other projects, I have a command in the cypress job in CI where I can adjust the values in command line but this test runs cypress automatically. Here is my cypress job in CI:

  cypress-test:
    needs: [workflow-info, build]
    runs-on: ubuntu-latest
    env:
      WORKER_ENV: ${{ needs.workflow-info.outputs.cf-worker-env }}
      BASE_URL: ${{ needs.workflow-info.outputs.base-url }}
      API_BASE_URL: ${{ needs.workflow-info.outputs.api-host }}
      CYPRESS_ENV: ${{ needs.workflow-info.outputs.cf-worker-env }} 
    strategy:
      fail-fast: false
      matrix:
        containers: [1, 2, 3, 4, 5, 6, 7, 8, 9]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          cache: 'yarn'
          node-version: '20.9.0'
      - name: Install Specific Chrome Version
        run: |
          sudo apt-get install -y wget
          sudo wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
          sudo apt-get install ./google-chrome-stable_current_amd64.deb
      - name: Get yarn cache directory path
        id: yarn-cache-dir-path
        shell: bash
        run: |
          echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
      - uses: actions/cache@v4
        with:
          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
          key: yarn-${{ hashFiles('yarn.lock') }}
          restore-keys: |
            yarn-
      - name: Restore next build and deps
        uses: actions/cache@v4
        with:
          path: |
            ./next/.next
            ./next/node_modules
            ./legacy/node_modules
            ./node_modules
            ~/.cache/Cypress
          key: next-build-${{ github.sha }}
      - name: Setup /etc/hosts
        run: sudo echo "127.0.0.1 e2etest.dev.my-company.com" | sudo tee -a /etc/hosts
      - name: Print CF Worker Env
        run: |
          echo "CF Worker Env: ${{ needs.workflow-info.outputs.cf-worker-env }}" 
      - name: Print CYPRESS_ENV
        run: echo "CYPRESS_ENV=${CYPRESS_ENV}" 
    
      - name: Run App
        run: yarn dev &
      - name: Run Cypress Tests
        uses: cypress-io/github-action@v6
        with:
          browser: chrome
          working-directory: next
          record: true
          parallel: true
          config: baseUrl=${{ needs.workflow-info.outputs.base-url }}
          ci-build-id: ${{ needs.workflow-info.outputs.cypress-run-id }}-${{ github.run_attempt }}
        env:
          CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_DASHBOARD_KEY_NEXT }}
          DEBUG: '@cypress/github-action'
          CYPRESS_ENV: ${{ needs.workflow-info.outputs.cf-worker-env }}  

Solution

  • The environment var CYPESS_ENV does not find it's way into the test code, most likely because env is a reserved word and is therefore rejected.

    Experimenting

    In a clean project (Windows syntax),

    // package.json
    
    {
      "dependencies": {
        "cypress": "^13.11.0"
      },
      "scripts": {
        "start1": "SET CYPRESS_ENV=legacy && npx cypress open",
        "start2": "SET CYPRESS_CYPRESS_ENV=legacy && npx cypress open",
      }
    }
    
    it('logs all Cypress.env()', () => {
      console.log('Cypress.env()', Cypress.env())
    })
    

    Running yarn start1 with CYPRESS_ENV=legacy, the above test logs empty environment object:

    Cypress.env() ➤ {}

    Running yarn start2 with CYPRESS_CYPRESS_ENV=legacy, the above test logs the environment value you want:

    Cypress.env() ➤ { CYPRESS_ENV: 'legacy ' }

    Note there is an extra space at the end of the value for some weird reason.

    If you double-prefix the environment variable, then your before() code should work with a .trim() in the if() statement:

    if (Cypress.env('CYPRESS_ENV').trim() === 'legacy') {
      cy.visit('http://e2etest.dev.my-company.com:8081/company/sign-in');
    } else {
      cy.visit('http://e2etest.staging.my-company.com:8081/company/sign-in');
    }