Playwright: How to pass environment variables from library to pipeline? - reactjs

Background
I have a React/TypeScript project running Playwright integration tests in an Azure DevOps pipeline. The pipeline gets environment variables from an Azure DevOps library.
Problem
I can run the tests locally against my deployed pre-prod environment successfully.
However, the tests fail in the pipeline. They fail because the pipeline cannot read the environment variables I am trying to pass in from the library.
Failing line of code:
await page.getByRole('textbox', { name: 'myVariable' }).fill(process.env.MyVariable as string);
Pipeline error on my environment variable:
How do I pass environment variables from the library to the pipeline such that Playwright can read them?

Solution
I updated my test file name from myFile.spec.ts to myFile.spec.tsx.
I prefixed my environment variables with REACT_APP_.
await page.getByRole('textbox', { name: 'myVariable' }).fill(process.env.REACT_APP_MY_VARIABLE as string);
Now my Azure DevOps pipeline can read the variables in the Azure DevOps library, and the tests succeed!

Related

Consume Cloud Run environment variables inside Nextjs app

I've recently built a Nextjs app, which I am hosting on Google Cloud Run.
My app makes some requests to external APIs from the getStaticProps() method.
I would like to be able to point to a different API host depending on the environment (e.g prod or dev) using environment variables which would be set differently for each environment.
I know I can store these variables in environment specific files like .env.development and .env.production however I would like to be able to store these environment variables in the environment variables field in the Google Cloud console for the cloud run service and skip storing them in the files altogether.
I have tried adding in the variables to Cloud Run, but it does not work. I have also tried prefixing the variables with NEXT_PUBLIC_... With no luck.
Did anyone have any tips on how to accomplish this?
Ok... I think I have figured it out now.
I was using Cloud Builds to build my container, and the container runs npm run build before it runs npm run start.
I assume that my Cloud Run variables aren't available at the point in time when Cloud Build is building the project.
So, I think my solution is prob to try and inject the variables at the point when it is building, using substitution variables.
EDIT: Confirmed. If I start Nextjs in dev mode, such that the page is rendered on the server for each request, then the Cloud Run environment variables are used.
To build the Nextjs app for production, I include the environment variables in the Dockerfile that is built by Cloud Build
EDIT: as request, an example of a dockerfile setting the environment variable:
FROM node:16.13-alpine
RUN mkdir -p /usr/src
WORKDIR /usr/src
COPY . /usr/src
ENV NEXT_PUBLIC_MY_API_HOST='https://some.host.com'
RUN npm install -only=production
RUN npm run build
EXPOSE 3000
CMD npm run start
Then you can just reference the environment variable from within your code using process.env.NEXT_PUBLIC_MY_API_HOST

How to set .env for react app deployed with azure devops pipeline on app service

I developed a pipeline with CI/CD on azure Devops for deploying a React app on Azure web app service. Locally I'm using a .env file and this file is on .gitignore. I want to know how can i set the .env for reading it on production.
You can check the documentation below:
https://create-react-app.dev/docs/adding-custom-environment-variables/#adding-development-environment-variables-in-env
.env files should be checked into source control (with the exclusion of .env*.local ).
If you don't want to check in the .env files to DevOps, you could add the variables in the pipeline variables:
In addition, you can refer to the following case for more suggestions:
How to use environment variables in React app hosted in Azure
Many of the proposed solutions related to this issue may not work but I solved it the following way. However, first let me explain why other solutions may not (should not) work (please correct me if I am wrong)
Adding pipeline variables (even though they are environment variables) should not work since a react app is run on the client side and there is no server side code that can inject environment variables to the react app.
Installing environment variable task on the classic pipeline should not work for the same reason.
Adding to Application Settings in azure app service should not work for the same reason.
Having .env or .env.development or .env.production file in a git repo should not be a good practice as it may compromise api keys and other sensitive information.
So here is my solution -
Step1: Add all those .env files to azure devops library as secure files. You can download these secure files in the build machine using a DownloadSecureFile#1 pipeline task (yml). This way we are making sure the correct .env file is provided in the build machine before the task yarn build --mode development in the pipeline.
Step2:
Add the following task in your azure yml pipeline in appropriate place. I have created a github repo https://github.com/mail4hafij/react-yarn-azure-pipeline if you want to see a complete example.
# Download secure file from azure library
- task: DownloadSecureFile#1
inputs:
secureFile: '.env.development'
# Copy the .env file
- task: CopyFiles#2
inputs:
sourceFolder: '$(Agent.TempDirectory)'
contents: '**/*.env.development'
targetFolder: '$(YOUR_DEFINED_PROJECT_ROOT_FOLDER_VARIABLE)'
cleanTargetFolder: false
Keep note, secure files can't be edited but you can always re-upload.

Azure environment variables only available inside server.js

Trying to setup React app deployed by Azure Devops to use environment variables from Azure.
The command run to start the application is
pm2 start server.js
Within server.js I have added some logging...
console.log(process.env);
This dumps out all the env variables as you would expect (including those set in Azure).
When I attempt to use the same environment variables elsewhere, they are undefined. The files I'm attempting to access the environment variables are in typescript files, and I'm attempting to access them using process.env.MY_VAR.
If you run a process in the context of a build or release, it has access to the environment variables that are defined in the build/release. If you run it elsewhere, it doesn't. Because it's a different environment, and nothing is setting those environment variables. If you want those environment variables set, you need to set them.
In an Azure app service, the correct place is in the App Settings section of your app service. You can use an ARM template to deploy your app service and configure the app settings, or you can set the app settings directly while deploying with the App Service Deploy task.

Firebase + Next.js serverless, on GCP - How to manage staging, production + local

I'm using React with next.js and Google Cloud functions to serve the app. I also use firebase. I'm looking for the best way to automatically configure the staging and production configuration for the 3 environments.
Production: Uses production credentials
Staging: Uses staging credentials
Local: Also uses staging credentials
I have two Firebase projects and currently switch between the configuration using the firebase.js file in my app. I swap out the config object, then deploy. I want to be able to run the app locally, and both on staging and production without changing anything on deploy as it leads to errors.
The issue for me is setting different environment variables for the two cloud projects...I can read cloud environment variables I set up there, but only in the cloud functions environment, not in the client-facing app, which is where I am currently swapping the configuration.
I can see this being solved by:
Google Cloud Platform environment variables (but I have tried and failed to read them from the client). Maybe I change the next.js config to read something up in the cloud when running, instead of doing the config change at deploy?
Local nextjs environment configuration but this doesn't know anything about the two different servers (only dev vs prod which don't match up exactly with local and cloud)
React dotenv configuration (same as the point above)
webpack / npm configuration that swaps the config when compiling
Swapping env based on firebase use [environment] on the command line at deploy time
Points #1 and #5 seem the most likely candidates for automatic and seamless deployment but I can't figure out how to read the GCP config variables in React and for #5 I don't know how to run a custom script that could swap variables based on the firebase project currently being used on the command line.
Most info I have seen on this doesn't tackle this issue exactly - all the env variables are either only in the cloud functions or distinguish local vs cloud or dev vs prod, but cannot distinguish between two clouds and a local that uses the same config as one of the clouds.
Someone must have had experience with this?
I've finally tracked down an answer to this.
The best way I've found to handle this in React/nextjs is to use a combination of my ideas #4 and #5 from my original question.
As seen here, firebase has a firebase apps:sdkconfig command on the cli that:
Prints the Google services configuration of a Firebase App.
So knowing that, you can add a script to npm that creates a firebase config file each time the site gets built. Since it knows which firebase project you are currently using on the command line, it knows the version of the config to output when you're deploying.
Then, in your package.json, you can set it to run.
"scripts": {
...
"build": "npm run getconfig && next build",
"getconfig": "firebase apps:sdkconfig web --json > ./firebase-config.json",
...
},
Then, in your firebase.js or wherever you're configuring firebase in your app:
// Get the Firebase config from the auto generated file.
const firebaseConfig = require('./firebase-config.json').result.sdkConfig;
// Instantiate a Firebase app.
const firebaseApp = firebase.initializeApp(firebaseConfig);
This works both locally and in the cloud with no manual changes needed other than what you'd already be doing to switch the environment you're using (i.e. firebase use)
You might need to tweak which npm script it runs on or other small things to suit your needs, but this general setup is working great for me with production, staging and development environments.

create-react-app build/serve environment variables

Relatively new to working with react. I have an application that is working fine in local docker. I populate a bunch of REACT_APP_ environment variables by exporting them to the environment before starting the docker container.
Now, I'm trying to deploy this to a kubernetes pod by running a yarn build and then serving up the build. I see that the environment variables are available on the pod itself by looking at printenv but the application doesn't appear to be picking them up.
Is there something special with serving a production build of a react-app to get it to see the exported environment variables that I'm missing?
I don't want to embed an .env file into the built docker image for security reasons, so I'm hoping that running a react build via serve can still pick up exported REACT_APP_ environment variables that are set via kubernetes secrets.
So apparently, whenever you build a react application with npm, static files are produced that don't know anything about any environment variables you may try to inject at runtime with Kubernetes.
The article below does a good job of explaining this and why they choose to attach the environment variables to the JavaScript window object since it has application-scope available to it.
Making a React application container environment-aware at Kubernetes deployment

Resources