Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cypress-dotenv v3.x #50

Merged
merged 10 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ NON_CYPRESS_TEST_VAR=goodbye
CYPRESS_BASE_URL=http://google.com
CYPRESS_ENV=testing
CYPRESS_I_AM_NUMBER=100
CYPRESS_I_AM_BOOLEAN=true
CYPRESS_I_AM_BOOLEAN=true
CYPRESS_I_AM_A_NUMBER_WITH_LEADING_ZERO=0100
26 changes: 5 additions & 21 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,9 @@ Please fill out this section with a description of your changes and your approac

_fill me out 📝_

## How to test/verify these changes
## Verification Checklist

<!--
Replace the sample steps below with steps on how a reviewer of this PR can test your changes. This should include things such as (if applicable):
* Do you need to use a specific account to log in?
* Is there a particular patient profile that should be used?
-->

1. Clone this branch and run: `npm run cypress`
1. Next, do thing 1
1. Now do thing 2
1. Notice that XYZ has changed


## Screenshots and/or video

<!--
If relevant, make sure to include relevant video or before/after screenshots that demonstrate the changes.
If no visuals are required, then please fill out this section with "N/A"
-->

_fill me out 📸_
- [ ] Provided a good description of the changes introduced with this PR.
- [ ] Written adequate unit tests (if necessary)
- [ ] Updated the README (if necessary)
- [ ] Make sure things still work with v10 and up of Cypress
20 changes: 20 additions & 0 deletions .github/workflows/pr-quality-checks.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Run a number of quality checks ever time a PR is opened
name: Pull Request Quality Checks

permissions:
contents: read
pull-requests: read
on:
workflow_dispatch:
inputs:
Expand Down Expand Up @@ -60,3 +63,20 @@ jobs:
env:
CI: true
NODE_ENV: test

integration-testing:
name: Integration testing
runs-on: ubuntu-latest
needs: setup
steps:
# restore dependencies that were installed in the `setup` job
- name: Restore dependencies
uses: actions/cache@v3
with:
path: |
./*
~/.npm
key: ${{ github.sha }}

- name: Cypress Run
uses: cypress-io/github-action@v6
Fixed Show fixed Hide fixed
Dismissed Show dismissed Hide dismissed
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20
18
46 changes: 21 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Cypress dotenv

Cypress plugin that enables compatability with [dotenv](https://www.npmjs.com/package/dotenv).
Cypress plugin that enables compatibility with [dotenv](https://www.npmjs.com/package/dotenv).

> [!NOTE]
> If you need support for Cypress v9 or below, please use [v2.x of this plugin](https://github.com/morficus/cypress-dotenv/tree/v2.0.2)


[![Build Status](https://travis-ci.org/morficus/cypress-dotenv.svg?branch=master)](https://travis-ci.org/morficus/cypress-dotenv)
[![Maintainability](https://api.codeclimate.com/v1/badges/0d189dae8e924ada81ad/maintainability)](https://codeclimate.com/github/morficus/cypress-dotenv/maintainability)
Expand Down Expand Up @@ -35,41 +39,33 @@ yarn add --dev dotenv cypress-dotenv

## Configure

Cypress (< 10.0.0)

Since this is a plugin, you will need to modify your file `cypress/plugins/index.js` to look something like this:

```javascript
const dotenvPlugin = require('cypress-dotenv');
module.exports = (on, config) => {
config = dotenvPlugin(config)
return config
}
```
Version 3.x of this plugin only supports Cypress v10+. For instructions on how to set up this plugin with older versions of Cypress, please refer to the [v2.x README](https://github.com/morficus/cypress-dotenv/tree/v2.0.2?tab=readme-ov-file#configure)

Cypress (>= 10.0.0)

According to [Migration Guide](https://docs.cypress.io/guides/references/migration-guide#Plugins-File-Removed):
The setupNodeEvents() config option is functionally equivalent to the function exported from the plugins file
Since this is a plugin, you will need to modify your `cypress.config.js` to look something like this

```javascript
```typescript
import { defineConfig } from 'cypress'
import dotenvPlugin from 'cypress-dotenv'

export default defineConfig({
e2e: {
...
setupNodeEvents(on, config) {
return dotenvPlugin(config)
},
e2e: {
...
setupNodeEvents(on, config) {
const updatedConfig = dotenvPlugin(config, null, true)
// continue loading other plugins
return updatedConfig
},
},
...
})
```

## Options
This plugin takes three paramaters. The first parameter (which is mandatory) is the Cypress config object.

The second is an optional [dotenv](https://www.npmjs.com/package/dotenv#config) config object.

The third is an optional [all] boolean parameter, which is set to false by default. If set to true, it returns all available environmental variables, not limited to those prefixed with CYPRESS_.
## Options
This plugin takes three parameters:

1. The first parameter (which is mandatory) is the Cypress config object.
1. The second is an optional [dotenv](https://www.npmjs.com/package/dotenv#config) config object.
1. The third (called `all`) is an optional boolean parameter, which is set to false by default. If set to true, it returns all available environmental variables, not limited to those prefixed with CYPRESS_.
16 changes: 16 additions & 0 deletions cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { defineConfig } = require('cypress')
const dotenvPlugin = require('./index')

module.exports = defineConfig({
video: false,
e2e: {
// We've imported your old cypress plugins here.
// You may want to clean this up later by importing these.
setupNodeEvents(on, config) {
const updatedConfig = dotenvPlugin(config, null, true)
// continue loading other plugins

return updatedConfig
}
}
})
3 changes: 0 additions & 3 deletions cypress.json

This file was deleted.

25 changes: 0 additions & 25 deletions cypress/plugins/index.js

This file was deleted.

File renamed without changes.
47 changes: 36 additions & 11 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@ const camelcase = require('camelcase')
const clonedeep = require('lodash.clonedeep')
const pkgName = '[cypress-dotenv]'

/**
* Checks if something that was parsed as a number should be a string instead.
* Specifically for cases where a number has a leading zero
* See: https://github.com/morficus/cypress-dotenv/issues/32
*/
function checkIfTrulyNumber({ parsedValue, rawValue }) {
let correctValue = parsedValue

if (typeof parsedValue === 'number' && rawValue.startsWith('0')) {
// if env var has a leading zero, then it must be a string and not a number
correctValue = rawValue
}

return correctValue
}

/**
* Cypress dotenv plugin
*
Expand All @@ -19,36 +35,45 @@ module.exports = (cypressConfig, dotEnvConfig, all = false) => {
const cypressPrefix = 'CYPRESS_'

// load the content of the .env file, then parse each variable to the correct type (string, number, boolean, etc.)
let envVars = require('dotenv').config(dotEnvConfig)
const rawEnvVars = require('dotenv').config(dotEnvConfig).parsed

// if no env vars were parsed, then there is nothing to do here (most likely an empty or non-existing .env file)
if (envVars.parsed === undefined) {
// if no env vars were found, then there is nothing to do here (most likely an empty or non-existing .env file)
if (rawEnvVars === undefined || rawEnvVars === null || Object.keys(rawEnvVars).length === 0) {
return cypressConfig
}

const dotenvParseVariables = require('dotenv-parse-variables')
envVars = dotenvParseVariables(envVars.parsed)
const parsedEnvVars = dotenvParseVariables(rawEnvVars)

const enhancedConfig = clonedeep(cypressConfig)
enhancedConfig.env = enhancedConfig.env || {}

// get the name of all env vars that relate to cypress
const cypressEnvVarKeys = all
? Object.keys(envVars)
: Object.keys(envVars).filter((envName) => envName.startsWith(cypressPrefix))
? Object.keys(parsedEnvVars)
: Object.keys(parsedEnvVars).filter((envName) => envName.startsWith(cypressPrefix))

cypressEnvVarKeys.forEach((originalName) => {
// remove the CYPRESS_ prefix from the env var name
const pattern = new RegExp(`^${cypressPrefix}`, 'g')
const cleanName = originalName.replace(pattern, '')

// convert the env var name from snake_case to camelCase
const camelCaseName = camelcase(cleanName)
const parsedEnvar = envVars[originalName]
const processEnvVar = process.env[originalName]
const envVar = typeof parsedEnvar === 'string' ? processEnvVar : parsedEnvar

enhancedConfig.env[cleanName] = envVar
const parsedValue = parsedEnvVars[originalName]
const rawValue = process.env[originalName]

let effectiveValue = typeof parsedValue === 'string' ? rawValue : parsedValue

if (typeof effectiveValue === 'number') {
effectiveValue = checkIfTrulyNumber({ parsedValue: effectiveValue, rawValue })
}

enhancedConfig.env[cleanName] = effectiveValue

if (enhancedConfig.hasOwnProperty(camelCaseName) && camelCaseName !== 'env') {
enhancedConfig[camelCaseName] = envVar
enhancedConfig[camelCaseName] = effectiveValue
}
})

Expand Down
13 changes: 10 additions & 3 deletions index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('Cypress dotenv plugin', () => {
expect(enhancedConfig.env).toEqual({})
})

it('Should only add CYPRESS_ vars to the config', () => {
it('Should only add CYPRESS_ vars to the config by default', () => {
const enhancedConfig = plugin(cypressConfigExample)

expect(enhancedConfig.env.TEST_VAR).toBeDefined()
Expand Down Expand Up @@ -72,6 +72,11 @@ describe('Cypress dotenv plugin', () => {
expect(enhancedConfig.env.I_AM_NUMBER).toEqual(100)
})

it('Should parse things that are numbers with leading zeros, as a string', () => {
const enhancedConfig = plugin(cypressConfigExample)
expect(enhancedConfig.env.I_AM_A_NUMBER_WITH_LEADING_ZERO).toEqual('0100')
})

it('Should parse things that are booleans, as booleans', () => {
const enhancedConfig = plugin(cypressConfigExample)
expect(enhancedConfig.env.I_AM_BOOLEAN).toEqual(true)
Expand All @@ -96,7 +101,8 @@ describe('Cypress dotenv plugin', () => {
ENV: 'testing',
I_AM_BOOLEAN: true,
I_AM_NUMBER: 100,
TEST_VAR: 'hello'
TEST_VAR: 'hello',
I_AM_A_NUMBER_WITH_LEADING_ZERO: '0100'
}
const enhancedConfig = plugin({})

Expand All @@ -123,7 +129,8 @@ describe('Cypress dotenv plugin', () => {
I_AM_BOOLEAN: true,
I_AM_NUMBER: 100,
NON_CYPRESS_TEST_VAR: 'goodbye',
TEST_VAR: 'hello'
TEST_VAR: 'hello',
I_AM_A_NUMBER_WITH_LEADING_ZERO: '0100'
})
})
})
Expand Down
Loading
Loading