javascriptcypressyarnpkgvisual-testingpercy

NodeJS: NOT able to set PERCY_TOKEN via package script with start-server-and-test


I have been trying really hard to set the PERCY_TOKEN on a local test run according the official guideline from percy and trigger it via yarn.

The guideline says:

$ PERCY_TOKEN=aaabbbcccdddeeefff PERCY_BRANCH=local npm test

My attempt right now looks like this:

package.json


...
"scripts": {
    "start": "react-scripts -r @cypress/instrument-cra start",
    "start:silent": "BROWSER=none yarn start",
    "start:server": "start-server-and-test start:silent http://localhost:3000",
    "build": "react-scripts build",
    "eject": "react-scripts eject",
    "envGenerateExample": "cat .env | sed 's/=.*/=/g' > .env.example",
    "jest:test": "react-scripts test --env=jest-environment-jsdom-sixteen",
    "cy:run": " 'yarn start:server './node_modules/.bin/cypress run'",
    "cy:open": "yarn start:server './node_modules/.bin/cypress open'",
    "cy:ci": "yarn start:server cy:chrome",
    "cy:chrome": "cypress run --browser chrome --record",
    "percy:exec": "yarn percy exec -- cypress run",
    "cy:percy": "yarn start:server percy:exec",
    "percy:local": "PERCY_TOKEN=$(grep 'PERCY_TOKEN.*' .env | sed 's/.*=//'); PERCY_BRANCH=local;",
    "cy:percy:local": "yarn percy:local && yarn start:server percy:exec"
  },
...
$ yarn cy:percy:local

Compiled successfully!

You can now view playground in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.1.163:3000

Note that the development build is not optimized.
To create a production build, use yarn build.

...

> playground@0.2.0 percy:exec /Users/norfeldt/Repos/playground
> yarn percy exec -- cypress run

warning From Yarn 1.0 onwards, scripts don't require "--" for options to be forwarded. In a future version, any explicit "--" will be forwarded as-is to the scripts.
$ /Users/norfeldt/Repos/playground/node_modules/.bin/percy exec cypress run
 ›   Warning: Skipping visual tests. PERCY_TOKEN was not provided.
...

TL;DR solution

package.json


...
"scripts": {
    "start": "react-scripts -r @cypress/instrument-cra start",
    "start:silent": "BROWSER=none yarn start",
    "start:server": "start-server-and-test start:silent http://localhost:3000",
    ...
    "percy:local": "PERCY_TOKEN=$(grep 'PERCY_TOKEN.*' .env | sed 's/.*=//') PERCY_BRANCH=local yarn start:server 'percy exec cypress run'"
  },
...

Solution

  • yarn internally uses sh to execute the commands given in the scripts (cmd in case of windows) - Source. This is very similar to what npm does as well.

    Here && is handled by a shell, so your command yarn percy:local && yarn start:server percy:exec is run as 2 separate child processes. This means yarn percy:local runs in a process and sets the env variables as desired in its context but the second process which is running yarn start:server percy:exec has no idea about the env variables set by process 1.

    Lets see how OS X handles this:

    1. With &&
    sh -c 'PERCY_TOKEN=asdfasdf; PERCY_BRANCH=local' &&  sh -c 'echo $PERCY_TOKEN'
    

    This prints nothing

    1. Without &&
    sh -c 'PERCY_TOKEN=asdfasdf; PERCY_BRANCH=local echo $PERCY_TOKEN'
    

    This prints asdfasdf

    I think removing the && in the cy:percy:local should fix your issue.

    Edit: Solution for your particular situation as discussed in comments

    As explained in the 2nd point of this answer: stackoverflow.com/a/37141993/8266093 I would suggest you run this script in the format ENV_KEY1=value1 ENV_KEY2=value2 command which in your case becomes PERCY_TOKEN=$(grep 'PERCY_TOKEN.*' .env | sed 's/.*=//') PERCY_BRANCH=local yarn percy exec cypress run. Along with this, you can add your start-server yarn command as well if running it separately is not a solution for you.