diff --git a/packages/reporter/src/header/header.scss b/packages/reporter/src/header/header.scss index cc4ee5d5075..98c2d751420 100644 --- a/packages/reporter/src/header/header.scss +++ b/packages/reporter/src/header/header.scss @@ -95,6 +95,29 @@ $color-transition: color 150ms ease-out; align-items: center; flex: 1; + &.sticky-header { + position: sticky; + top: 64px; // Height of main header + z-index: 10; + background-color: $gray-1100; + + &::after { + content: ''; + position: absolute; + top: 100%; + left: 0; + right: 0; + height: 16px; + background: linear-gradient( + to bottom, + $gray-1100 0%, + rgba(22, 24, 39, 0.3) 100% + ); + pointer-events: none; + z-index: 9; + } + } + span > span > a > svg { margin-bottom: -2px; margin-right: 8px; diff --git a/packages/reporter/src/header/header.tsx b/packages/reporter/src/header/header.tsx index 7d97924865a..2a976c4edfb 100644 --- a/packages/reporter/src/header/header.tsx +++ b/packages/reporter/src/header/header.tsx @@ -19,9 +19,10 @@ export interface ReporterHeaderProps { statsStore: StatsStore runnablesStore: RunnablesStore spec?: Cypress.Cypress['spec'] + experimentalStudio?: boolean } -const Header: React.FC = observer(({ appState, events = defaultEvents, statsStore, runnablesStore, spec }: ReporterHeaderProps) => { +const Header: React.FC = observer(({ appState, events = defaultEvents, statsStore, runnablesStore, spec, experimentalStudio }: ReporterHeaderProps) => { return
{appState.isSpecsListOpen ? 'Collapse' : 'Expand'} Specs List F

} wrapperClassName='toggle-specs-wrapper' className='cy-tooltip'> @@ -44,7 +45,7 @@ const Header: React.FC = observer(({ appState, events = def
- {spec && } + {spec && }
diff --git a/packages/reporter/src/main.tsx b/packages/reporter/src/main.tsx index 9da21dad759..5f464166919 100644 --- a/packages/reporter/src/main.tsx +++ b/packages/reporter/src/main.tsx @@ -19,6 +19,21 @@ import TestingPreferences from './preferences/testing-preferences' import type { MobxRunnerStore } from '@packages/app/src/store/mobx-runner-store' import { StudioTestHeader } from './studio/StudioTestHeader' +// Import the config function to access experimental features +function getRunnerConfigFromWindow () { + try { + // Use the same approach as the app's reporter.ts + if (typeof window !== 'undefined' && window.__CYPRESS_CONFIG__?.base64Config) { + const { decodeBase64Unicode } = require('@packages/frontend-shared/src/utils/base64') + return JSON.parse(decodeBase64Unicode(window.__CYPRESS_CONFIG__.base64Config)) as Cypress.Config + } + } catch (e) { + // Fallback to empty config if parsing fails + console.warn('Failed to parse Cypress config:', e) + } + return {} as Cypress.Config +} + function usePrevious (value) { const ref = useRef() @@ -51,7 +66,10 @@ export interface SingleReporterProps extends BaseReporterProps { } // In React Class components (now deprecated), we used to use appState as a default prop. Now since defaultProps are not supported in functional components, we can use ES6 default params to accomplish the same thing -const Reporter: React.FC = observer(({ appState = appStateDefault, runner, className, error, runMode = 'single', studioEnabled, autoScrollingEnabled, isSpecsListOpen, resetStatsOnSpecChange, renderReporterHeader = (props: ReporterHeaderProps) =>
, runnerStore }) => { +const Reporter: React.FC = observer(({ appState = appStateDefault, runner, className, error, runMode = 'single', studioEnabled, autoScrollingEnabled, isSpecsListOpen, resetStatsOnSpecChange, renderReporterHeader = (props: ReporterHeaderProps) => { + const config = getRunnerConfigFromWindow() + return
+}, runnerStore }) => { const previousSpecRunId = usePrevious(runnerStore.specRunId) const [isMounted, setIsMounted] = useState(false) const [isInitialized, setIsInitialized] = useState(false) diff --git a/packages/reporter/src/runnables/runnable-header.tsx b/packages/reporter/src/runnables/runnable-header.tsx index 88a9a2bd251..02d3f1107c4 100644 --- a/packages/reporter/src/runnables/runnable-header.tsx +++ b/packages/reporter/src/runnables/runnable-header.tsx @@ -7,24 +7,34 @@ import { DebugDismiss } from '../header/DebugDismiss' import { Duration } from '../duration/duration' import { SpecFileName } from '../shared/SpecFileName' -const renderRunnableHeader = (children: ReactElement) =>
{children}
+const renderRunnableHeader = (children: ReactElement, enableStickyHeader?: boolean) => ( +
+ {children} +
+) interface RunnableHeaderProps { spec: Cypress.Cypress['spec'] statsStore: StatsStore runnablesStore: RunnablesStore + experimentalStudio?: boolean } -const RunnableHeader: React.FC = observer(({ spec, statsStore, runnablesStore }) => { +const RunnableHeader: React.FC = observer(({ spec, statsStore, runnablesStore, experimentalStudio }) => { if (spec.relative === '__all') { if (spec.specFilter) { return renderRunnableHeader( Specs matching "{spec.specFilter}", + experimentalStudio, ) } return renderRunnableHeader( All Specs, + experimentalStudio, ) } @@ -34,6 +44,7 @@ const RunnableHeader: React.FC = observer(({ spec, statsSto {runnablesStore.testFilter && runnablesStore.totalTests > 0 && } , + experimentalStudio, ) })