Skip to content

Commit 2147a84

Browse files
update env / task examples (#6331)
* update env / task examples * update plugin example to be more realistic * lint * more updates * lint * few more updates to wording * Update docs/app/continuous-integration/overview.mdx * Update docs/api/commands/task.mdx
1 parent c9fd19e commit 2147a84

28 files changed

+392
-269
lines changed

docs/api/commands/exec.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ cy.exec('man bear pig', { failOnNonZeroExit: false }).then((result) => {
138138
})
139139
```
140140

141-
#### Specify environment variables
141+
#### Specify system environment variables
142142

143143
```javascript
144144
cy.exec('echo $USERNAME', { env: { USERNAME: 'johndoe' } })

docs/api/commands/prompt.mdx

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -347,43 +347,43 @@ Placeholders let you use dynamic and sensitive values while maintaining cache ef
347347
```typescript
348348
describe('Campaign Management', () => {
349349
it('creates multiple campaigns with different discount percentages', () => {
350-
const adminPassword = Cypress.env('ADMIN_PASSWORD')
351-
352-
const campaigns = [
353-
{ name: 'Fall Sale', discountPct: 10 },
354-
{ name: 'Spring Sale', discountPct: 15 },
355-
]
356-
357-
// This loop demonstrates the caching benefit:
358-
// - First iteration: AI generates and caches the code
359-
// - Subsequent iterations: Reuse cached code with different placeholder values
360-
campaigns.forEach((campaign) => {
361-
const campaignName = campaign.name
362-
const campaignDiscountPct = campaign.discountPct
363-
364-
cy.prompt(
365-
[
366-
`Visit ${Cypress.env('ADMIN_URL')}/admin/login`,
367-
// Using {{adminPassword}} prevents this sensitive value from being sent to AI
368-
'Type {{adminPassword}} into the password field',
369-
'Click Sign In',
370-
'Open the Promotions tab',
371-
'Click to create a new campaign',
372-
// Using {{campaignName}} and {{campaignDiscountPct}}
373-
// allows for high performance caching with different values
374-
'Type {{campaignName}} into the name field',
375-
'Set discount to {{campaignDiscountPct}}% for all products',
376-
'Save the campaign',
377-
'Verify the campaign "{{campaignName}}" appears in the list',
378-
],
379-
{
380-
placeholders: {
381-
adminPassword,
382-
campaignName,
383-
campaignDiscountPct,
384-
},
385-
}
386-
)
350+
cy.task('getSecret', 'ADMIN_PASSWORD').then((adminPassword) => {
351+
const campaigns = [
352+
{ name: 'Fall Sale', discountPct: 10 },
353+
{ name: 'Spring Sale', discountPct: 15 },
354+
]
355+
356+
// This loop demonstrates the caching benefit:
357+
// - First iteration: AI generates and caches the code
358+
// - Subsequent iterations: Reuse cached code with different placeholder values
359+
campaigns.forEach((campaign) => {
360+
const campaignName = campaign.name
361+
const campaignDiscountPct = campaign.discountPct
362+
363+
cy.prompt(
364+
[
365+
`Visit ${Cypress.env('ADMIN_URL')}/admin/login`,
366+
// Using {{adminPassword}} prevents this sensitive value from being sent to AI
367+
'Type {{adminPassword}} into the password field',
368+
'Click Sign In',
369+
'Open the Promotions tab',
370+
'Click to create a new campaign',
371+
// Using {{campaignName}} and {{campaignDiscountPct}}
372+
// allows for high performance caching with different values
373+
'Type {{campaignName}} into the name field',
374+
'Set discount to {{campaignDiscountPct}}% for all products',
375+
'Save the campaign',
376+
'Verify the campaign "{{campaignName}}" appears in the list',
377+
],
378+
{
379+
placeholders: {
380+
adminPassword,
381+
campaignName,
382+
campaignDiscountPct,
383+
},
384+
}
385+
)
386+
})
387387
})
388388
})
389389
})
@@ -567,7 +567,7 @@ describe('Feature: User Registration', () => {
567567
],
568568
{
569569
placeholders: {
570-
password: Cypress.env('PASSWORD'),
570+
password: 'PASSWORD_PLACEHOLDER', // Use cy.task('getSecret', 'PASSWORD') to get the actual value
571571
},
572572
}
573573
)
@@ -687,20 +687,20 @@ The commands in the generated code may look like:
687687
### Login flow
688688

689689
```javascript
690-
const password = Cypress.env('adminPassword')
691-
692-
cy.prompt(
693-
[
694-
'visit the login page',
695-
'type "[email protected]" in the email field',
696-
'type {{password}} in the password field',
697-
'click the login button',
698-
'verify we are redirected to the dashboard',
699-
],
700-
{
701-
placeholders: { password },
702-
}
703-
)
690+
cy.task('getSecret', 'ADMIN_PASSWORD').then((password) => {
691+
cy.prompt(
692+
[
693+
'visit the login page',
694+
'type "[email protected]" in the email field',
695+
'type {{password}} in the password field',
696+
'click the login button',
697+
'verify we are redirected to the dashboard',
698+
],
699+
{
700+
placeholders: { password },
701+
}
702+
)
703+
})
704704
```
705705

706706
### E-commerce checkout
@@ -794,7 +794,7 @@ cy.origin('https://cloud.cypress.io/login', () => {
794794
],
795795
{
796796
placeholders: {
797-
password: Cypress.env('PASSWORD'),
797+
password: 'PASSWORD_PLACEHOLDER',
798798
},
799799
}
800800
)

docs/api/commands/task.mdx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ cy.task('queryDatabase', { dbName, query })
420420
```ts
421421
import mysql from 'mysql'
422422
// the connection strings for different databases could
423-
// come from the Cypress configuration or from environment variables
423+
// come from system environment variables
424424
const connections = {
425425
stagingA: {
426426
host: 'staging.my.co',
@@ -507,6 +507,43 @@ on('task', {
507507

508508
:::
509509

510+
### Accessing secrets securely
511+
512+
You can use `cy.task()` to securely access secrets from the Node.js process environment variables. This is the recommended approach for accessing sensitive values like passwords, API keys, or tokens, as they remain in the Node.js process and are not exposed to the browser.
513+
514+
:::cypress-config-plugin-example
515+
516+
```ts
517+
on('task', {
518+
getSecret(secretName: string) {
519+
const secret = process.env[secretName]
520+
521+
if (!secret) {
522+
throw new Error(`Secret ${secretName} is not set`)
523+
}
524+
525+
return secret
526+
},
527+
})
528+
```
529+
530+
:::
531+
532+
```javascript
533+
// in test
534+
cy.task('getSecret', 'API_KEY').then((apiKey) => {
535+
cy.request({
536+
method: 'POST',
537+
url: 'https://api.example.com/data',
538+
headers: {
539+
Authorization: `Bearer ${apiKey}`,
540+
},
541+
})
542+
})
543+
```
544+
545+
In CI environments, you can set these secrets as environment variables in your CI provider's secret management system.
546+
510547
## Rules
511548

512549
<HeaderRequirements />

docs/api/commands/wrap.mdx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,15 @@ import { userService } from '../../src/_services/user.service'
126126
it('can assert against resolved object using .should', () => {
127127
cy.log('user service login')
128128
const username = Cypress.env('username')
129-
const password = Cypress.env('password')
130-
131-
// wrap the promise returned by the application code
132-
cy.wrap(userService.login(username, password))
133-
// check the yielded object
134-
.should('be.an', 'object')
135-
.and('have.keys', ['firstName', 'lastName', 'username', 'id', 'token'])
136-
.and('contain', {
137-
username: 'test',
138-
firstName: 'Test',
129+
cy.task('getSecret', 'PASSWORD').then((password) => {
130+
// wrap the promise returned by the application code
131+
cy.wrap(userService.login(username, password))
132+
// check the yielded object
133+
.should('be.an', 'object')
134+
.and('have.keys', ['firstName', 'lastName', 'username', 'id', 'token'])
135+
.and('contain', {
136+
username: 'test',
137+
firstName: 'Test',
139138
lastName: 'User',
140139
})
141140

docs/api/cypress-api/env.mdx

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ specs.
3636
<strong>Difference between OS-level and Cypress environment variables</strong>
3737

3838
In Cypress, "environment variables" are variables that are accessible via
39-
`Cypress.env`. These are not the same as OS-level environment variables.
39+
`Cypress.env` and the browser. These are not the same as OS-level environment variables.
4040
However,
4141
[it is possible to set Cypress environment variables from OS-level environment variables](/app/references/environment-variables#Option-3-CYPRESS_).
4242

@@ -76,16 +76,16 @@ Set multiple environment variables with an object literal.
7676
```ts
7777
{
7878
env: {
79-
foo: 'bar',
80-
baz: 'quux',
79+
apiUrl: 'https://api.example.com',
80+
apiVersion: 'v1',
8181
},
8282
}
8383
```
8484

8585
:::
8686

8787
```javascript
88-
Cypress.env() // => {foo: 'bar', baz: 'quux'}
88+
Cypress.env() // => {apiUrl: 'https://api.example.com', apiVersion: 'v1'}
8989
```
9090

9191
### Name
@@ -102,13 +102,13 @@ command line. Cypress will automatically convert values into Number or Boolean.
102102
:::
103103

104104
```javascript
105-
CYPRESS_HOST=laura.dev CYPRESS_IS_CI=true CYPRESS_MY_ID=123 cypress run
105+
CYPRESS_HOST=laura.dev CYPRESS_IS_CI=true CYPRESS_API_VERSION=123 cypress run
106106
```
107107

108108
```javascript
109109
Cypress.env('HOST') // => "laura.dev"
110110
Cypress.env('IS_CI') // => true
111-
Cypress.env('MY_ID') // => 123
111+
Cypress.env('API_VERSION') // => 123
112112
```
113113

114114
### Name and Value
@@ -129,8 +129,7 @@ only be in effect for the remainder of the tests _in the same spec file._
129129
```ts
130130
{
131131
env: {
132-
foo: 'bar',
133-
baz: 'quux',
132+
host: 'laura.dev',
134133
},
135134
}
136135
```
@@ -152,8 +151,8 @@ Cypress.env('host') // => http://server.dev.local
152151
```ts
153152
{
154153
env: {
155-
foo: 'bar',
156-
baz: 'quux',
154+
host: 'laura.dev',
155+
apiVersion: 'v1',
157156
},
158157
}
159158
```
@@ -163,10 +162,10 @@ Cypress.env('host') // => http://server.dev.local
163162
```javascript
164163
Cypress.env({
165164
host: 'http://server.dev.local',
166-
foo: 'foo',
165+
apiVersion: 'v2',
167166
})
168167

169-
Cypress.env() // => {foo: 'foo', baz: 'quux', host: 'http://server.dev.local'}
168+
Cypress.env() // => {apiVersion: 'v2', host: 'http://server.dev.local'}
170169
```
171170

172171
### From a plugin
@@ -181,25 +180,32 @@ of the tests in your spec run.
181180
:::cypress-config-plugin-example
182181

183182
```js
184-
config.env.sharedSecret =
185-
process.env.NODE_ENV === 'qa' ? 'hoop brick tort' : 'sushi cup lemon'
183+
config.env.apiBaseUrl =
184+
process.env.NODE_ENV === 'qa'
185+
? 'https://api-qa.example.com'
186+
: 'https://api.example.com'
186187

187188
return config
188189
```
189190

190191
:::
191192

192193
```js
193-
// cypress/e2e/secrets.cy.js
194-
describe('Environment variable set in plugin', () => {
195-
let sharedSecret
194+
// cypress/e2e/api-tests.cy.js
195+
describe('API tests', () => {
196+
let apiBaseUrl
196197

197198
before(() => {
198-
sharedSecret = Cypress.env('sharedSecret')
199+
apiBaseUrl = Cypress.env('apiBaseUrl')
199200
})
200201

201-
it.only('can be accessed within test.', () => {
202-
cy.log(sharedSecret)
202+
it('can make requests to the correct environment', () => {
203+
cy.request({
204+
method: 'GET',
205+
url: `${apiBaseUrl}/users`,
206+
}).then((response) => {
207+
expect(response.status).to.eq(200)
208+
})
203209
})
204210
})
205211
```

docs/api/node-events/browser-launch-api.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ following properties:
5454
| `preferences` | `object` | An object describing browser preferences. Differs between browsers. See [Change browser preferences](#Change-browser-preferences) for details. |
5555
| `args` | `string[]` | An array of strings that will be passed as command-line args when the browser is launched. Has no effect on Electron. See [Modify browser launch arguments](#Modify-browser-launch-arguments) for details. |
5656
| `extensions` | `string[]` | An array of paths to folders containing unpacked WebExtensions to be loaded before the browser starts. See [Add browser extensions](#Add-browser-extensions) for details. |
57-
| `env` | `object` | An object of environment variables to pass to the launched browser. See [Configure browser environment](#Configure-browser-environment) for details. |
57+
| `env` | `object` | An object of system environment variables to pass to the launched browser. See [Configure browser environment](#Configure-browser-environment) for details. |
5858

5959
## Usage
6060

@@ -162,7 +162,7 @@ Here are preferences available for the currently supported browsers:
162162

163163
:::info
164164

165-
If you want to ignore Chrome preferences altogether, you can set `IGNORE_CHROME_PREFERENCES` as an environment variable when running Cypress.
165+
If you want to ignore Chrome preferences altogether, you can set `IGNORE_CHROME_PREFERENCES` as a system environment variable when running Cypress.
166166

167167
:::
168168

@@ -206,7 +206,7 @@ line switches. The supported switches depend on the Electron version, see
206206
[Electron documentation](https://www.electronjs.org/docs/api/command-line-switches).
207207

208208
You can pass Electron-specific launch arguments using the
209-
`ELECTRON_EXTRA_LAUNCH_ARGS` environment variable. For example, to disable HTTP
209+
`ELECTRON_EXTRA_LAUNCH_ARGS` system environment variable. For example, to disable HTTP
210210
browser cache and ignore certificate errors, you can set the environment
211211
variables before running Cypress like below:
212212

0 commit comments

Comments
 (0)