How can I use different Cypress.env() variables for Circle testing? - cypress

I am doing some automatic testing on Circleci, with different enviromental variables: I need one port for my local testing and a different one for Circleci.
How can I make Cypress do that? I tried making cypress.env.circle, but that does not seem to work

The cypress docs explain 5 ways to set variables.
To use one port locally and one on CircleCI I would:
Add a default port to cypress.json under the env section for local use so you don't have to think about it, and anyone else contributing will have a working version.
Set an environment variable in CircleCI named cypress_VAR_NAME which will override default in cypress.json
cypress.json example
{
"env": {
"the_port": 5000
}
}
CircleCI variable would then be cypress_the_port and you would read it in your specs as parseInt(Cypress.env('the_port')) (assuming your spec needs an integer for port)

Related

Facing problem to set service name from env variable in serverless.yml file after upgrading to latest version

I am trying to set the serverless service name from the env file. Before deploying serverless, I have set the value of ECR_NAME as
export ECR_NAME=$(echo $CI_ENVIRONMENT_SLUG | awk -v srch="-" -v repl="" '{ gsub(srch,repl,$0); print $0 }')
Then I have written it as below in the serverless.yml.
service: ${env:CI_PROJECT_NAME}-${env:ECR_NAME}
useDotenv: true
configValidationMode: error
variablesResolutionMode: 20210326
Getting the below error:
Error:
Cannot resolve serverless.yml: "service" property is not accessible (configured behind variables which cannot be resolved at this stage)
Installed version
Framework Core: 3.14.0
Plugin: 6.2.1
SDK: 4.3.2
See Issue #9313 on GitHub:
https://github.com/serverless/serverless/issues/9813
Problem:
The latest version of the serverless framework is no longer working
for AWS Lambda deployments and is throwing the following error:
Cannot resolve serverless.yml: “provider.stage” property is not accessible (configured behind variables which cannot be resolved at this stage)
Discussion:
with the new resolver, such definition is not supported. In general,
it is discouraged to configure stage behind env variables for example,
as at the point where stage is going to be resolved, not whole env
might be available (e.g. loading env vars from .env.{stage} needs to
resolve stage first in order to properly load variables from file),
which might introduce bugs that are hard to debug. Also, the
provider.stage serves more as a "default" stage and --stage flag via
CLI is the preferred way of setting it.
...
In your configuration file you explicitly opt-in to use new resolver
via variablesResolutionMode: 20210326 variable.
We are not discouraging the use of env variables - quite the contrary,
we've been promoting them as a replacement for custom CLI options for
example and it is generally a great practice to use them. As for env
source for stage specifically, this has been introduced as a fix, as
stage should be already resolved before we attempt env variables
resolution, as loading .env files can depend on stage property.
#medikoo I know we've talked about it today, do you think it could be
safe to resolve stage from env source in specific circumstances (e.g.
when dotenv is not used)?
See also:
https://www.serverless.com/framework/docs/deprecations/#new-variables-resolver
https://www.serverless.com/framework/docs/providers/aws/guide/variables/

How can I switch between env files based on the build command using godotenv?

I'm planning to use godotenv to setup different environments for my project but I am not sure how to switch between files like dev.env, uat.env, prod.env
I want to be able to just pass a value in my Docker command like RUN go build -o my-project --prod . and have godotenv pickup the relative env file - in this case prod.env (assuming this is the correct way.
Also, how can I make sure that the other env files don't get included in the build of a particular env.
I will advice you use the -X flag as suggested by Go Documentation on Command Line
-X importpath.name=value
Set the value of the string variable in importpath named name to value.
This is only effective if the variable is declared in the source code either uninitialized or initialized to a constant string expression. -X will not work if the initializer makes a function call or refers to other variables.
Note that before Go 1.5 this option took two separate arguments.
Such that you can then call any of your .env file referencing it location.
E.g. go build -ldflags="-X 'package_path.variable_name=new_value'"
That is
go build -ldflags "-X 'my/main/config.Version=v1.0.0'" -o $(MY_BIN) $(MY_SRC)
Hard coding your environment at the build stage seems odd to me. You don't want to build a diff image per env, that's wasteful.
The module documentation suggests a better approach:
Existing envs take precedence of envs that are loaded later.
The convention for managing multiple environments (i.e. development, test, production) is to create an env named {YOURAPP}_ENV and load envs in this order:
env := os.Getenv("FOO_ENV")
if "" == env {
env = "development"
}
godotenv.Load(".env." + env + ".local")
if "test" != env {
godotenv.Load(".env.local")
}
godotenv.Load(".env." + env)
godotenv.Load() // The Original .env

Serverless stage environment variables using dotenv (.env)

I'm new to serverless,
So far I was be able to deploy and use .env for the app.
then, under provider in stage property in serverless.yml file, I change it to different stage. I also made new.env.{stage}.
after re-deploy using sls deploy, It still reads the default .env file.
the documentation states:
The framework looks for .env and .env.{stage} files in service directory and then tries to load them using dotenv. If .env.{stage} is found, .env will not be loaded. If stage is not explicitly defined, it defaults to dev.
So, I still don't understand "If stage is not explicitly defined, it defaults to dev". How to explicitly define it?
The dotenv File is choosen based on your stage property configuration. You need to explicitly define the stage property in your serverless.yaml or set it within your deployment command.
This will use the .env.dev file
useDotenv: true
provider:
name: aws
stage: dev # dev [default], stage, prod
memorySize: 3008
timeout: 30
Or you set the stage property via deploy command.
This will use the .env.prod file
sls deploy --stage prod
In your serverless.yml you need to define the stage property inside the provider object.
Example:
provider:
name: aws
[...]
stage: prod
As Feb 2023 I'm going to attempt to give my solution. I'm using the Nx tootling for monorepo (this shouldn't matter but just in case) and I'm using the serverless.ts instead.
I see the purpose of this to be to enhance the developer experience in the sense that it is nice to just nx run users:serve --stage=test (in my case using Nx) or sls offline --stage=test and serverless to be able to load the appropriate variables for that specific environment.
Some people went the route of using several .env.<stage> per environment. I tried to go this route but because I'm not that good of a developer I couldn't make it work. The approach that worked for the was to concatenate variable names inside the serverless.ts. Let me explain...
I'm using just one .env file instead but changing variable names based on the --stage. The magic is happening in the serverless.ts
// .env
STAGE_development=test
DB_NAME_development=mycraftypal
DB_USER_development=postgres
DB_PASSWORD_development=abcde1234
DB_PORT_development=5432
READER_development=localhost // this could be aws rds uri per db instances
WRITER_development=localhost // this could be aws rds uri per db instances
# TEST
STAGE_test=test
DB_NAME_test=mycraftypal
DB_USER_test=postgres
DB_PASSWORD_test=abcde1234
DB_PORT_test=5433
READER_test=localhost // this could be aws rds uri per db instances
WRITER_test=localhost // this could be aws rds uri per db instances
// serverless.base.ts or serverless.ts based on your configuration
...
useDotenv: true, // this property is at the root level
...
provider: {
...
stage: '${opt:stage, "development"}', // get the --stage flag value or default to development
...,
environment: {
STAGE: '${env:STAGE_${self:provider.stage}}}',
DB_NAME: '${env:DB_NAME_${self:provider.stage}}',
DB_USER: '${env:DB_USER_${self:provider.stage}}',
DB_PASSWORD: '${env:DB_PASSWORD_${self:provider.stage}}',
READER: '${env:READER_${self:provider.stage}}',
WRITER: '${env:WRITER_${self:provider.stage}}',
DB_PORT: '${env:DB_PORT_${self:provider.stage}}',
AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
}
...
}
When one is utilizing the useDotenv: true, serverless loads your variables from the .env and puts them in the env variable so you can access them env:STAGE.
Now I can access the variable with dynamic stage like so ${env:DB_PORT_${self:provider.stage}}. If you look at the .env file each variable has the ..._<stage> at the end. In this way I can retrieve dynamically each value.
I'm still figuring it out since I don't want to have the word production in my url but still get the values dynamically and since I'm concatenating this value ${env:DB_PORT_${self:provider.stage}}... then the actual variable becomes DB_PORT_ instead of DB_PORT.

How to pass values from command line to cypress spec file?

I have a few different environments in which I am running Cypress tests (i.e. envA, envB, envC)
I run the tests like so:
npm run cypress:open -- --env apiEndpoint=https://app-envA.mySite.com
npm run cypress:open -- --env apiEndpoint=https://app-envB.mySite.com
npm run cypress:open -- --env apiEndpoint=https://app-envC.mySite.com
As you can see, the apiEndpoint varies based on the environment.
In one of my Cypress tests, I am testing a value that changes based on the environment being tested.
For example:
expect(resourceTiming.name).to.eq('https://cdn-envA.net/myPage.html')
As you can see the text envA appears in this assertion.
The issue I'm facing is that if I run this test in envB, it will fail like so:
Expected: expect(resourceTiming.name).to.eq('https://cdn-envB.net/myPage.html')
Actual: expect(resourceTiming.name).to.eq('https://cdn-envA.net/myPage.html')
My question is - how can I update the spec files so that the correct URL is asserted when I run in the different environments?
I am wondering if there's a way to pass a value from the command line to the spec file to tell the spec file which environment I'm in, but I'm not sure if that's possible.
You can directly use the Cypress.env('apiEndpoint') in your assertions, so that whatever you're passing via CLI, your spec files has the same value -
expect(resourceTiming.name).to.eq(Cypress.env('apiEndpoint'))
And if you want to check that when you pass https://app-envA.mySite.com and the url you expect in the spec file is https://cdn-envA.net/myPage.html, You can use:
expect(resourceTiming.name).to.eq(Cypress.env('apiEndpoint').replace('app', 'cdn').replace('mySite.com', 'net') + '/myPage.html')
Your best bet, in my opinion, is to utilize environment configs (envA.json, envB.json, etc)
Keep all of the property names in the configs identical, and then apply the values based on the environment:
// envA.json file
"env": {
"baseUrl": "yourUrlForEnvA.com"
}
// envB.json file
"env": {
"baseUrl": "yourUrlForEnvB.com"
}
That way, you can call Cypress.env('baseUrl') in your test, and no matter what, the right property should be loaded in.
You would call your environment from the command line with the following syntax:
"cypress run --config-file cypress\\config\\envA.json",
This sets up the test run to grab the right config from the start.
Calling the url for login, for example, would be something like:
cy.login(Cypress.env('baseUrl'))
Best of luck to you!

How can I identify a Buildbot environment by environnment variable?

Does Buildbot provide an environment variable in CI jobs to allow it's identification like e.g. Travis does with TRAVIS?
Last I checked Buildbot does not set an environment variable which has for purpose to indicate that build code is being run through buildbot. In my own setup I do need a few variables that my build code uses so I've setup a dictionary like this:
from buildbot.plugins import util
env = {
'BUILDBOT': '1',
'BUILD_TAG': util.Interpolate("%(prop:buildername)s-%(prop:buildnumber)s"),
'BUILDER': util.Property('buildername')
}
This dictionary can then be used to configure builders:
util.BuilderConfig(
name="foo",
workernames=["a", "b"],
env=env, ...)
The env parameter makes it so that all shell commands issued by this builder will use the environment variables I've declared in my dictionary.
I use BUILDBOT to detect whether the code is running in buildbot at all. The other variables are passed over to services like Sauce Labs and BrowserStack in order to identify the builds there, or they are used for diagnostic purposes.

Resources