Skip to content

Commit a73f304

Browse files
internal: Hide studio buttons when running All Specs via experimentalRunAllSpecs mode (#32051)
* internal: hide studio buttons when running all specs * fix selector in tests
1 parent 205801c commit a73f304

File tree

6 files changed

+119
-10
lines changed

6 files changed

+119
-10
lines changed

packages/app/cypress/e2e/studio/studio-cloud.cy.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,69 @@ describe('studio functionality', () => {
296296
cy.findByTestId('studio-toolbar').should('not.exist')
297297
})
298298

299+
it('hides studio button when running all specs', () => {
300+
// Use the run-all-specs project which already has run-all-specs enabled
301+
cy.scaffoldProject('run-all-specs')
302+
cy.openProject('run-all-specs')
303+
304+
// Enable experimental studio by modifying the config
305+
cy.withCtx(async (ctx) => {
306+
const configPath = 'cypress.config.js'
307+
const configContent = await ctx.actions.file.readFileInProject(configPath)
308+
const updatedConfig = configContent.replace(
309+
'experimentalRunAllSpecs: true,',
310+
'experimentalRunAllSpecs: true,\n experimentalStudio: true,',
311+
)
312+
313+
await ctx.actions.file.writeFileInProject(configPath, updatedConfig)
314+
})
315+
316+
cy.startAppServer('e2e')
317+
cy.visitApp()
318+
cy.specsPageIsVisible()
319+
320+
// Spawns new browser so we need to stub this
321+
cy.withCtx((ctx, { sinon }) => {
322+
sinon.stub(ctx.actions.project, 'launchProject').resolves()
323+
})
324+
325+
// Run all specs
326+
cy.findByTestId('run-all-specs-for-all').click()
327+
328+
// Wait for the runner to load
329+
cy.waitForSpecToFinish()
330+
331+
// Verify that we're running all specs by checking the header
332+
cy.get('[data-cy="runnable-header"]').should('contain', 'All Specs')
333+
334+
// Verify that the studio button is NOT visible when running all specs
335+
cy.findByTestId('studio-button').should('not.exist')
336+
337+
// Verify that the studio panel is NOT visible
338+
cy.findByTestId('studio-panel').should('not.exist')
339+
})
340+
341+
it('shows studio button when running a single spec', () => {
342+
// Use the existing experimental-studio project
343+
cy.scaffoldProject('experimental-studio')
344+
cy.openProject('experimental-studio')
345+
cy.startAppServer('e2e')
346+
cy.visitApp()
347+
cy.specsPageIsVisible()
348+
349+
// Run a single spec instead of all specs
350+
cy.get('[data-cy-row="spec.cy.js"]').click()
351+
352+
cy.waitForSpecToFinish()
353+
354+
// Verify that we're running a single spec (not all specs)
355+
cy.get('[data-cy="runnable-header"]').should('contain', 'spec.cy.js')
356+
cy.get('[data-cy="runnable-header"]').should('not.contain', 'All Specs')
357+
358+
// Verify that the studio button IS visible when running a single spec
359+
cy.findByTestId('studio-button').should('be.visible')
360+
})
361+
299362
describe('failing to load studio and retrying', () => {
300363
it('displays error panel when studio bundle fails to load', () => {
301364
// Intercept the studio bundle request and make it fail

packages/app/src/runner/SpecRunnerOpenMode.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117

118118
<script lang="ts" setup>
119119
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
120+
import { useRoute } from 'vue-router'
120121
import { REPORTER_ID, RUNNER_ID } from './utils'
121122
import InlineSpecList from '../specs/InlineSpecList.vue'
122123
import { getAutIframeModel, getEventManager } from '.'
@@ -222,6 +223,7 @@ const props = defineProps<{
222223
gql: SpecRunnerFragment
223224
}>()
224225
226+
const route = useRoute()
225227
const eventManager = getEventManager()
226228
227229
const autStore = useAutStore()
@@ -288,7 +290,10 @@ const shouldShowStudioButton = computed(() => {
288290
const experimentalStudioConfig = props.gql.currentProject?.config?.find((item) => item.field === 'experimentalStudio')
289291
const experimentalStudioEnabled = experimentalStudioConfig?.value === true
290292
291-
return !!cloudStudioRequested.value && !studioStore.isOpen && experimentalStudioEnabled
293+
// Check if we're running all specs by looking at the route query
294+
const isRunningAllSpecs = route.query.file === '__all'
295+
296+
return !!cloudStudioRequested.value && !studioStore.isOpen && experimentalStudioEnabled && !isRunningAllSpecs
292297
})
293298
294299
const shouldShowStudioPanel = computed(() => {

packages/reporter/cypress/e2e/tests.cy.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { MobxRunnerStore } from '@packages/app/src/store/mobx-runner-store'
55
let runner: EventEmitter
66
let runnables: RootRunnable
77

8-
function visitAndRenderReporter (studioEnabled: boolean = false, studioActive: boolean = false) {
8+
function visitAndRenderReporter (studioEnabled: boolean = false, studioActive: boolean = false, specRelative: string = 'relative/path/to/foo.js') {
99
cy.fixture('runnables').then((_runnables) => {
1010
runnables = _runnables
1111
})
@@ -16,7 +16,7 @@ function visitAndRenderReporter (studioEnabled: boolean = false, studioActive: b
1616

1717
runnerStore.setSpec({
1818
name: 'foo.js',
19-
relative: 'relative/path/to/foo.js',
19+
relative: specRelative,
2020
absolute: '/absolute/path/to/foo.js',
2121
})
2222

@@ -196,6 +196,36 @@ describe('tests', () => {
196196
.find('.collapsible-content').should('not.exist')
197197
})
198198
})
199+
200+
describe('studio controls', () => {
201+
it('hides launch studio icon when running all specs', () => {
202+
visitAndRenderReporter(true, false, '__all')
203+
204+
cy.contains('test 1').realHover()
205+
cy.get('[data-cy="launch-studio"]').should('not.exist')
206+
})
207+
208+
it('shows launch studio icon when running a single spec', () => {
209+
visitAndRenderReporter(true, false, 'relative/path/to/foo.js')
210+
211+
cy.contains('test 1').realHover()
212+
cy.get('[data-cy="launch-studio"]').should('exist')
213+
})
214+
215+
it('hides new test button in suites when running all specs', () => {
216+
visitAndRenderReporter(true, false, '__all')
217+
218+
cy.contains('suite 1').realHover()
219+
cy.get('[data-cy="create-new-test-button"]').should('not.exist')
220+
})
221+
222+
it('shows new test button in suites when running a single spec', () => {
223+
visitAndRenderReporter(true, false, 'relative/path/to/foo.js')
224+
225+
cy.contains('suite 1').realHover()
226+
cy.get('[data-cy="create-new-test-button"]').should('exist')
227+
})
228+
})
199229
})
200230

201231
describe('studio controls', () => {

packages/reporter/src/runnables/runnable-and-suite.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ interface SuiteProps {
2525
model: SuiteModel
2626
studioEnabled: boolean
2727
canSaveStudioLogs: boolean
28+
spec?: Cypress.Cypress['spec']
2829
}
2930

3031
const headerIconDefaultProps = {
@@ -33,7 +34,7 @@ const headerIconDefaultProps = {
3334
className: 'header-icon',
3435
}
3536

36-
const Suite: React.FC<SuiteProps> = observer(({ eventManager = events, model, studioEnabled, canSaveStudioLogs }: SuiteProps) => {
37+
const Suite: React.FC<SuiteProps> = observer(({ eventManager = events, model, studioEnabled, canSaveStudioLogs, spec }: SuiteProps) => {
3738
const _launchStudio = useCallback((e: MouseEvent) => {
3839
e.preventDefault()
3940
e.stopPropagation()
@@ -82,7 +83,7 @@ const Suite: React.FC<SuiteProps> = observer(({ eventManager = events, model, st
8283
{getHeaderIcon(isOpen)}
8384
</div>
8485
<span className='runnable-title'>{model.title}</span>
85-
{(studioEnabled && !appState.studioActive) && (
86+
{(studioEnabled && !appState.studioActive && spec?.relative !== '__all') && (
8687
<>
8788
<Button data-cy='create-new-test-button' size='20' onClick={_launchStudio} variant='outline-dark' className={cs('launch-studio-button')} >
8889
<IconActionAddMedium strokeColor='gray-500' />
@@ -104,6 +105,7 @@ const Suite: React.FC<SuiteProps> = observer(({ eventManager = events, model, st
104105
studioEnabled={studioEnabled}
105106
canSaveStudioLogs={canSaveStudioLogs}
106107
shouldShowConnectingDots={shouldShowConnectionDots(model.children, runnable, index)}
108+
spec={spec}
107109
/>)
108110
})}
109111
</ul>
@@ -134,13 +136,14 @@ export interface RunnableProps {
134136
studioEnabled: boolean
135137
canSaveStudioLogs: boolean
136138
shouldShowConnectingDots: boolean
139+
spec?: Cypress.Cypress['spec']
137140
}
138141

139142
// NOTE: some of the driver tests dig into the React instance for this component
140143
// in order to mess with its internal state. converting it to a functional
141144
// component breaks that, so it needs to stay a Class-based component or
142145
// else the driver tests need to be refactored to support it being functional
143-
const Runnable: React.FC<RunnableProps> = observer(({ appState: appStateProps = appState, model, studioEnabled, canSaveStudioLogs, shouldShowConnectingDots }) => {
146+
const Runnable: React.FC<RunnableProps> = observer(({ appState: appStateProps = appState, model, studioEnabled, canSaveStudioLogs, shouldShowConnectingDots, spec }) => {
144147
return (<>
145148
<li
146149
className={cs(`${model.type} runnable runnable-${model.state}`, {
@@ -151,10 +154,11 @@ const Runnable: React.FC<RunnableProps> = observer(({ appState: appStateProps =
151154
data-model-state={model.state}
152155
>
153156
{model.type === 'test'
154-
? <Test model={model as TestModel} studioEnabled={studioEnabled} canSaveStudioLogs={canSaveStudioLogs} />
157+
? <Test model={model as TestModel} studioEnabled={studioEnabled} canSaveStudioLogs={canSaveStudioLogs} spec={spec} />
155158
: <Suite model={model as SuiteModel}
156159
studioEnabled={studioEnabled}
157160
canSaveStudioLogs={canSaveStudioLogs}
161+
spec={spec}
158162
/>}
159163
</li>
160164
{shouldShowConnectingDots && <div className='runnable-dotted-line' />}

packages/reporter/src/runnables/runnables.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ interface RunnablesListProps {
8888
runnables: RunnableArray
8989
studioEnabled: boolean
9090
canSaveStudioLogs: boolean
91+
spec: Cypress.Cypress['spec']
9192
}
9293

93-
const RunnablesList: React.FC<RunnablesListProps> = observer(({ runnables, studioEnabled, canSaveStudioLogs }: RunnablesListProps) => {
94+
const RunnablesList: React.FC<RunnablesListProps> = observer(({ runnables, studioEnabled, canSaveStudioLogs, spec }: RunnablesListProps) => {
9495
return (
9596
<div className='wrap'>
9697
<ul className='runnables'>
@@ -101,6 +102,7 @@ const RunnablesList: React.FC<RunnablesListProps> = observer(({ runnables, studi
101102
canSaveStudioLogs={canSaveStudioLogs}
102103
studioEnabled={studioEnabled}
103104
shouldShowConnectingDots={shouldShowConnectionDots(runnables, runnable, index)}
105+
spec={spec}
104106
/>))}
105107
</ul>
106108
</div>
@@ -143,6 +145,7 @@ const RunnablesContent: React.FC<RunnablesContentProps> = observer(({ runnablesS
143145
runnables={isRunning ? runnables : runnablesHistory[specPath]}
144146
studioEnabled={studioEnabled}
145147
canSaveStudioLogs={canSaveStudioLogs}
148+
spec={spec}
146149
/>
147150
)
148151
})

packages/reporter/src/test/test.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,10 @@ interface TestProps {
8888
model: TestModel
8989
studioEnabled: boolean
9090
canSaveStudioLogs: boolean
91+
spec?: Cypress.Cypress['spec']
9192
}
9293

93-
const Test: React.FC<TestProps> = observer(({ model, events: eventsProps = events, appState: appStateProps = appState, scroller: scrollerProps = scroller, studioEnabled, canSaveStudioLogs }) => {
94+
const Test: React.FC<TestProps> = observer(({ model, events: eventsProps = events, appState: appStateProps = appState, scroller: scrollerProps = scroller, studioEnabled, canSaveStudioLogs, spec }) => {
9495
const containerRef = useRef(null)
9596
const [isMounted, setIsMounted] = useState(false)
9697

@@ -135,7 +136,10 @@ const Test: React.FC<TestProps> = observer(({ model, events: eventsProps = event
135136
const _controls = () => {
136137
let controls: Array<JSX.Element> = []
137138

138-
if (studioEnabled && !appStateProps.studioActive && model.state !== 'pending') {
139+
// Check if we're running all specs by looking at the spec relative path
140+
const isRunningAllSpecs = spec?.relative === '__all'
141+
142+
if (studioEnabled && !appStateProps.studioActive && model.state !== 'pending' && !isRunningAllSpecs) {
139143
controls.push(
140144
<LaunchStudioIcon
141145
key={`studio-command-${model}`}

0 commit comments

Comments
 (0)