Skip to content

Commit 4671317

Browse files
astone123mschile
andauthored
feat: (studio) support @cypress/grep package in Cypress Studio (#32311)
Co-authored-by: Matt Schile <mschile@cypress.io>
1 parent 8eda0c8 commit 4671317

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

cli/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
_Released 09/16/2025 (PENDING)_
55

6+
**Features:**
7+
8+
- Added support for using [@cypress/grep](https://www.npmjs.com/package/@cypress/grep) with Cypress Studio. Addresses [#32292](https://github.com/cypress-io/cypress/issues/32292).
9+
610
**Dependency Updates:**
711

812
- Updated [`better-sqlite3`](https://www.npmjs.com/package/better-sqlite3) from `11.9.1` to `11.10.0`. Addressed in [#32404](https://github.com/cypress-io/cypress/pull/32404).

packages/app/src/store/studio-store.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ interface StudioRecorderState {
111111
sessionId?: string
112112
_isStudioCreatedTest: boolean
113113
newTestLineNumber?: number
114+
_originalGrepSettings: Record<string, string>
114115
}
115116

116117
function getUrlParams () {
@@ -148,6 +149,7 @@ export const useStudioStore = defineStore('studioRecorder', {
148149
sessionId: persistedSessionId,
149150
newTestLineNumber: undefined,
150151
_isStudioCreatedTest: false,
152+
_originalGrepSettings: {},
151153
}
152154
},
153155

@@ -254,6 +256,14 @@ export const useStudioStore = defineStore('studioRecorder', {
254256
this.sessionId = studio.sessionId
255257
}
256258

259+
// if the user has any settings related to @cypress/grep, we need to temporarily remove them
260+
// so that studio can run all of the tests regardless of whether they match the grep filters
261+
if (studio.newTestLineNumber || studio.testId) {
262+
if (this.detectAndStoreGrepSettings()) {
263+
this.clearGrepSettings()
264+
}
265+
}
266+
257267
// if we have an existing test or are creating a new test, we need to start loading
258268
// otherwise if we have a suite, we can just set the studio active
259269
if (this.testId || studio.newTestLineNumber) {
@@ -276,6 +286,62 @@ export const useStudioStore = defineStore('studioRecorder', {
276286
}
277287
},
278288

289+
detectAndStoreGrepSettings () {
290+
const grepEnvVars = [
291+
'grep',
292+
'grepTags', 'grep-tags',
293+
'grepUntagged', 'grep-untagged',
294+
'grepOmitFiltered', 'grep-omit-filtered',
295+
]
296+
297+
this._originalGrepSettings = {}
298+
299+
try {
300+
const cypress = getCypress()
301+
302+
for (const envVar of grepEnvVars) {
303+
const value = cypress.env(envVar)
304+
305+
if (value != null) {
306+
this._originalGrepSettings[envVar] = value
307+
}
308+
}
309+
310+
return Object.keys(this._originalGrepSettings).length > 0
311+
} catch {
312+
return false
313+
}
314+
},
315+
316+
clearGrepSettings () {
317+
try {
318+
const cypress = getCypress()
319+
320+
for (const envVar of Object.keys(this._originalGrepSettings)) {
321+
cypress.env(envVar, null)
322+
}
323+
} catch {
324+
// Cypress not ready, skip
325+
}
326+
},
327+
328+
restoreGrepSettings () {
329+
// Only restore if we have settings to restore
330+
if (Object.keys(this._originalGrepSettings).length === 0) {
331+
return
332+
}
333+
334+
try {
335+
const cypress = getCypress()
336+
337+
for (const [envVar, value] of Object.entries(this._originalGrepSettings)) {
338+
cypress.env(envVar, value)
339+
}
340+
} catch {
341+
// Cypress not ready, skip
342+
}
343+
},
344+
279345
interceptTest (test) {
280346
// if this test is the one we created, we can just set the test id
281347
if ((this.newTestLineNumber && test.invocationDetails?.line === this.newTestLineNumber) || (this.suiteId && this._hasStarted)) {
@@ -319,13 +385,16 @@ export const useStudioStore = defineStore('studioRecorder', {
319385
reset () {
320386
this.stop()
321387

388+
this.restoreGrepSettings()
389+
322390
this.logs = []
323391
this.url = undefined
324392
this._hasStarted = false
325393
this._currentId = 1
326394
this.isFailed = false
327395
this.showUrlPrompt = true
328396
this._isStudioCreatedTest = false
397+
this._originalGrepSettings = {}
329398

330399
this._maybeResetRunnables()
331400
},

packages/app/src/studio/studio-app-types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ CyEventEmitter & {
3131
getRootSuite: () => Suite
3232
}
3333
areSourceMapsAvailable?: boolean
34+
stackUtils?: {
35+
getSourceDetailsForFirstLine: (stack: string, projectRoot: string) => {
36+
line: number
37+
column: number
38+
file: string
39+
}
40+
}
3441
}
3542

3643
export interface TestBlock {

packages/driver/src/cypress.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import $SetterGetter from './cypress/setter_getter'
3030
import { validateConfig } from './util/config'
3131
import $utils from './cypress/utils'
3232

33+
import $stackUtils from './cypress/stack_utils'
3334
import { $Chainer } from './cypress/chainer'
3435
import { $Cookies, ICookies } from './cypress/cookies'
3536
import { $Command } from './cypress/command'
@@ -127,6 +128,7 @@ class $Cypress {
127128
specBridgeCommunicator: SpecBridgeCommunicator
128129
isCrossOriginSpecBridge: boolean
129130
on: any
131+
stackUtils: typeof $stackUtils | null = null
130132

131133
// attach to $Cypress to access
132134
// all of the constructors
@@ -363,6 +365,7 @@ class $Cypress {
363365
this.mocha = $Mocha.create(specWindow, this, this.config)
364366
this.runner = $Runner.create(specWindow, this.mocha, this, this.cy, this.state)
365367
this.downloads = $Downloads.create(this)
368+
this.stackUtils = $stackUtils
366369

367370
// wire up command create to cy
368371
// @ts-expect-error

0 commit comments

Comments
 (0)