mirror of
https://github.com/cypress-io/cypress.git
synced 2026-03-06 06:49:18 -06:00
fix(component-testing): Video recording (#15140)
This commit is contained in:
committed by
GitHub
parent
c1c27a0c99
commit
02aec1eb62
@@ -210,7 +210,7 @@ commands:
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
- store_artifacts:
|
||||
path: /tmp/artifacts
|
||||
path: ./packages/runner-ct/cypress/videos
|
||||
- store-npm-logs
|
||||
|
||||
run-e2e-tests:
|
||||
|
||||
1
packages/runner-ct/.gitignore
vendored
Normal file
1
packages/runner-ct/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
cypress/videos/*
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"testFiles": "**/*spec.{ts,tsx}",
|
||||
"video": false
|
||||
"video": true
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference types="@percy/cypress" />
|
||||
import React from 'react'
|
||||
import { mount } from '@cypress/react'
|
||||
import App from '../../src/app/RunnerCt'
|
||||
import RunnerCt from '../../src/app/RunnerCt'
|
||||
import State from '../../src/lib/state'
|
||||
import '@packages/runner/src/main.scss'
|
||||
|
||||
@@ -12,18 +12,23 @@ class FakeEventManager {
|
||||
notifyRunningSpec = () => { }
|
||||
}
|
||||
|
||||
const fakeConfig = { projectName: 'Project', env: {}, isTextTerminal: false } as any as Cypress.RuntimeConfigOptions
|
||||
|
||||
describe('RunnerCt', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1000, 500)
|
||||
})
|
||||
|
||||
function assertSpecsListIs (state: 'closed' | 'open') {
|
||||
// for some reason should("not.be.visible") doesn't work here so ensure that specs list was outside of screen
|
||||
cy.get('[data-cy=specs-list]').then(([el]) => {
|
||||
const { x } = el.getBoundingClientRect()
|
||||
cy.get('[data-cy=specs-list]').then(($el) => {
|
||||
const { x } = $el[0].getBoundingClientRect()
|
||||
|
||||
state === 'closed' ? expect(x).to.be.lessThan(0) : expect(x).to.be.lessThan(0)
|
||||
})
|
||||
}
|
||||
|
||||
it('renders App', () => {
|
||||
cy.viewport(1000, 500)
|
||||
it('renders RunnerCt', () => {
|
||||
const state = new State({
|
||||
reporterWidth: 500,
|
||||
spec: null,
|
||||
@@ -31,11 +36,30 @@ describe('RunnerCt', () => {
|
||||
})
|
||||
|
||||
mount(
|
||||
<App
|
||||
<RunnerCt
|
||||
state={state}
|
||||
// @ts-ignore - this is difficult to stub. Real one breaks things.
|
||||
eventManager={new FakeEventManager()}
|
||||
config={{ projectName: 'Project', env: {} }}
|
||||
config={fakeConfig}
|
||||
/>,
|
||||
)
|
||||
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('renders RunnerCt for video recording', () => {
|
||||
const state = new State({
|
||||
reporterWidth: 500,
|
||||
spec: null,
|
||||
specs: [{ relative: '/test.js', absolute: 'root/test.js', name: 'test.js' }],
|
||||
})
|
||||
|
||||
mount(
|
||||
<RunnerCt
|
||||
state={state}
|
||||
// @ts-ignore - this is difficult to stub. Real one breaks things.
|
||||
eventManager={new FakeEventManager()}
|
||||
config={{ ...fakeConfig, isTextTerminal: true }}
|
||||
/>,
|
||||
)
|
||||
|
||||
@@ -44,7 +68,6 @@ describe('RunnerCt', () => {
|
||||
|
||||
context('keyboard shortcuts', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1000, 500)
|
||||
const state = new State({
|
||||
reporterWidth: 500,
|
||||
spec: null,
|
||||
@@ -52,11 +75,11 @@ describe('RunnerCt', () => {
|
||||
})
|
||||
|
||||
mount(
|
||||
<App
|
||||
<RunnerCt
|
||||
state={state}
|
||||
// @ts-ignore - this is difficult to stub. Real one breaks things.
|
||||
eventManager={new FakeEventManager()}
|
||||
config={{ projectName: 'Project', env: {} }}
|
||||
config={fakeConfig}
|
||||
/>,
|
||||
)
|
||||
|
||||
@@ -80,7 +103,6 @@ describe('RunnerCt', () => {
|
||||
|
||||
context('specs-list resizing', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1000, 500)
|
||||
const state = new State({
|
||||
reporterWidth: 500,
|
||||
spec: null,
|
||||
@@ -88,11 +110,11 @@ describe('RunnerCt', () => {
|
||||
})
|
||||
|
||||
mount(
|
||||
<App
|
||||
<RunnerCt
|
||||
state={state}
|
||||
// @ts-ignore - this is difficult to stub. Real one breaks things.
|
||||
eventManager={new FakeEventManager()}
|
||||
config={{ projectName: 'Project', env: {} }}
|
||||
config={fakeConfig}
|
||||
/>,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -69,9 +69,12 @@ main.app-ct {
|
||||
|
||||
.app-wrapper {
|
||||
position: relative;
|
||||
width: calc(100vw - #{$specs-list-offset});
|
||||
height: 100vh;
|
||||
margin-inline: $specs-list-offset;
|
||||
|
||||
&.with-specs-drawer {
|
||||
width: calc(100vw - #{$specs-list-offset});
|
||||
margin-inline: $specs-list-offset;
|
||||
}
|
||||
}
|
||||
|
||||
.app-wrapper-screenshotting {
|
||||
|
||||
@@ -24,17 +24,10 @@ import './RunnerCt.scss'
|
||||
import { KeyboardHelper, NoSpecSelected } from './NoSpecSelected'
|
||||
import { useScreenshotHandler } from './useScreenshotHandler'
|
||||
|
||||
// Cypress.ConfigOptions only appears to have internal options.
|
||||
// TODO: figure out where the "source of truth" should be for
|
||||
// an internal options interface.
|
||||
export interface ExtendedConfigOptions extends Cypress.ConfigOptions {
|
||||
projectName: string
|
||||
}
|
||||
|
||||
interface AppProps {
|
||||
state: State
|
||||
eventManager: typeof EventManager
|
||||
config: ExtendedConfigOptions
|
||||
config: Cypress.RuntimeConfigOptions
|
||||
}
|
||||
|
||||
const DEFAULT_LEFT_SIDE_OF_SPLITPANE_WIDTH = 355
|
||||
@@ -48,10 +41,11 @@ const App: React.FC<AppProps> = observer(
|
||||
const pluginRootContainer = React.useRef<null | HTMLDivElement>(null)
|
||||
|
||||
const { state, eventManager, config } = props
|
||||
const isOpenMode = !config.isTextTerminal
|
||||
|
||||
const [pluginsHeight, setPluginsHeight] = React.useState(500)
|
||||
const [isResizing, setIsResizing] = React.useState(false)
|
||||
const [isSpecsListOpen, setIsSpecsListOpen] = React.useState(true)
|
||||
const [isSpecsListOpen, setIsSpecsListOpen] = React.useState(isOpenMode)
|
||||
const [drawerWidth, setDrawerWidth] = React.useState(300)
|
||||
const windowSize = useWindowSize()
|
||||
const [leftSideOfSplitPaneWidth, setLeftSideOfSplitPaneWidth] = React.useState(DEFAULT_LEFT_SIDE_OF_SPLITPANE_WIDTH)
|
||||
@@ -124,47 +118,53 @@ const App: React.FC<AppProps> = observer(
|
||||
return (
|
||||
<>
|
||||
<main className="app-ct">
|
||||
<div
|
||||
className={cs(
|
||||
'specs-list-drawer',
|
||||
{
|
||||
'display-none': state.screenshotting,
|
||||
},
|
||||
)}
|
||||
style={{
|
||||
transform: isSpecsListOpen ? `translateX(0)` : `translateX(-${drawerWidth - 20}px)`,
|
||||
}}
|
||||
>
|
||||
<ResizableBox
|
||||
disabled={!isSpecsListOpen}
|
||||
width={drawerWidth}
|
||||
onIsResizingChange={setIsResizing}
|
||||
onWidthChange={setDrawerWidth}
|
||||
className="specs-list-container"
|
||||
data-cy="specs-list-resize-box"
|
||||
minWidth={200}
|
||||
maxWidth={windowSize.width / 100 * 80} // 80vw
|
||||
{isOpenMode && (
|
||||
<div
|
||||
className={cs(
|
||||
'specs-list-drawer',
|
||||
{
|
||||
'display-none': state.screenshotting,
|
||||
},
|
||||
)}
|
||||
style={{
|
||||
transform: isSpecsListOpen ? `translateX(0)` : `translateX(-${drawerWidth - 20}px)`,
|
||||
}}
|
||||
>
|
||||
<nav>
|
||||
<a
|
||||
id="menu-toggle"
|
||||
onClick={() => setIsSpecsListOpen(!isSpecsListOpen)}
|
||||
className="menu-toggle"
|
||||
aria-label="Open the menu"
|
||||
>
|
||||
<Burger />
|
||||
</a>
|
||||
</nav>
|
||||
<SpecList
|
||||
specs={state.specs}
|
||||
inputRef={searchRef}
|
||||
disableTextSelection={isResizing}
|
||||
selectedSpecs={state.spec ? [state.spec.absolute] : []}
|
||||
onSelectSpec={runSpec}
|
||||
/>
|
||||
</ResizableBox>
|
||||
</div>
|
||||
<div className={cs('app-wrapper', { 'app-wrapper-screenshotting': state.screenshotting })}>
|
||||
<ResizableBox
|
||||
disabled={!isSpecsListOpen}
|
||||
width={drawerWidth}
|
||||
onIsResizingChange={setIsResizing}
|
||||
onWidthChange={setDrawerWidth}
|
||||
className="specs-list-container"
|
||||
data-cy="specs-list-resize-box"
|
||||
minWidth={200}
|
||||
maxWidth={windowSize.width / 100 * 80} // 80vw
|
||||
>
|
||||
<nav>
|
||||
<a
|
||||
id="menu-toggle"
|
||||
onClick={() => setIsSpecsListOpen(!isSpecsListOpen)}
|
||||
className="menu-toggle"
|
||||
aria-label="Open the menu"
|
||||
>
|
||||
<Burger />
|
||||
</a>
|
||||
</nav>
|
||||
<SpecList
|
||||
specs={state.specs}
|
||||
inputRef={searchRef}
|
||||
disableTextSelection={isResizing}
|
||||
selectedSpecs={state.spec ? [state.spec.absolute] : []}
|
||||
onSelectSpec={runSpec}
|
||||
/>
|
||||
</ResizableBox>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={cs('app-wrapper', {
|
||||
'with-specs-drawer': isOpenMode,
|
||||
'app-wrapper-screenshotting': state.screenshotting,
|
||||
})}>
|
||||
<SplitPane
|
||||
split="vertical"
|
||||
primary="first"
|
||||
|
||||
@@ -280,7 +280,7 @@ export default class State {
|
||||
}
|
||||
|
||||
@action
|
||||
initializePlugins = (config: Cypress.ConfigOptions, rootElement: HTMLElement) => {
|
||||
initializePlugins = (config: Cypress.RuntimeConfigOptions, rootElement: HTMLElement) => {
|
||||
if (config.env.reactDevtools) {
|
||||
this.loadReactDevTools(rootElement)
|
||||
.then(action(() => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const run = (options) => {
|
||||
// TODO make sure if we need to run this in electron by default to match e2e behavior?
|
||||
options.browser = options.browser || 'chrome'
|
||||
|
||||
// if we're in run mode with component
|
||||
|
||||
Reference in New Issue
Block a user