mirror of
https://github.com/cypress-io/cypress.git
synced 2026-02-12 02:00:06 -06:00
Merge pull request #16831 from cypress-io/8.0-release
BREAKING CHANGE: 8.0 release
This commit is contained in:
@@ -69,8 +69,8 @@ exports['shows help for run --foo 1'] = `
|
||||
-e, --env <env> sets environment variables. separate multiple values with a comma. overrides any value in cypress.json or cypress.env.json
|
||||
--group <name> a named group for recorded runs in the Cypress Dashboard
|
||||
-k, --key <record-key> your secret Record Key. you can omit this if you set a CYPRESS_RECORD_KEY environment variable.
|
||||
--headed displays the browser instead of running headlessly (defaults to true for Firefox and Chromium-family browsers)
|
||||
--headless hide the browser instead of running headed (defaults to true for Electron)
|
||||
--headed displays the browser instead of running headlessly
|
||||
--headless hide the browser instead of running headed (default for cypress run)
|
||||
--no-exit keep the browser open after tests finish
|
||||
--parallel enables concurrent runs and automatic load balancing of specs across multiple machines or processes
|
||||
-p, --port <port> runs Cypress on a specific port. overrides any value in cypress.json.
|
||||
|
||||
@@ -115,8 +115,8 @@ const descriptions = {
|
||||
forceInstall: 'force install the Cypress binary',
|
||||
global: 'force Cypress into global mode as if its globally installed',
|
||||
group: 'a named group for recorded runs in the Cypress Dashboard',
|
||||
headed: 'displays the browser instead of running headlessly (defaults to true for Firefox and Chromium-family browsers)',
|
||||
headless: 'hide the browser instead of running headed (defaults to true for Electron)',
|
||||
headed: 'displays the browser instead of running headlessly',
|
||||
headless: 'hide the browser instead of running headed (default for cypress run)',
|
||||
key: 'your secret Record Key. you can omit this if you set a CYPRESS_RECORD_KEY environment variable.',
|
||||
parallel: 'enables concurrent runs and automatic load balancing of specs across multiple machines or processes',
|
||||
port: 'runs Cypress on a specific port. overrides any value in cypress.json.',
|
||||
|
||||
2
cli/types/cypress-npm-api.d.ts
vendored
2
cli/types/cypress-npm-api.d.ts
vendored
@@ -138,7 +138,7 @@ declare namespace CypressCommandLine {
|
||||
/**
|
||||
* Specify configuration
|
||||
*/
|
||||
config: Partial<Cypress.ResolvedConfigOptions>
|
||||
config: Cypress.ConfigOptions
|
||||
/**
|
||||
* Path to the config file to be used.
|
||||
*
|
||||
|
||||
100
cli/types/cypress.d.ts
vendored
100
cli/types/cypress.d.ts
vendored
@@ -64,6 +64,22 @@ declare namespace Cypress {
|
||||
path: string
|
||||
isHeaded: boolean
|
||||
isHeadless: boolean
|
||||
/**
|
||||
* Informational text to accompany this browser. Shown in desktop-gui.
|
||||
*/
|
||||
info?: string
|
||||
/**
|
||||
* Warning text to accompany this browser. Shown in desktop-gui.
|
||||
*/
|
||||
warning?: string
|
||||
/**
|
||||
* The minimum majorVersion of this browser supported by Cypress.
|
||||
*/
|
||||
minSupportedVersion?: number
|
||||
/**
|
||||
* If `true`, this browser is too old to be supported by Cypress.
|
||||
*/
|
||||
unsupportedVersion?: boolean
|
||||
}
|
||||
|
||||
interface LocalStorage {
|
||||
@@ -341,15 +357,6 @@ declare namespace Cypress {
|
||||
*/
|
||||
env(object: ObjectLike): void
|
||||
|
||||
/**
|
||||
* Firefox only: Get the current number of tests that will run between forced garbage collections.
|
||||
*
|
||||
* Returns undefined if not in Firefox, returns a null or 0 if forced GC is disabled.
|
||||
*
|
||||
* @see https://on.cypress.io/firefox-gc-issue
|
||||
*/
|
||||
getFirefoxGcInterval(): number | null | undefined
|
||||
|
||||
/**
|
||||
* @returns the number of test retries currently enabled for the run
|
||||
*/
|
||||
@@ -1833,6 +1840,12 @@ declare namespace Cypress {
|
||||
* @see https://on.cypress.io/then
|
||||
*/
|
||||
then<S>(options: Partial<Timeoutable>, fn: (this: ObjectLike, currentSubject: Subject) => PromiseLike<S>): Chainable<S>
|
||||
/**
|
||||
* Enables you to work with the subject yielded from the previous command / promise.
|
||||
*
|
||||
* @see https://on.cypress.io/then
|
||||
*/
|
||||
then<S extends string | number | boolean>(fn: (this: ObjectLike, currentSubject: Subject) => S): Chainable<S>
|
||||
/**
|
||||
* Enables you to work with the subject yielded from the previous command / promise.
|
||||
*
|
||||
@@ -1850,7 +1863,7 @@ declare namespace Cypress {
|
||||
*
|
||||
* @see https://on.cypress.io/then
|
||||
*/
|
||||
then<S extends object | any[] | string | number | boolean>(fn: (this: ObjectLike, currentSubject: Subject) => S): Chainable<S>
|
||||
then<S extends any[] | object>(fn: (this: ObjectLike, currentSubject: Subject) => S): Chainable<S>
|
||||
/**
|
||||
* Enables you to work with the subject yielded from the previous command / promise.
|
||||
*
|
||||
@@ -2640,13 +2653,6 @@ declare namespace Cypress {
|
||||
* @default 'top'
|
||||
*/
|
||||
scrollBehavior: scrollBehaviorOptions
|
||||
/**
|
||||
* Firefox version 79 and below only: The number of tests that will run between forced garbage collections.
|
||||
* If a number is supplied, it will apply to `run` mode and `open` mode.
|
||||
* Set the interval to `null` or 0 to disable forced garbage collections.
|
||||
* @default { runMode: 1, openMode: null }
|
||||
*/
|
||||
firefoxGcInterval: Nullable<number | { runMode: Nullable<number>, openMode: Nullable<number> }>
|
||||
/**
|
||||
* Allows listening to the `before:run`, `after:run`, `before:spec`, and `after:spec` events in the plugins file during interactive mode.
|
||||
* @default false
|
||||
@@ -2678,17 +2684,46 @@ declare namespace Cypress {
|
||||
*/
|
||||
includeShadowDom: boolean
|
||||
|
||||
/**
|
||||
* The list of hosts to be blocked
|
||||
*/
|
||||
blockHosts: null | string | string[]
|
||||
/**
|
||||
* Path to folder containing component test files.
|
||||
*/
|
||||
componentFolder: false | string
|
||||
/**
|
||||
* A unique ID for the project used for recording
|
||||
*/
|
||||
projectId: null | string
|
||||
/**
|
||||
* Path to the support folder.
|
||||
*/
|
||||
supportFolder: string
|
||||
/**
|
||||
* Glob pattern to determine what test files to load.
|
||||
*/
|
||||
testFiles: string | string[]
|
||||
/**
|
||||
* The user agent the browser sends in all request headers.
|
||||
*/
|
||||
userAgent: null | string
|
||||
/**
|
||||
* Polyfills `window.fetch` to enable Network spying and stubbing
|
||||
*/
|
||||
experimentalFetchPolyfill: boolean
|
||||
|
||||
/**
|
||||
* Override default config options for Component Testing runner.
|
||||
* @default {}
|
||||
*/
|
||||
component: ResolvedConfigOptions
|
||||
component: Omit<ResolvedConfigOptions, 'e2e' | 'component'>
|
||||
|
||||
/**
|
||||
* Override default config options for E2E Testing runner.
|
||||
* @default {}
|
||||
*/
|
||||
e2e: ResolvedConfigOptions
|
||||
e2e: Omit<ResolvedConfigOptions, 'e2e' | 'component'>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2701,10 +2736,6 @@ declare namespace Cypress {
|
||||
* @see https://nodejs.org/api/os.html#os_os_arch
|
||||
*/
|
||||
arch: string
|
||||
/**
|
||||
* The list of hosts to be blocked
|
||||
*/
|
||||
blockHosts: null | string | string[]
|
||||
/**
|
||||
* The browser Cypress is running on.
|
||||
*/
|
||||
@@ -2713,10 +2744,6 @@ declare namespace Cypress {
|
||||
* Available browsers found on your system.
|
||||
*/
|
||||
browsers: Browser[]
|
||||
/**
|
||||
* Path to folder containing component test files.
|
||||
*/
|
||||
componentFolder: string
|
||||
/**
|
||||
* Hosts mappings to IP addresses.
|
||||
*/
|
||||
@@ -2736,22 +2763,6 @@ declare namespace Cypress {
|
||||
* The platform Cypress is running on.
|
||||
*/
|
||||
platform: 'linux' | 'darwin' | 'win32'
|
||||
/**
|
||||
* A unique ID for the project used for recording
|
||||
*/
|
||||
projectId: null | string
|
||||
/**
|
||||
* Path to the support folder.
|
||||
*/
|
||||
supportFolder: string
|
||||
/**
|
||||
* Glob pattern to determine what test files to load.
|
||||
*/
|
||||
testFiles: string
|
||||
/**
|
||||
* The user agent the browser sends in all request headers.
|
||||
*/
|
||||
userAgent: null | string
|
||||
/**
|
||||
* The Cypress version being used.
|
||||
*/
|
||||
@@ -2798,7 +2809,8 @@ declare namespace Cypress {
|
||||
/**
|
||||
* All configuration items are optional.
|
||||
*/
|
||||
type ConfigOptions = Partial<ResolvedConfigOptions>
|
||||
type CoreConfigOptions = Partial<Omit<ResolvedConfigOptions, 'e2e' | 'component'>>
|
||||
type ConfigOptions = CoreConfigOptions & {e2e?: CoreConfigOptions, component?: CoreConfigOptions }
|
||||
|
||||
interface PluginConfigOptions extends ResolvedConfigOptions {
|
||||
/**
|
||||
|
||||
@@ -257,6 +257,15 @@ describe('then', () => {
|
||||
$p // $ExpectType JQuery<HTMLParagraphElement>
|
||||
})
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/16669
|
||||
it('any as default', () => {
|
||||
cy.get('body')
|
||||
.then(() => ({} as any))
|
||||
.then(v => {
|
||||
v // $ExpectType any
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
cy.wait(['@foo', '@bar'])
|
||||
|
||||
@@ -83,7 +83,8 @@
|
||||
"channel": "stable",
|
||||
"version": "69.0.1",
|
||||
"path": "/Applications/Firefox/Contents/MacOS/Firefox",
|
||||
"majorVersion": "69"
|
||||
"majorVersion": "69",
|
||||
"unsupportedVersion": true
|
||||
},
|
||||
{
|
||||
"name": "firefox",
|
||||
|
||||
@@ -204,6 +204,20 @@ describe('Project Nav', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('has unsupportedVersions styled and unselectable', function () {
|
||||
cy.get('.browsers-list .dropdown-chosen').click()
|
||||
|
||||
cy.get('.browsers-list').find('.dropdown-menu')
|
||||
.find('li').should('have.length', this.config.browsers.length - 1)
|
||||
.contains('span', 'Firefox 69')
|
||||
.should('have.class', 'unsupported-version')
|
||||
.click()
|
||||
|
||||
cy.get('.browsers-list .dropdown-menu').should('be.visible')
|
||||
|
||||
cy.get('.browsers-list .dropdown-chosen').contains('Chromium')
|
||||
})
|
||||
|
||||
it('saves chosen browser in local storage', () => {
|
||||
expect(localStorage.getItem('chosenBrowser')).to.eq(JSON.stringify({ name: 'chromium', channel: 'stable' }))
|
||||
})
|
||||
@@ -255,7 +269,7 @@ describe('Project Nav', function () {
|
||||
const browserArg = this.ipc.launchBrowser.getCall(0).args[0].browser
|
||||
|
||||
expect(browserArg).to.have.keys([
|
||||
'family', 'name', 'path', 'profilePath', 'version', 'majorVersion', 'displayName', 'info', 'isChosen', 'custom', 'warning', 'channel',
|
||||
'family', 'name', 'path', 'profilePath', 'version', 'majorVersion', 'displayName', 'info', 'isChosen', 'custom', 'warning', 'channel', 'unsupportedVersion',
|
||||
])
|
||||
|
||||
expect(browserArg.path).to.include('/')
|
||||
@@ -364,6 +378,22 @@ describe('Project Nav', function () {
|
||||
})
|
||||
})
|
||||
|
||||
describe('when browser saved in local storage has an unsupported version', function () {
|
||||
beforeEach(function () {
|
||||
localStorage.setItem('chosenBrowser', JSON.stringify({ name: 'firefox', channel: 'stable' }))
|
||||
|
||||
// sanity check: saved browser should be found in the config
|
||||
expect(this.config.browsers.find((b) => b.name === 'firefox' && b.channel === 'stable' && b.unsupportedVersion)).to.exist
|
||||
|
||||
this.openProject.resolve(this.config)
|
||||
})
|
||||
|
||||
it('defaults to first browser', () => {
|
||||
cy.get('.browsers-list .dropdown-chosen')
|
||||
.should('contain', 'Chrome')
|
||||
})
|
||||
})
|
||||
|
||||
describe('only one browser available', function () {
|
||||
beforeEach(function () {
|
||||
this.config.browsers = [{
|
||||
|
||||
@@ -236,6 +236,13 @@
|
||||
li {
|
||||
padding: 9px 15px;
|
||||
white-space: nowrap;
|
||||
|
||||
.unsupported-version {
|
||||
color: #888;
|
||||
img {
|
||||
filter: opacity(0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-chosen {
|
||||
|
||||
@@ -12,6 +12,7 @@ export default class Browser {
|
||||
@observable info
|
||||
@observable custom
|
||||
@observable warning
|
||||
@observable unsupportedVersion
|
||||
@observable isChosen = false
|
||||
|
||||
constructor (browser) {
|
||||
@@ -26,5 +27,6 @@ export default class Browser {
|
||||
this.info = browser.info
|
||||
this.custom = browser.custom
|
||||
this.warning = browser.warning
|
||||
this.unsupportedVersion = browser.unsupportedVersion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { Component } from 'react'
|
||||
import { observer } from 'mobx-react'
|
||||
import cs from 'classnames'
|
||||
import Tooltip from '@cypress/react-tooltip'
|
||||
import { BrowserIcon, Dropdown } from '@packages/ui-components'
|
||||
|
||||
@@ -49,6 +50,8 @@ export default class Browsers extends Component {
|
||||
}
|
||||
|
||||
_onSelect = (browser) => {
|
||||
if (browser.unsupportedVersion) return true
|
||||
|
||||
this.props.project.setChosenBrowser(browser)
|
||||
}
|
||||
|
||||
@@ -69,14 +72,14 @@ export default class Browsers extends Component {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className={cs({ 'unsupported-version': browser.unsupportedVersion })}>
|
||||
{icon}{' '}
|
||||
{prefixText}{' '}
|
||||
{browser.displayName}{' '}
|
||||
{browser.majorVersion}
|
||||
{this._info(browser)}
|
||||
{this._warn(browser)}
|
||||
</>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -119,12 +119,16 @@ export default class Project {
|
||||
return _.filter(this.browsers, { isChosen: false })
|
||||
}
|
||||
|
||||
@computed get supportedBrowsers () {
|
||||
return _.filter(this.browsers, (browser) => !browser.unsupportedVersion)
|
||||
}
|
||||
|
||||
@computed get chosenBrowser () {
|
||||
return _.find(this.browsers, { isChosen: true })
|
||||
}
|
||||
|
||||
@computed get defaultBrowser () {
|
||||
return this.browsers[0]
|
||||
return this.supportedBrowsers[0]
|
||||
}
|
||||
|
||||
@computed get warnings () {
|
||||
@@ -173,7 +177,7 @@ export default class Project {
|
||||
// use a custom browser if one is supplied. or, if they already have
|
||||
// a browser chosen that's been saved in localStorage, then select that
|
||||
// otherwise just do the default.
|
||||
const customBrowser = _.find(this.browsers, { custom: true })
|
||||
const customBrowser = _.find(this.supportedBrowsers, { custom: true })
|
||||
|
||||
if (customBrowser) {
|
||||
return this.setChosenBrowser(customBrowser, { save: false })
|
||||
@@ -260,7 +264,7 @@ export default class Project {
|
||||
filter.name = ls
|
||||
}
|
||||
|
||||
const browser = _.find(this.browsers, filter) || this.defaultBrowser
|
||||
const browser = _.find(this.supportedBrowsers, filter) || this.defaultBrowser
|
||||
|
||||
this.setChosenBrowser(browser)
|
||||
}
|
||||
|
||||
@@ -4007,15 +4007,15 @@ describe('mouse state', () => {
|
||||
// TODO: add back assertion on Y values
|
||||
const coordsFirefox = {
|
||||
clientX: 494,
|
||||
// clientY: 10,
|
||||
clientY: 10,
|
||||
// layerX: 492,
|
||||
// layerY: 215,
|
||||
pageX: 494,
|
||||
pageY: 226,
|
||||
screenX: 494,
|
||||
// screenY: 10,
|
||||
screenY: 10,
|
||||
x: 494,
|
||||
// y: 10,
|
||||
y: 10,
|
||||
}
|
||||
|
||||
let coords
|
||||
@@ -4030,8 +4030,7 @@ describe('mouse state', () => {
|
||||
}
|
||||
|
||||
const mouseout = cy.stub().callsFake((e) => {
|
||||
expect(_.toPlainObject(e)).to.containSubset({
|
||||
...coords,
|
||||
const exp = {
|
||||
altKey: false,
|
||||
bubbles: true,
|
||||
button: 0,
|
||||
@@ -4059,13 +4058,16 @@ describe('mouse state', () => {
|
||||
type: 'mouseout',
|
||||
view: cy.state('window'),
|
||||
// which: 0,
|
||||
})
|
||||
}
|
||||
|
||||
expect(_.pick(e, _.keys(exp))).to.containSubset(exp)
|
||||
_.each(coords, (v, key) => expect(e[key], key).closeTo(v, 1))
|
||||
|
||||
e.target.removeEventListener('mouseout', mouseout)
|
||||
}).as('mouseout')
|
||||
|
||||
const mouseleave = cy.stub().callsFake((e) => {
|
||||
expect(_.toPlainObject(e)).to.containSubset({
|
||||
...coords,
|
||||
const exp = {
|
||||
altKey: false,
|
||||
bubbles: false,
|
||||
button: 0,
|
||||
@@ -4094,13 +4096,16 @@ describe('mouse state', () => {
|
||||
type: 'mouseleave',
|
||||
view: cy.state('window'),
|
||||
// which: 0,
|
||||
})
|
||||
}
|
||||
|
||||
expect(_.pick(e, _.keys(exp))).to.containSubset(exp)
|
||||
_.each(coords, (v, key) => expect(e[key], key).closeTo(v, 1))
|
||||
|
||||
e.target.removeEventListener('mouseleave', mouseleave)
|
||||
}).as('mouseleave')
|
||||
|
||||
const pointerout = cy.stub().callsFake((e) => {
|
||||
expect(_.toPlainObject(e)).to.containSubset({
|
||||
...coords,
|
||||
const exp = {
|
||||
altKey: false,
|
||||
bubbles: true,
|
||||
button: -1,
|
||||
@@ -4129,13 +4134,15 @@ describe('mouse state', () => {
|
||||
type: 'pointerout',
|
||||
view: cy.state('window'),
|
||||
// which: 0,
|
||||
})
|
||||
}
|
||||
|
||||
expect(_.pick(e, _.keys(exp))).to.containSubset(exp)
|
||||
_.each(coords, (v, key) => expect(e[key], key).closeTo(v, 1))
|
||||
|
||||
e.target.removeEventListener('pointerout', pointerout)
|
||||
}).as('pointerout')
|
||||
const pointerleave = cy.stub().callsFake((e) => {
|
||||
expect(_.toPlainObject(e)).to.containSubset({
|
||||
...coords,
|
||||
const exp = {
|
||||
altKey: false,
|
||||
bubbles: false,
|
||||
button: -1,
|
||||
@@ -4164,13 +4171,15 @@ describe('mouse state', () => {
|
||||
type: 'pointerleave',
|
||||
view: cy.state('window'),
|
||||
// which: 0,
|
||||
})
|
||||
}
|
||||
|
||||
expect(_.pick(e, _.keys(exp))).to.containSubset(exp)
|
||||
_.each(coords, (v, key) => expect(e[key], key).closeTo(v, 1))
|
||||
|
||||
e.target.removeEventListener('pointerleave', pointerleave)
|
||||
}).as('pointerleave')
|
||||
const mouseover = cy.stub().callsFake((e) => {
|
||||
expect(_.toPlainObject(e)).to.containSubset({
|
||||
...coords,
|
||||
const exp = {
|
||||
altKey: false,
|
||||
bubbles: true,
|
||||
button: 0,
|
||||
@@ -4199,13 +4208,15 @@ describe('mouse state', () => {
|
||||
type: 'mouseover',
|
||||
view: cy.state('window'),
|
||||
// which: 0,
|
||||
})
|
||||
}
|
||||
|
||||
expect(_.pick(e, _.keys(exp))).to.containSubset(exp)
|
||||
_.each(coords, (v, key) => expect(e[key], key).closeTo(v, 1))
|
||||
|
||||
e.target.removeEventListener('mouseover', mouseover)
|
||||
}).as('mouseover')
|
||||
const mouseenter = cy.stub().callsFake((e) => {
|
||||
expect(_.toPlainObject(e)).to.containSubset({
|
||||
...coords,
|
||||
const exp = {
|
||||
altKey: false,
|
||||
bubbles: false,
|
||||
button: 0,
|
||||
@@ -4234,13 +4245,15 @@ describe('mouse state', () => {
|
||||
type: 'mouseenter',
|
||||
view: cy.state('window'),
|
||||
// which: 0,
|
||||
})
|
||||
}
|
||||
|
||||
expect(_.pick(e, _.keys(exp))).to.containSubset(exp)
|
||||
_.each(coords, (v, key) => expect(e[key], key).closeTo(v, 1))
|
||||
|
||||
e.target.removeEventListener('mouseenter', mouseenter)
|
||||
}).as('mouseenter')
|
||||
const pointerover = cy.stub().callsFake((e) => {
|
||||
expect(_.toPlainObject(e)).to.containSubset({
|
||||
...coords,
|
||||
const exp = {
|
||||
altKey: false,
|
||||
bubbles: true,
|
||||
button: -1,
|
||||
@@ -4269,13 +4282,15 @@ describe('mouse state', () => {
|
||||
type: 'pointerover',
|
||||
view: cy.state('window'),
|
||||
// which: 0,
|
||||
})
|
||||
}
|
||||
|
||||
expect(_.pick(e, _.keys(exp))).to.containSubset(exp)
|
||||
_.each(coords, (v, key) => expect(e[key], key).closeTo(v, 1))
|
||||
|
||||
e.target.removeEventListener('pointerover', pointerover)
|
||||
}).as('pointerover')
|
||||
const pointerenter = cy.stub().callsFake((e) => {
|
||||
expect(_.toPlainObject(e)).to.containSubset({
|
||||
...coords,
|
||||
const exp = {
|
||||
altKey: false,
|
||||
bubbles: false,
|
||||
button: -1,
|
||||
@@ -4304,7 +4319,10 @@ describe('mouse state', () => {
|
||||
type: 'pointerenter',
|
||||
view: cy.state('window'),
|
||||
// which: 0,
|
||||
})
|
||||
}
|
||||
|
||||
expect(_.pick(e, _.keys(exp))).to.containSubset(exp)
|
||||
_.each(coords, (v, key) => expect(e[key], key).closeTo(v, 1))
|
||||
|
||||
e.target.removeEventListener('pointerenter', pointerenter)
|
||||
}).as('pointerenter')
|
||||
|
||||
@@ -312,8 +312,8 @@ describe('src/cypress/dom/visibility', () => {
|
||||
`)
|
||||
|
||||
this.$parentPointerEventsNone = add(`\
|
||||
<div style="pointer-events: none;">
|
||||
<span style="position: fixed; top: 20px;">parent pointer-events: none</span>
|
||||
<div style="pointer-events: none">
|
||||
<span style="position: fixed; left: 0; top: 50%;">parent pointer-events: none</span>
|
||||
</div>\
|
||||
`)
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
beforeEach(() => {
|
||||
Cypress.config('retries', 0)
|
||||
})
|
||||
|
||||
const autIframeHasFocus = () => Object.getOwnPropertyDescriptor(top.Document.prototype, 'hasFocus').value.call(top.frames[1].document)
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/1939
|
||||
it('has focus when running headlessly in electron', (done) => {
|
||||
it('has focus when running headlessly', () => {
|
||||
if (Cypress.browser.isHeadless) {
|
||||
// top (aka Cypress frame) should always be in focus
|
||||
// when running headlessly. if we aren't running headlessly
|
||||
// it may not be in focus if the user has clicked away.
|
||||
// we don't want this test to potentially fail in that case
|
||||
expect(top.document.hasFocus()).to.be.true
|
||||
done()
|
||||
} else {
|
||||
// else done and making sure only 2 path options are here
|
||||
done()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -19,6 +21,10 @@ it('sets the AUT document.hasFocus to top.document.hasFocus', () => {
|
||||
// the top does.
|
||||
cy.visit('/timeout')
|
||||
.then(() => {
|
||||
if (Cypress.browser.isHeadless) {
|
||||
return cy.document().invoke('hasFocus').should('be.true')
|
||||
}
|
||||
|
||||
if (top.document.hasFocus()) {
|
||||
return cy.document().invoke('hasFocus').should('be.true')
|
||||
}
|
||||
@@ -27,7 +33,7 @@ it('sets the AUT document.hasFocus to top.document.hasFocus', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('continues to have focus through top navigations', (done) => {
|
||||
it('continues to have focus through top navigation', () => {
|
||||
cy
|
||||
.visit('http://localhost:3501/fixtures/generic.html')
|
||||
.then(() => {
|
||||
@@ -36,11 +42,8 @@ it('continues to have focus through top navigations', (done) => {
|
||||
// when running headlessly. if we aren't running headlessly
|
||||
// it may not be in focus if the user has clicked away.
|
||||
// we don't want this test to potentially fail in that case
|
||||
expect(top.document.hasFocus()).to.be.true
|
||||
done()
|
||||
} else {
|
||||
// else done and making sure only 2 path options are here
|
||||
done()
|
||||
// it's OK if the autIframe has focus too, since that means the window still has focus
|
||||
expect(top.document.hasFocus() || autIframeHasFocus()).to.be.true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
import { createIntervalGetter, install } from '../../../src/util/firefox_forced_gc'
|
||||
|
||||
describe('driver/src/util/firefox_forced_gc', () => {
|
||||
describe('#createIntervalGetter returns a function that', () => {
|
||||
const run = (configObj) => {
|
||||
const fakeCypress = {
|
||||
config: (key) => {
|
||||
return key ? configObj[key] : configObj
|
||||
},
|
||||
browser: configObj.browser,
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return createIntervalGetter(fakeCypress)()
|
||||
}
|
||||
|
||||
it('returns undefined if not in Firefox', () => {
|
||||
expect(run({
|
||||
browser: {
|
||||
family: 'chrome',
|
||||
},
|
||||
})).to.be.undefined
|
||||
})
|
||||
|
||||
it('returns a number if firefoxGcInterval is a plain number', () => {
|
||||
expect(run({
|
||||
browser: {
|
||||
family: 'firefox',
|
||||
majorVersion: 79,
|
||||
},
|
||||
firefoxGcInterval: 99,
|
||||
})).to.eq(99)
|
||||
})
|
||||
|
||||
it('returns null if firefoxGcInterval is null', () => {
|
||||
expect(run({
|
||||
browser: {
|
||||
family: 'firefox',
|
||||
majorVersion: 79,
|
||||
},
|
||||
firefoxGcInterval: null,
|
||||
})).to.eq(null)
|
||||
})
|
||||
|
||||
it('returns the appropriate interval for open mode', () => {
|
||||
expect(run({
|
||||
browser: {
|
||||
family: 'firefox',
|
||||
majorVersion: 79,
|
||||
},
|
||||
firefoxGcInterval: {
|
||||
runMode: 10,
|
||||
openMode: 20,
|
||||
},
|
||||
isInteractive: true,
|
||||
})).to.eq(20)
|
||||
})
|
||||
|
||||
it('returns the appropriate interval for run mode', () => {
|
||||
expect(run({
|
||||
browser: {
|
||||
family: 'firefox',
|
||||
majorVersion: 79,
|
||||
},
|
||||
firefoxGcInterval: {
|
||||
runMode: 10,
|
||||
openMode: 20,
|
||||
},
|
||||
isInteractive: false,
|
||||
})).to.eq(10)
|
||||
})
|
||||
|
||||
it('has been correctly mounted at Cypress.getFirefoxGcInterval', {
|
||||
// @ts-ignore
|
||||
firefoxGcInterval: 5,
|
||||
}, () => {
|
||||
const real = Cypress.getFirefoxGcInterval
|
||||
const fake = createIntervalGetter(Cypress)
|
||||
|
||||
// conditional, so it can pass in non-ff browsers
|
||||
expect(real()).to.eq(fake()).and.eq(Cypress.isBrowser('firefox') && Cypress.browser.majorVersion < 80 ? 5 : undefined)
|
||||
})
|
||||
})
|
||||
|
||||
describe('#install', () => {
|
||||
let MockCypress: any
|
||||
let commandStartFn: any
|
||||
let testBeforeRunAsyncFn: any
|
||||
|
||||
beforeEach(() => {
|
||||
MockCypress = {
|
||||
on: cy.stub().throws(),
|
||||
emit: cy.stub().throws(),
|
||||
browser: {
|
||||
family: 'firefox',
|
||||
majorVersion: 79,
|
||||
},
|
||||
getFirefoxGcInterval: cy.stub().throws(),
|
||||
backend: cy.stub().throws(),
|
||||
}
|
||||
|
||||
commandStartFn = testBeforeRunAsyncFn = undefined
|
||||
|
||||
MockCypress.on.withArgs('command:start').callsFake((_, fn) => {
|
||||
commandStartFn = fn
|
||||
})
|
||||
|
||||
MockCypress.on.withArgs('test:before:run:async').callsFake((_, fn) => {
|
||||
testBeforeRunAsyncFn = fn
|
||||
})
|
||||
})
|
||||
|
||||
const fakeVisit = () => {
|
||||
commandStartFn({ get: cy.stub().throws().withArgs('name').returns('visit') })
|
||||
}
|
||||
|
||||
const fakeBeforeTestRun = (order) => {
|
||||
return testBeforeRunAsyncFn({ order }) || Promise.resolve()
|
||||
}
|
||||
|
||||
it('registers no event handlers if not in Firefox', () => {
|
||||
MockCypress.browser.family = 'chrome'
|
||||
|
||||
install(MockCypress)
|
||||
|
||||
expect(MockCypress.on).to.not.be.called
|
||||
})
|
||||
|
||||
// @see https://github.com/cypress-io/cypress/issues/8241
|
||||
it('registers no event handlers if in Firefox >= 80', () => {
|
||||
MockCypress.browser.majorVersion = 80
|
||||
|
||||
install(MockCypress)
|
||||
|
||||
expect(MockCypress.on).to.not.be.called
|
||||
})
|
||||
|
||||
it('triggers a forced GC correctly with interval = 1', () => {
|
||||
MockCypress.getFirefoxGcInterval.returns(1)
|
||||
|
||||
const forceGc = MockCypress.backend.withArgs('firefox:force:gc').resolves()
|
||||
const emitBefore = MockCypress.emit.withArgs('before:firefox:force:gc').returns()
|
||||
const emitAfter = MockCypress.emit.withArgs('after:firefox:force:gc').returns()
|
||||
|
||||
install(MockCypress)
|
||||
|
||||
return fakeBeforeTestRun(0).then(() => {
|
||||
fakeVisit()
|
||||
|
||||
return fakeBeforeTestRun(1)
|
||||
})
|
||||
.then(() => {
|
||||
expect(forceGc).to.be.calledOnce
|
||||
expect(emitBefore).to.be.calledOnce
|
||||
expect(emitAfter).to.be.calledOnce
|
||||
})
|
||||
.then(() => {
|
||||
return fakeBeforeTestRun(2)
|
||||
})
|
||||
.then(() => {
|
||||
return fakeBeforeTestRun(3)
|
||||
})
|
||||
.then(() => {
|
||||
expect(forceGc).to.be.calledOnce
|
||||
expect(emitBefore).to.be.calledOnce
|
||||
expect(emitAfter).to.be.calledOnce
|
||||
|
||||
fakeVisit()
|
||||
|
||||
return fakeBeforeTestRun(4)
|
||||
})
|
||||
.then(() => {
|
||||
expect(forceGc).to.be.calledTwice
|
||||
expect(emitBefore).to.be.calledTwice
|
||||
expect(emitAfter).to.be.calledTwice
|
||||
})
|
||||
})
|
||||
|
||||
it('triggers a forced GC correctly with interval = 3', () => {
|
||||
MockCypress.getFirefoxGcInterval.returns(3)
|
||||
|
||||
const forceGc = MockCypress.backend.withArgs('firefox:force:gc').resolves()
|
||||
const emitBefore = MockCypress.emit.withArgs('before:firefox:force:gc').returns()
|
||||
const emitAfter = MockCypress.emit.withArgs('after:firefox:force:gc').returns()
|
||||
|
||||
install(MockCypress)
|
||||
|
||||
return fakeBeforeTestRun(0).then(() => {
|
||||
return fakeBeforeTestRun(1)
|
||||
})
|
||||
.then(() => {
|
||||
expect(forceGc).to.not.be.called
|
||||
expect(emitBefore).to.not.be.called
|
||||
expect(emitAfter).to.not.be.called
|
||||
|
||||
fakeVisit()
|
||||
})
|
||||
.then(() => {
|
||||
return fakeBeforeTestRun(2)
|
||||
})
|
||||
.then(() => {
|
||||
return fakeBeforeTestRun(3)
|
||||
})
|
||||
.then(() => {
|
||||
expect(forceGc).to.be.calledOnce
|
||||
expect(emitBefore).to.be.calledOnce
|
||||
expect(emitAfter).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
|
||||
it('does not trigger any forced GC with falsy interval', () => {
|
||||
MockCypress.getFirefoxGcInterval.returns(false)
|
||||
|
||||
const forceGc = MockCypress.backend.withArgs('firefox:force:gc').resolves()
|
||||
const emitBefore = MockCypress.emit.withArgs('before:firefox:force:gc').returns()
|
||||
const emitAfter = MockCypress.emit.withArgs('after:firefox:force:gc').returns()
|
||||
|
||||
install(MockCypress)
|
||||
|
||||
return fakeBeforeTestRun(0).then(() => {
|
||||
return fakeBeforeTestRun(1)
|
||||
})
|
||||
.then(() => {
|
||||
expect(forceGc).to.not.be.called
|
||||
expect(emitBefore).to.not.be.called
|
||||
expect(emitAfter).to.not.be.called
|
||||
|
||||
fakeVisit()
|
||||
})
|
||||
.then(() => {
|
||||
return fakeBeforeTestRun(2)
|
||||
})
|
||||
.then(() => {
|
||||
expect(forceGc).to.not.be.called
|
||||
expect(emitBefore).to.not.be.called
|
||||
expect(emitAfter).to.not.be.called
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -2,6 +2,14 @@ const { $ } = Cypress
|
||||
|
||||
let isActuallyInteractive
|
||||
|
||||
isActuallyInteractive = Cypress.config('isInteractive')
|
||||
if (!isActuallyInteractive) {
|
||||
// we want to only enable retries in runMode
|
||||
// and because we set `isInteractive` above
|
||||
// we have to set retries here
|
||||
Cypress.config('retries', 2)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
isActuallyInteractive = Cypress.config('isInteractive')
|
||||
|
||||
@@ -14,11 +22,6 @@ beforeEach(() => {
|
||||
// necessary or else snapshots will not be taken
|
||||
// and we can't test them
|
||||
Cypress.config('numTestsKeptInMemory', 1)
|
||||
|
||||
// we want to only enable retries in runMode
|
||||
// and because we set `isInteractive` above
|
||||
// we have to set retries here
|
||||
Cypress.config('retries', 2)
|
||||
}
|
||||
|
||||
// remove all event listeners
|
||||
|
||||
@@ -14,7 +14,6 @@ const $Commands = require('./cypress/commands')
|
||||
const $Cookies = require('./cypress/cookies')
|
||||
const $Cy = require('./cypress/cy')
|
||||
const $Events = require('./cypress/events')
|
||||
const $FirefoxForcedGc = require('./util/firefox_forced_gc')
|
||||
const $Keyboard = require('./cy/keyboard')
|
||||
const $SetterGetter = require('./cypress/setter_getter')
|
||||
const $Log = require('./cypress/log')
|
||||
@@ -137,7 +136,6 @@ class $Cypress {
|
||||
this.originalConfig = _.cloneDeep(config)
|
||||
this.config = $SetterGetter.create(config)
|
||||
this.env = $SetterGetter.create(env)
|
||||
this.getFirefoxGcInterval = $FirefoxForcedGc.createIntervalGetter(this)
|
||||
this.getTestRetries = function () {
|
||||
const testRetries = this.config('retries')
|
||||
|
||||
@@ -213,8 +211,6 @@ class $Cypress {
|
||||
|
||||
this.events.proxyTo(this.cy)
|
||||
|
||||
$FirefoxForcedGc.install(this)
|
||||
|
||||
$scriptUtils.runScripts(specWindow, scripts)
|
||||
.catch((error) => {
|
||||
this.runner.onSpecError('error')({ error })
|
||||
@@ -230,6 +226,19 @@ class $Cypress {
|
||||
}
|
||||
}))
|
||||
})
|
||||
.then(() => {
|
||||
// in order to utilize focusmanager.testingmode and trick browser into being in focus even when not focused
|
||||
// this is critical for headless mode since otherwise the browser never gains focus
|
||||
if (this.browser.isHeadless && this.isBrowser({ family: 'firefox' })) {
|
||||
window.addEventListener('blur', () => {
|
||||
this.backend('firefox:window:focus')
|
||||
})
|
||||
|
||||
if (!document.hasFocus()) {
|
||||
return this.backend('firefox:window:focus')
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
this.cy.initialize(this.$autIframe)
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import { isNumber, isNull } from 'lodash'
|
||||
|
||||
function usingFirefoxWithGcBug (browser: Cypress.Browser) {
|
||||
// @see https://github.com/cypress-io/cypress/issues/8241
|
||||
return browser.family === 'firefox' && browser.majorVersion < 80
|
||||
}
|
||||
|
||||
export function createIntervalGetter (Cypress: Cypress.Cypress) {
|
||||
return () => {
|
||||
if (!usingFirefoxWithGcBug(Cypress.browser)) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const intervals = Cypress.config('firefoxGcInterval')
|
||||
|
||||
if (isNumber(intervals) || isNull(intervals)) {
|
||||
return intervals
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return intervals[Cypress.config('isInteractive') ? 'openMode' : 'runMode']
|
||||
}
|
||||
}
|
||||
|
||||
export function install (Cypress: Cypress.Cypress & EventEmitter) {
|
||||
if (!usingFirefoxWithGcBug(Cypress.browser)) {
|
||||
return
|
||||
}
|
||||
|
||||
let cyVisitedSinceLastGc = false
|
||||
let testsSinceLastForcedGc = 0
|
||||
|
||||
Cypress.on('command:start', function (cmd) {
|
||||
if (cmd.get('name') === 'visit') {
|
||||
cyVisitedSinceLastGc = true
|
||||
}
|
||||
})
|
||||
|
||||
Cypress.on('test:before:run:async', function (testAttrs) {
|
||||
const { order } = testAttrs
|
||||
|
||||
testsSinceLastForcedGc++
|
||||
|
||||
// if this is the first test, or the last test didn't run a cy.visit...
|
||||
if (order === 0 || !cyVisitedSinceLastGc) {
|
||||
return
|
||||
}
|
||||
|
||||
const gcInterval = Cypress.getFirefoxGcInterval()
|
||||
|
||||
cyVisitedSinceLastGc = false
|
||||
|
||||
if (gcInterval && gcInterval > 0 && testsSinceLastForcedGc >= gcInterval) {
|
||||
testsSinceLastForcedGc = 0
|
||||
Cypress.emit('before:firefox:force:gc', { gcInterval })
|
||||
|
||||
return Cypress.backend('firefox:force:gc').then(() => {
|
||||
return Cypress.emit('after:firefox:force:gc', { gcInterval })
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
}
|
||||
@@ -9,7 +9,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"google-chrome",
|
||||
"chrome",
|
||||
"google-chrome-stable"
|
||||
]
|
||||
],
|
||||
"minSupportedVersion": 64
|
||||
},
|
||||
{
|
||||
"name": "chromium",
|
||||
@@ -20,7 +21,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"binary": [
|
||||
"chromium-browser",
|
||||
"chromium"
|
||||
]
|
||||
],
|
||||
"minSupportedVersion": 64
|
||||
},
|
||||
{
|
||||
"name": "chrome",
|
||||
@@ -28,7 +30,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"channel": "beta",
|
||||
"displayName": "Chrome Beta",
|
||||
"versionRegex": {},
|
||||
"binary": "google-chrome-beta"
|
||||
"binary": "google-chrome-beta",
|
||||
"minSupportedVersion": 64
|
||||
},
|
||||
{
|
||||
"name": "chrome",
|
||||
@@ -36,7 +39,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"channel": "canary",
|
||||
"displayName": "Canary",
|
||||
"versionRegex": {},
|
||||
"binary": "google-chrome-canary"
|
||||
"binary": "google-chrome-canary",
|
||||
"minSupportedVersion": 64
|
||||
},
|
||||
{
|
||||
"name": "firefox",
|
||||
@@ -44,7 +48,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"channel": "stable",
|
||||
"displayName": "Firefox",
|
||||
"versionRegex": {},
|
||||
"binary": "firefox"
|
||||
"binary": "firefox",
|
||||
"minSupportedVersion": 86
|
||||
},
|
||||
{
|
||||
"name": "firefox",
|
||||
@@ -55,7 +60,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"binary": [
|
||||
"firefox-developer-edition",
|
||||
"firefox"
|
||||
]
|
||||
],
|
||||
"minSupportedVersion": 86
|
||||
},
|
||||
{
|
||||
"name": "firefox",
|
||||
@@ -66,7 +72,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"binary": [
|
||||
"firefox-nightly",
|
||||
"firefox-trunk"
|
||||
]
|
||||
],
|
||||
"minSupportedVersion": 86
|
||||
},
|
||||
{
|
||||
"name": "edge",
|
||||
@@ -77,7 +84,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"binary": [
|
||||
"edge",
|
||||
"microsoft-edge"
|
||||
]
|
||||
],
|
||||
"minSupportedVersion": 79
|
||||
},
|
||||
{
|
||||
"name": "edge",
|
||||
@@ -85,7 +93,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"channel": "canary",
|
||||
"displayName": "Edge Canary",
|
||||
"versionRegex": {},
|
||||
"binary": "edge-canary"
|
||||
"binary": "edge-canary",
|
||||
"minSupportedVersion": 79
|
||||
},
|
||||
{
|
||||
"name": "edge",
|
||||
@@ -93,7 +102,8 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"channel": "beta",
|
||||
"displayName": "Edge Beta",
|
||||
"versionRegex": {},
|
||||
"binary": "edge-beta"
|
||||
"binary": "edge-beta",
|
||||
"minSupportedVersion": 79
|
||||
},
|
||||
{
|
||||
"name": "edge",
|
||||
@@ -104,6 +114,7 @@ exports['browsers returns the expected list of browsers 1'] = [
|
||||
"binary": [
|
||||
"edge-dev",
|
||||
"microsoft-edge-dev"
|
||||
]
|
||||
],
|
||||
"minSupportedVersion": 79
|
||||
}
|
||||
]
|
||||
|
||||
@@ -10,6 +10,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"chrome",
|
||||
"google-chrome-stable"
|
||||
],
|
||||
"minSupportedVersion": 64,
|
||||
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -29,6 +30,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"chromium-browser",
|
||||
"chromium"
|
||||
],
|
||||
"minSupportedVersion": 64,
|
||||
"path": "/Applications/Chromium.app/Contents/MacOS/Chromium",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -45,6 +47,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Chrome Beta",
|
||||
"versionRegex": {},
|
||||
"binary": "google-chrome-beta",
|
||||
"minSupportedVersion": 64,
|
||||
"path": "/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -61,6 +64,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Canary",
|
||||
"versionRegex": {},
|
||||
"binary": "google-chrome-canary",
|
||||
"minSupportedVersion": 64,
|
||||
"path": "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -77,6 +81,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Firefox",
|
||||
"versionRegex": {},
|
||||
"binary": "firefox",
|
||||
"minSupportedVersion": 86,
|
||||
"path": "/Applications/Firefox.app/Contents/MacOS/firefox-bin",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -96,6 +101,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"firefox-developer-edition",
|
||||
"firefox"
|
||||
],
|
||||
"minSupportedVersion": 86,
|
||||
"path": "/Applications/Firefox Developer Edition.app/Contents/MacOS/firefox-bin",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -115,6 +121,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"firefox-nightly",
|
||||
"firefox-trunk"
|
||||
],
|
||||
"minSupportedVersion": 86,
|
||||
"path": "/Applications/Firefox Nightly.app/Contents/MacOS/firefox-bin",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -134,6 +141,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"edge",
|
||||
"microsoft-edge"
|
||||
],
|
||||
"minSupportedVersion": 79,
|
||||
"path": "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -150,6 +158,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Edge Canary",
|
||||
"versionRegex": {},
|
||||
"binary": "edge-canary",
|
||||
"minSupportedVersion": 79,
|
||||
"path": "/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -166,6 +175,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Edge Beta",
|
||||
"versionRegex": {},
|
||||
"binary": "edge-beta",
|
||||
"minSupportedVersion": 79,
|
||||
"path": "/Applications/Microsoft Edge Beta.app/Contents/MacOS/Microsoft Edge Beta",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
@@ -185,6 +195,7 @@ exports['darwin browser detection detects browsers as expected 1'] = [
|
||||
"edge-dev",
|
||||
"microsoft-edge-dev"
|
||||
],
|
||||
"minSupportedVersion": 79,
|
||||
"path": "/Applications/Microsoft Edge Dev.app/Contents/MacOS/Microsoft Edge Dev",
|
||||
"version": "someVersion",
|
||||
"findAppParams": {
|
||||
|
||||
@@ -10,6 +10,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"chrome",
|
||||
"google-chrome-stable"
|
||||
],
|
||||
"minSupportedVersion": 64,
|
||||
"path": "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
||||
"version": "1.2.3",
|
||||
"findAppParams": {
|
||||
@@ -29,6 +30,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"chromium-browser",
|
||||
"chromium"
|
||||
],
|
||||
"minSupportedVersion": 64,
|
||||
"path": "C:/Program Files (x86)/Google/chrome-win32/chrome.exe",
|
||||
"version": "2.3.4",
|
||||
"findAppParams": {
|
||||
@@ -45,6 +47,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Chrome Beta",
|
||||
"versionRegex": {},
|
||||
"binary": "google-chrome-beta",
|
||||
"minSupportedVersion": 64,
|
||||
"path": "C:/Program Files (x86)/Google/Chrome Beta/Application/chrome.exe",
|
||||
"version": "6.7.8",
|
||||
"findAppParams": {
|
||||
@@ -61,6 +64,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Canary",
|
||||
"versionRegex": {},
|
||||
"binary": "google-chrome-canary",
|
||||
"minSupportedVersion": 64,
|
||||
"path": "C:/Users/flotwig/AppData/Local/Google/Chrome SxS/Application/chrome.exe",
|
||||
"version": "3.4.5",
|
||||
"findAppParams": {
|
||||
@@ -77,6 +81,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Firefox",
|
||||
"versionRegex": {},
|
||||
"binary": "firefox",
|
||||
"minSupportedVersion": 86,
|
||||
"path": "C:/Program Files/Mozilla Firefox/firefox.exe",
|
||||
"version": "72",
|
||||
"findAppParams": {
|
||||
@@ -96,6 +101,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"firefox-developer-edition",
|
||||
"firefox"
|
||||
],
|
||||
"minSupportedVersion": 86,
|
||||
"path": "C:/Program Files (x86)/Firefox Developer Edition/firefox.exe",
|
||||
"version": "73",
|
||||
"findAppParams": {
|
||||
@@ -115,6 +121,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"firefox-nightly",
|
||||
"firefox-trunk"
|
||||
],
|
||||
"minSupportedVersion": 86,
|
||||
"path": "C:/Program Files/Firefox Nightly/firefox.exe",
|
||||
"version": "74",
|
||||
"findAppParams": {
|
||||
@@ -134,6 +141,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"edge",
|
||||
"microsoft-edge"
|
||||
],
|
||||
"minSupportedVersion": 79,
|
||||
"path": "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe",
|
||||
"version": "11",
|
||||
"findAppParams": {
|
||||
@@ -150,6 +158,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Edge Canary",
|
||||
"versionRegex": {},
|
||||
"binary": "edge-canary",
|
||||
"minSupportedVersion": 79,
|
||||
"path": "C:/Users/flotwig/AppData/Local/Microsoft/Edge SxS/Application/msedge.exe",
|
||||
"version": "14",
|
||||
"findAppParams": {
|
||||
@@ -166,6 +175,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"displayName": "Edge Beta",
|
||||
"versionRegex": {},
|
||||
"binary": "edge-beta",
|
||||
"minSupportedVersion": 79,
|
||||
"path": "C:/Program Files (x86)/Microsoft/Edge Beta/Application/msedge.exe",
|
||||
"version": "12",
|
||||
"findAppParams": {
|
||||
@@ -185,6 +195,7 @@ exports['windows browser detection detects browsers as expected 1'] = [
|
||||
"edge-dev",
|
||||
"microsoft-edge-dev"
|
||||
],
|
||||
"minSupportedVersion": 79,
|
||||
"path": "C:/Program Files (x86)/Microsoft/Edge Dev/Application/msedge.exe",
|
||||
"version": "13",
|
||||
"findAppParams": {
|
||||
@@ -216,6 +227,7 @@ exports['windows browser detection detects local Firefox installs 1'] = [
|
||||
"displayName": "Firefox",
|
||||
"versionRegex": {},
|
||||
"binary": "firefox",
|
||||
"minSupportedVersion": 86,
|
||||
"path": "C:/Users/flotwig/AppData/Local/Mozilla Firefox/firefox.exe",
|
||||
"version": "100",
|
||||
"findAppParams": {
|
||||
@@ -235,6 +247,7 @@ exports['windows browser detection detects local Firefox installs 1'] = [
|
||||
"firefox-developer-edition",
|
||||
"firefox"
|
||||
],
|
||||
"minSupportedVersion": 86,
|
||||
"path": "C:/Users/flotwig/AppData/Local/Firefox Developer Edition/firefox.exe",
|
||||
"version": "300",
|
||||
"findAppParams": {
|
||||
@@ -254,6 +267,7 @@ exports['windows browser detection detects local Firefox installs 1'] = [
|
||||
"firefox-nightly",
|
||||
"firefox-trunk"
|
||||
],
|
||||
"minSupportedVersion": 86,
|
||||
"path": "C:/Users/flotwig/AppData/Local/Firefox Nightly/firefox.exe",
|
||||
"version": "200",
|
||||
"findAppParams": {
|
||||
|
||||
@@ -2,6 +2,13 @@ import { log } from './log'
|
||||
import * as cp from 'child_process'
|
||||
import { Browser, FoundBrowser } from './types'
|
||||
|
||||
// Chrome started exposing CDP 1.3 in 64
|
||||
const MIN_CHROME_VERSION = 64
|
||||
// Firefox started exposing CDP in 86
|
||||
const MIN_FIREFOX_VERSION = 86
|
||||
// Edge switched to Blink in 79
|
||||
const MIN_EDGE_VERSION = 79
|
||||
|
||||
/** list of the browsers we can detect and use by default */
|
||||
export const browsers: Browser[] = [
|
||||
{
|
||||
@@ -11,6 +18,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Chrome',
|
||||
versionRegex: /Google Chrome (\S+)/m,
|
||||
binary: ['google-chrome', 'chrome', 'google-chrome-stable'],
|
||||
minSupportedVersion: MIN_CHROME_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'chromium',
|
||||
@@ -20,6 +28,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Chromium',
|
||||
versionRegex: /Chromium (\S+)/m,
|
||||
binary: ['chromium-browser', 'chromium'],
|
||||
minSupportedVersion: MIN_CHROME_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'chrome',
|
||||
@@ -28,6 +37,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Chrome Beta',
|
||||
versionRegex: /Google Chrome (\S+) beta/m,
|
||||
binary: 'google-chrome-beta',
|
||||
minSupportedVersion: MIN_CHROME_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'chrome',
|
||||
@@ -36,6 +46,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Canary',
|
||||
versionRegex: /Google Chrome Canary (\S+)/m,
|
||||
binary: 'google-chrome-canary',
|
||||
minSupportedVersion: MIN_CHROME_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'firefox',
|
||||
@@ -45,6 +56,7 @@ export const browsers: Browser[] = [
|
||||
// Mozilla Firefox 70.0.1
|
||||
versionRegex: /^Mozilla Firefox ([^\sab]+)$/m,
|
||||
binary: 'firefox',
|
||||
minSupportedVersion: MIN_FIREFOX_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'firefox',
|
||||
@@ -55,6 +67,7 @@ export const browsers: Browser[] = [
|
||||
versionRegex: /^Mozilla Firefox (\S+b\S*)$/m,
|
||||
// ubuntu PPAs install it as firefox
|
||||
binary: ['firefox-developer-edition', 'firefox'],
|
||||
minSupportedVersion: MIN_FIREFOX_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'firefox',
|
||||
@@ -65,6 +78,7 @@ export const browsers: Browser[] = [
|
||||
versionRegex: /^Mozilla Firefox (\S+a\S*)$/m,
|
||||
// ubuntu PPAs install it as firefox-trunk
|
||||
binary: ['firefox-nightly', 'firefox-trunk'],
|
||||
minSupportedVersion: MIN_FIREFOX_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'edge',
|
||||
@@ -73,6 +87,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Edge',
|
||||
versionRegex: /Microsoft Edge (\S+)/m,
|
||||
binary: ['edge', 'microsoft-edge'],
|
||||
minSupportedVersion: MIN_EDGE_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'edge',
|
||||
@@ -81,6 +96,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Edge Canary',
|
||||
versionRegex: /Microsoft Edge Canary (\S+)/m,
|
||||
binary: 'edge-canary',
|
||||
minSupportedVersion: MIN_EDGE_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'edge',
|
||||
@@ -89,6 +105,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Edge Beta',
|
||||
versionRegex: /Microsoft Edge Beta (\S+)/m,
|
||||
binary: 'edge-beta',
|
||||
minSupportedVersion: MIN_EDGE_VERSION,
|
||||
},
|
||||
{
|
||||
name: 'edge',
|
||||
@@ -97,6 +114,7 @@ export const browsers: Browser[] = [
|
||||
displayName: 'Edge Dev',
|
||||
versionRegex: /Microsoft Edge Dev (\S+)/m,
|
||||
binary: ['edge-dev', 'microsoft-edge-dev'],
|
||||
minSupportedVersion: MIN_EDGE_VERSION,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@@ -16,26 +16,32 @@ import {
|
||||
} from './types'
|
||||
import * as windowsHelper from './windows'
|
||||
|
||||
type HasVersion = {
|
||||
version?: string
|
||||
majorVersion?: string | number
|
||||
type HasVersion = Partial<FoundBrowser> & {
|
||||
version: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export const setMajorVersion = <T extends HasVersion>(browser: T): T => {
|
||||
let majorVersion = browser.majorVersion
|
||||
const majorVersion = parseInt(browser.version.split('.')[0]) || browser.version
|
||||
|
||||
if (browser.version) {
|
||||
majorVersion = parseInt(browser.version.split('.')[0]) || browser.version
|
||||
log(
|
||||
'browser %s version %s major version %s',
|
||||
browser.name,
|
||||
browser.version,
|
||||
majorVersion,
|
||||
)
|
||||
const unsupportedVersion = browser.minSupportedVersion && majorVersion < browser.minSupportedVersion
|
||||
|
||||
log(
|
||||
'browser %s version %s major version %s',
|
||||
browser.name,
|
||||
browser.version,
|
||||
majorVersion,
|
||||
unsupportedVersion,
|
||||
)
|
||||
|
||||
const foundBrowser = extend({}, browser, { majorVersion })
|
||||
|
||||
if (unsupportedVersion) {
|
||||
foundBrowser.unsupportedVersion = true
|
||||
foundBrowser.warning = `Cypress does not support running ${browser.displayName} version ${majorVersion}. To use ${browser.displayName} with Cypress, install a version of ${browser.displayName} newer than or equal to ${browser.minSupportedVersion}.`
|
||||
}
|
||||
|
||||
return extend({}, browser, { majorVersion })
|
||||
return foundBrowser
|
||||
}
|
||||
|
||||
type PlatformHelper = {
|
||||
@@ -102,6 +108,8 @@ function checkOneBrowser (browser: Browser): Promise<boolean | FoundBrowser> {
|
||||
'custom',
|
||||
'warning',
|
||||
'info',
|
||||
'minSupportedVersion',
|
||||
'unsupportedVersion',
|
||||
])
|
||||
|
||||
const logBrowser = (props: any) => {
|
||||
@@ -125,21 +133,9 @@ function checkOneBrowser (browser: Browser): Promise<boolean | FoundBrowser> {
|
||||
.then(pickBrowserProps)
|
||||
.then(tap(logBrowser))
|
||||
.then((browser) => setMajorVersion(browser))
|
||||
.then(maybeSetFirefoxWarning)
|
||||
.catch(failed)
|
||||
}
|
||||
|
||||
export const firefoxGcWarning = 'This version of Firefox has a bug that causes excessive memory consumption and will cause your tests to run slowly. It is recommended to upgrade to Firefox 80 or newer. [Learn more.](https://docs.cypress.io/guides/references/configuration.html#firefoxGcInterval)'
|
||||
|
||||
// @see https://github.com/cypress-io/cypress/issues/8241
|
||||
const maybeSetFirefoxWarning = (browser: FoundBrowser) => {
|
||||
if (browser.family === 'firefox' && Number(browser.majorVersion) < 80) {
|
||||
browser.warning = firefoxGcWarning
|
||||
}
|
||||
|
||||
return browser
|
||||
}
|
||||
|
||||
/** returns list of detected browsers */
|
||||
export const detect = (goalBrowsers?: Browser[]): Bluebird<FoundBrowser[]> => {
|
||||
// we can detect same browser under different aliases
|
||||
@@ -192,18 +188,16 @@ export const detectByPath = (
|
||||
const setCustomBrowserData = (browser: Browser, path: string, versionStr: string): FoundBrowser => {
|
||||
const version = helper.getVersionNumber(versionStr, browser)
|
||||
|
||||
let parsedBrowser = {
|
||||
let parsedBrowser = extend({}, browser, {
|
||||
name: browser.name,
|
||||
displayName: `Custom ${browser.displayName}`,
|
||||
info: `Loaded from ${path}`,
|
||||
custom: true,
|
||||
path,
|
||||
version,
|
||||
}
|
||||
})
|
||||
|
||||
parsedBrowser = setMajorVersion(parsedBrowser)
|
||||
|
||||
return extend({}, browser, parsedBrowser)
|
||||
return setMajorVersion(parsedBrowser)
|
||||
}
|
||||
|
||||
const pathData = helper.getPathData(path)
|
||||
@@ -226,7 +220,6 @@ export const detectByPath = (
|
||||
|
||||
return setCustomBrowserData(browser, pathData.path, version)
|
||||
})
|
||||
.then(maybeSetFirefoxWarning)
|
||||
.catch((err: NotDetectedAtPathError) => {
|
||||
if (err.notDetectedAtPath) {
|
||||
throw err
|
||||
|
||||
@@ -43,6 +43,8 @@ export type Browser = {
|
||||
warning?: string
|
||||
/** optional info that will be shown in the GUI */
|
||||
info?: string
|
||||
/** if set, the majorVersion must be >= this to be run in Cypress */
|
||||
minSupportedVersion?: number
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,6 +56,7 @@ export type FoundBrowser = Omit<Browser, 'versionRegex' | 'binary'> & {
|
||||
majorVersion?: string
|
||||
/** is this a user-supplied browser? */
|
||||
custom?: boolean
|
||||
unsupportedVersion?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
require('../spec_helper')
|
||||
import { firefoxGcWarning, detect, detectByPath, setMajorVersion } from '../../lib/detect'
|
||||
import { detect, detectByPath, setMajorVersion } from '../../lib/detect'
|
||||
import { goalBrowsers } from '../fixtures'
|
||||
import { expect } from 'chai'
|
||||
import { utils } from '../../lib/utils'
|
||||
@@ -62,6 +62,21 @@ describe('browser detection', () => {
|
||||
// @ts-ignore
|
||||
expect(res.majorVersion).to.equal(foundBrowser.version)
|
||||
})
|
||||
|
||||
it('creates warning when version is unsupported', () => {
|
||||
const foundBrowser = {
|
||||
displayName: 'TestBro',
|
||||
name: 'test browser',
|
||||
version: '9000.1',
|
||||
minSupportedVersion: 9001,
|
||||
}
|
||||
|
||||
const res = setMajorVersion(foundBrowser)
|
||||
|
||||
// @ts-ignore
|
||||
expect(res.warning).to.contain('does not support running TestBro version 9000')
|
||||
.and.contain('TestBro newer than or equal to 9001')
|
||||
})
|
||||
})
|
||||
|
||||
context('#detectByPath', () => {
|
||||
@@ -143,18 +158,14 @@ describe('browser detection', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// @see https://github.com/cypress-io/cypress/issues/8241
|
||||
it('adds warnings to Firefox versions less than 80', async () => {
|
||||
it('creates warning when version is unsupported', async () => {
|
||||
execa.withArgs('/good-firefox', ['--version'])
|
||||
.resolves({ stdout: 'Mozilla Firefox 80.0' })
|
||||
.resolves({ stdout: 'Mozilla Firefox 85.0' })
|
||||
|
||||
execa.withArgs('/bad-firefox', ['--version'])
|
||||
.resolves({ stdout: 'Mozilla Firefox 79.1' })
|
||||
const foundBrowser = await detectByPath('/good-firefox')
|
||||
|
||||
expect(await detectByPath('/good-firefox')).to.not.have.property('warning')
|
||||
expect(await detectByPath('/bad-firefox')).to.include({
|
||||
warning: firefoxGcWarning,
|
||||
})
|
||||
expect(foundBrowser.warning).to.contain('does not support running Custom Firefox version 85')
|
||||
.and.contain('Firefox newer than or equal to 86')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,8 +4,7 @@ import _ from 'lodash'
|
||||
import * as linuxHelper from '../../lib/linux'
|
||||
import 'chai-as-promised'
|
||||
import { log } from '../log'
|
||||
import { detect, firefoxGcWarning } from '../../lib/detect'
|
||||
import { browsers } from '../../lib/browsers'
|
||||
import { detect } from '../../lib/detect'
|
||||
import { goalBrowsers } from '../fixtures'
|
||||
import { expect } from 'chai'
|
||||
import { utils } from '../../lib/utils'
|
||||
@@ -49,7 +48,7 @@ describe('linux browser detection', () => {
|
||||
// https://github.com/cypress-io/cypress/pull/7039
|
||||
it('sets profilePath on snapcraft chromium', () => {
|
||||
execa.withArgs('chromium', ['--version'])
|
||||
.resolves({ stdout: 'Chromium 1.2.3 snap' })
|
||||
.resolves({ stdout: 'Chromium 64.2.3 snap' })
|
||||
|
||||
sinon.stub(os, 'platform').returns('linux')
|
||||
sinon.stub(os, 'homedir').returns('/home/foo')
|
||||
@@ -60,10 +59,11 @@ describe('linux browser detection', () => {
|
||||
name: 'chromium',
|
||||
family: 'chromium',
|
||||
displayName: 'Chromium',
|
||||
majorVersion: 1,
|
||||
majorVersion: 64,
|
||||
minSupportedVersion: 64,
|
||||
path: 'chromium',
|
||||
profilePath: '/home/foo/snap/chromium/current',
|
||||
version: '1.2.3',
|
||||
version: '64.2.3',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -93,18 +93,6 @@ describe('linux browser detection', () => {
|
||||
return linuxHelper.detect(goal).then(checkBrowser)
|
||||
})
|
||||
|
||||
// @see https://github.com/cypress-io/cypress/issues/8241
|
||||
it('adds warnings to Firefox versions less than 80', async () => {
|
||||
const goalFirefox = _.find(browsers, { binary: 'firefox' })
|
||||
|
||||
sinon.stub(os, 'platform').withArgs().returns('linux')
|
||||
execa.withArgs('firefox', ['--version']).resolves({ stdout: 'Mozilla Firefox 79.1' })
|
||||
|
||||
expect((await detect([goalFirefox]))[0]).to.include({
|
||||
warning: firefoxGcWarning,
|
||||
})
|
||||
})
|
||||
|
||||
// despite using detect(), this test is in linux/spec instead of detect_spec because it is
|
||||
// testing side effects that occur within the Linux-specific detect function
|
||||
// https://github.com/cypress-io/cypress/issues/1400
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
import { EventEmitter } from 'events'
|
||||
import { RootRunnable } from '../../src/runnables/runnables-store'
|
||||
|
||||
describe('forced gc', () => {
|
||||
let runner: EventEmitter
|
||||
let runnables: RootRunnable
|
||||
|
||||
beforeEach(() => {
|
||||
cy.fixture('runnables').then((_runnables) => {
|
||||
runnables = _runnables
|
||||
})
|
||||
|
||||
runner = new EventEmitter()
|
||||
|
||||
cy.visit('/').then((win) => {
|
||||
win.render({
|
||||
runner,
|
||||
spec: {
|
||||
name: 'foo',
|
||||
absolute: '/foo/bar',
|
||||
relative: 'foo/bar',
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
cy.get('.reporter').then(() => {
|
||||
runner.emit('runnables:ready', runnables)
|
||||
runner.emit('reporter:start', {})
|
||||
})
|
||||
})
|
||||
|
||||
it('does not display the warning when interval is undefined', () => {
|
||||
cy.get('.forced-gc-warning').should('not.exist')
|
||||
})
|
||||
|
||||
describe('when interval is null or a number', () => {
|
||||
beforeEach(() => {
|
||||
runner.emit('before:firefox:force:gc', { gcInterval: null })
|
||||
})
|
||||
|
||||
it('expands on click', () => {
|
||||
cy.contains('GC Interval').click()
|
||||
cy.contains('Garbage Collection Interval').should('be.visible')
|
||||
})
|
||||
|
||||
it('collapses on a second click', () => {
|
||||
cy.contains('GC Interval').click().click()
|
||||
cy.contains('Garbage Collection Interval').should('not.be.visible')
|
||||
})
|
||||
|
||||
it('collapses on a clicking X', () => {
|
||||
cy.contains('GC Interval').click()
|
||||
cy.get('.forced-gc-warning .fa-times').click()
|
||||
cy.contains('Garbage Collection Interval').should('not.be.visible')
|
||||
})
|
||||
|
||||
it('opens links externally', () => {
|
||||
cy.spy(runner, 'emit')
|
||||
cy.contains('GC Interval').click()
|
||||
cy.get('.forced-gc-warning a').each(($link) => {
|
||||
cy.wrap($link).click()
|
||||
cy.wrap(runner.emit).should('be.calledWith', 'external:open', $link.attr('href'))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when interval is null', () => {
|
||||
beforeEach(() => {
|
||||
runner.emit('before:firefox:force:gc', { gcInterval: null })
|
||||
})
|
||||
|
||||
it('displays the warning with (disabled)', () => {
|
||||
cy.get('.forced-gc-warning').should('be.visible')
|
||||
cy.contains('GC Interval: disabled')
|
||||
})
|
||||
|
||||
it('displays the full message with (disabled)', () => {
|
||||
cy.contains('GC Interval').click()
|
||||
cy.contains('Garbage Collection Interval: (disabled)').should('be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
describe('when interval is 0', () => {
|
||||
beforeEach(() => {
|
||||
runner.emit('before:firefox:force:gc', { gcInterval: 0 })
|
||||
})
|
||||
|
||||
it('displays the warning with (disabled)', () => {
|
||||
cy.get('.forced-gc-warning').should('be.visible')
|
||||
cy.contains('GC Interval: disabled')
|
||||
})
|
||||
|
||||
it('displays the full message with (disabled)', () => {
|
||||
cy.contains('GC Interval').click()
|
||||
cy.contains('Garbage Collection Interval: (disabled)').should('be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
describe('when interval is greater than 0', () => {
|
||||
beforeEach(() => {
|
||||
runner.emit('before:firefox:force:gc', { gcInterval: 15 })
|
||||
})
|
||||
|
||||
it('displays the warning with duration and running message', () => {
|
||||
cy.get('.forced-gc-warning').should('be.visible')
|
||||
cy.contains('GC Duration: 0.00')
|
||||
cy.contains('Running GC...')
|
||||
|
||||
// ensure the page is loaded before taking snapshot
|
||||
cy.contains('test 4').should('be.visible')
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('displays the full message with (enabled)', () => {
|
||||
cy.contains('GC Duration').click()
|
||||
cy.contains('Garbage Collection Interval: (enabled)').should('be.visible')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -141,28 +141,6 @@ describe('app state', () => {
|
||||
})
|
||||
})
|
||||
|
||||
context('#setForcingGc', () => {
|
||||
it('sets forcingGc', () => {
|
||||
const instance = new AppState()
|
||||
|
||||
instance.setForcingGc(false)
|
||||
expect(instance.forcingGc).to.be.false
|
||||
instance.setForcingGc(true)
|
||||
expect(instance.forcingGc).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
context('#setFirefoxGcInterval', () => {
|
||||
it('sets forcingGc', () => {
|
||||
const instance = new AppState()
|
||||
|
||||
instance.setFirefoxGcInterval(111)
|
||||
expect(instance.firefoxGcInterval).to.eq(111)
|
||||
instance.setFirefoxGcInterval(222)
|
||||
expect(instance.firefoxGcInterval).to.eq(222)
|
||||
})
|
||||
})
|
||||
|
||||
context('#setStudioActive', () => {
|
||||
it('sets studioActive', () => {
|
||||
const instance = new AppState()
|
||||
|
||||
@@ -25,8 +25,6 @@ type AppStateStub = AppState & {
|
||||
resume: SinonSpy
|
||||
end: SinonSpy
|
||||
temporarilySetAutoScrolling: SinonSpy
|
||||
setFirefoxGcInterval: SinonSpy
|
||||
setForcingGc: SinonSpy
|
||||
setStudioActive: SinonSpy
|
||||
stop: SinonSpy
|
||||
}
|
||||
@@ -39,8 +37,6 @@ const appStateStub = () => {
|
||||
resume: sinon.spy(),
|
||||
end: sinon.spy(),
|
||||
temporarilySetAutoScrolling: sinon.spy(),
|
||||
setFirefoxGcInterval: sinon.spy(),
|
||||
setForcingGc: sinon.spy(),
|
||||
setStudioActive: sinon.spy(),
|
||||
stop: sinon.spy(),
|
||||
} as AppStateStub
|
||||
@@ -194,28 +190,11 @@ describe('events', () => {
|
||||
expect(appState.temporarilySetAutoScrolling).to.have.been.calledWith(false)
|
||||
})
|
||||
|
||||
it('sets firefoxGcInterval on the app state on reporter:start', () => {
|
||||
runner.on.withArgs('reporter:start').callArgWith(1, { firefoxGcInterval: 111 })
|
||||
expect(appState.setFirefoxGcInterval).to.have.been.calledWith(111)
|
||||
})
|
||||
|
||||
it('sets studioActive on the app state on reporter:start', () => {
|
||||
runner.on.withArgs('reporter:start').callArgWith(1, { studioActive: true })
|
||||
expect(appState.setStudioActive).to.have.been.calledWith(true)
|
||||
})
|
||||
|
||||
it('sets forcingGc & firefoxGcInterval on the app state on before:firefox:force:gc', () => {
|
||||
runner.on.withArgs('before:firefox:force:gc').callArgWith(1, { gcInterval: 222 })
|
||||
expect(appState.setFirefoxGcInterval).to.have.been.calledWith(222)
|
||||
expect(appState.setForcingGc).to.have.been.calledWith(true)
|
||||
})
|
||||
|
||||
it('sets forcingGc & firefoxGcInterval on the app state on after:firefox:force:gc', () => {
|
||||
runner.on.withArgs('after:firefox:force:gc').callArgWith(1, { gcInterval: 333 })
|
||||
expect(appState.setFirefoxGcInterval).to.have.been.calledWith(333)
|
||||
expect(appState.setForcingGc).to.have.been.calledWith(false)
|
||||
})
|
||||
|
||||
it('sets initial scrollTop on the scroller on reporter:start', () => {
|
||||
runner.on.withArgs('reporter:start').callArgWith(1, { scrollTop: 123 })
|
||||
expect(runnablesStore.setInitialScrollTop).to.have.been.calledWith(123)
|
||||
|
||||
@@ -2,8 +2,6 @@ import _ from 'lodash'
|
||||
import { observable } from 'mobx'
|
||||
|
||||
interface DefaultAppState {
|
||||
forcingGc: boolean
|
||||
firefoxGcInterval: number | null | undefined
|
||||
isPaused: boolean
|
||||
isRunning: boolean
|
||||
nextCommandName: string | null | undefined
|
||||
@@ -12,8 +10,6 @@ interface DefaultAppState {
|
||||
}
|
||||
|
||||
const defaults: DefaultAppState = {
|
||||
forcingGc: false,
|
||||
firefoxGcInterval: undefined,
|
||||
isPaused: false,
|
||||
isRunning: false,
|
||||
nextCommandName: null,
|
||||
@@ -23,12 +19,10 @@ const defaults: DefaultAppState = {
|
||||
|
||||
class AppState {
|
||||
@observable autoScrollingEnabled = true
|
||||
@observable forcingGc = defaults.forcingGc
|
||||
@observable isPaused = defaults.isPaused
|
||||
@observable isRunning = defaults.isRunning
|
||||
@observable nextCommandName = defaults.nextCommandName
|
||||
@observable pinnedSnapshotId = defaults.pinnedSnapshotId
|
||||
@observable firefoxGcInterval = defaults.firefoxGcInterval
|
||||
@observable studioActive = defaults.studioActive
|
||||
|
||||
isStopped = false;
|
||||
@@ -59,14 +53,6 @@ class AppState {
|
||||
this._resetAutoScrolling()
|
||||
}
|
||||
|
||||
setForcingGc (forcingGc: boolean) {
|
||||
this.forcingGc = forcingGc
|
||||
}
|
||||
|
||||
setFirefoxGcInterval (firefoxGcInterval: DefaultAppState['firefoxGcInterval']) {
|
||||
this.firefoxGcInterval = firefoxGcInterval
|
||||
}
|
||||
|
||||
temporarilySetAutoScrolling (isEnabled?: boolean | null) {
|
||||
if (isEnabled != null) {
|
||||
this.autoScrollingEnabled = isEnabled
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img,a img{border:none;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}
|
||||
|
||||
@import './forced-gc-warning.scss';
|
||||
|
||||
.reporter {
|
||||
background-color: #F6F6F6;
|
||||
bottom: 0;
|
||||
|
||||
@@ -34,7 +34,6 @@ export interface Events {
|
||||
|
||||
interface StartInfo extends StatsStoreStartInfo {
|
||||
autoScrollingEnabled: boolean
|
||||
firefoxGcInterval: number
|
||||
scrollTop: number
|
||||
studioActive: boolean
|
||||
}
|
||||
@@ -91,7 +90,6 @@ const events: Events = {
|
||||
|
||||
runner.on('reporter:start', action('start', (startInfo: StartInfo) => {
|
||||
appState.temporarilySetAutoScrolling(startInfo.autoScrollingEnabled)
|
||||
appState.setFirefoxGcInterval(startInfo.firefoxGcInterval)
|
||||
runnablesStore.setInitialScrollTop(startInfo.scrollTop)
|
||||
appState.setStudioActive(startInfo.studioActive)
|
||||
if (runnablesStore.hasTests) {
|
||||
@@ -135,16 +133,6 @@ const events: Events = {
|
||||
appState.pinnedSnapshotId = null
|
||||
}))
|
||||
|
||||
runner.on('before:firefox:force:gc', action('before:firefox:force:gc', ({ gcInterval }) => {
|
||||
appState.setForcingGc(true)
|
||||
appState.setFirefoxGcInterval(gcInterval)
|
||||
}))
|
||||
|
||||
runner.on('after:firefox:force:gc', action('after:firefox:force:gc', ({ gcInterval }) => {
|
||||
appState.setForcingGc(false)
|
||||
appState.setFirefoxGcInterval(gcInterval)
|
||||
}))
|
||||
|
||||
localBus.on('resume', action('resume', () => {
|
||||
appState.resume()
|
||||
statsStore.resume()
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
.forced-gc-warning {
|
||||
background-color: $yellow-lightest;
|
||||
padding: 1em;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
box-shadow: 0 -1px 3px #ccc;
|
||||
border-right: 1px solid #ddd;
|
||||
|
||||
p {
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
a.code-link {
|
||||
&>code {
|
||||
color: #1079c3;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
text-decoration: none;
|
||||
|
||||
&>code {
|
||||
background-color: #e5f1f6;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #f9f2f4;
|
||||
color: #c7254e;
|
||||
border-radius: 2px;
|
||||
letter-spacing: 0.5px;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
>.gc-expando {
|
||||
display: none;
|
||||
|
||||
&.expanded {
|
||||
display: block;
|
||||
padding-bottom: 1em;
|
||||
|
||||
.fa-times {
|
||||
float: right;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gc-status {
|
||||
color: #888;
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
>.gc-status-bar {
|
||||
.status-text {
|
||||
float: right;
|
||||
}
|
||||
|
||||
>.total-time {
|
||||
>i {
|
||||
margin-right: .3em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
opacity: .7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
import { isUndefined, round } from 'lodash'
|
||||
import { observer } from 'mobx-react'
|
||||
import React from 'react'
|
||||
import { AppState } from './app-state'
|
||||
import { Events } from './events'
|
||||
|
||||
export interface Props {
|
||||
appState: Pick<AppState, 'forcingGc' | 'firefoxGcInterval'>
|
||||
events: Events
|
||||
}
|
||||
|
||||
interface State {
|
||||
expanded: boolean
|
||||
}
|
||||
|
||||
@observer
|
||||
class ForcedGcWarning extends React.Component<Props> {
|
||||
gcStartMs: number | null = null
|
||||
gcTotalMs: number = 0
|
||||
persisted = false
|
||||
state: State
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
expanded: false,
|
||||
}
|
||||
}
|
||||
|
||||
_toggleExpando () {
|
||||
this.setState({ expanded: !this.state.expanded })
|
||||
}
|
||||
|
||||
_updateGcTimer () {
|
||||
const { forcingGc } = this.props.appState
|
||||
|
||||
if (!forcingGc) {
|
||||
if (this.gcStartMs) {
|
||||
const duration = Date.now() - this.gcStartMs
|
||||
|
||||
this.gcStartMs = null
|
||||
this.gcTotalMs += duration
|
||||
}
|
||||
}
|
||||
|
||||
if (forcingGc && !this.gcStartMs) {
|
||||
this.gcStartMs = Date.now()
|
||||
}
|
||||
}
|
||||
|
||||
_renderDisabled () {
|
||||
return (
|
||||
<div className='forced-gc-warning'>
|
||||
<div className={`gc-expando ${this.state.expanded ? 'expanded' : ''}`}>
|
||||
<p>
|
||||
<strong>
|
||||
Garbage Collection Interval: (disabled)
|
||||
</strong>
|
||||
<i className='fas fa-times clickable' onClick={() => this._toggleExpando()}></i>
|
||||
</p>
|
||||
<div>
|
||||
<p>
|
||||
Cypress can force Firefox to run Garbage Collection (GC) between tests by enabling: <a className='code-link' onClick={this._handleLink} href='https://on.cypress.io/firefox-gc-interval'><code>firefoxGcInterval</code></a>
|
||||
</p>
|
||||
<p>
|
||||
By default, <a className='code-link' onClick={this._handleLink} href='https://on.cypress.io/firefox-gc-interval'><code>firefoxGcInterval</code></a> is only enabled in <strong>run mode</strong>.
|
||||
</p>
|
||||
<p>
|
||||
Running GC prevents Firefox from running out of memory during longer test runs.
|
||||
</p>
|
||||
<p>
|
||||
<a className='code-link' onClick={this._handleLink} href='https://on.cypress.io/firefox-gc-interval'>Learn more</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='gc-status-bar clickable gc-not-running' onClick={() => this._toggleExpando()}>
|
||||
<span className='total-time'>
|
||||
<i className='fas fa-ws fa-info-circle'></i>
|
||||
GC Interval: <span className='gc-status'>disabled</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
_handleLink = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
|
||||
if (!e.currentTarget || !e.currentTarget.href) {
|
||||
return
|
||||
}
|
||||
|
||||
e.preventDefault()
|
||||
this.props.events.emit('external:open', e.currentTarget.href)
|
||||
}
|
||||
|
||||
_renderForcedGcWarning () {
|
||||
const { forcingGc } = this.props.appState
|
||||
|
||||
return (
|
||||
<div className='forced-gc-warning'>
|
||||
<div className={`gc-expando ${this.state.expanded ? 'expanded' : ''}`}>
|
||||
<div>
|
||||
<p>
|
||||
<strong>
|
||||
Garbage Collection Interval: (enabled)
|
||||
</strong>
|
||||
<i className='fas fa-times clickable' onClick={() => this._toggleExpando()}></i>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
Cypress will force Firefox to run Garbage Collection (GC) between tests based on the value of: <a className='code-link' onClick={this._handleLink} href='https://on.cypress.io/firefox-gc-interval'><code>firefoxGcInterval</code></a>
|
||||
</p>
|
||||
<p>
|
||||
Running GC prevents Firefox from running out of memory during longer test runs.
|
||||
</p>
|
||||
<p>
|
||||
Running GC is an expensive operation that can take up to a few seconds to complete. During this time Firefox may "freeze" and become unresponsive to user input.
|
||||
</p>
|
||||
<p>
|
||||
To improve performance, you can try setting <a className='code-link' onClick={this._handleLink} href='https://on.cypress.io/firefox-gc-interval'><code>firefoxGcInterval</code></a> to a higher value, which will result in running GC less frequently.
|
||||
</p>
|
||||
<p>
|
||||
<a className='code-link' onClick={this._handleLink} href='https://on.cypress.io/firefox-gc-interval'>Learn more</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`gc-status-bar clickable ${forcingGc ? 'gc-running' : 'gc-not-running'}`} onClick={() => this._toggleExpando()}>
|
||||
<span className='total-time' title='Total time spent running GC throughout this run'>
|
||||
<i className='fas fa-ws fa-info-circle'></i>
|
||||
GC Duration: <span className='gc-status'>{round(this.gcTotalMs / 1000, 2).toFixed(2)}</span>
|
||||
</span>
|
||||
|
||||
{forcingGc && <span className='status-text'>
|
||||
<i className='fas fa-spinner fa-spin'></i> Running GC...
|
||||
</span>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { firefoxGcInterval } = this.props.appState
|
||||
|
||||
if (isUndefined(firefoxGcInterval)) {
|
||||
// we're either still loading or it is disabled
|
||||
return null
|
||||
}
|
||||
|
||||
if (firefoxGcInterval === 0 || firefoxGcInterval == null) {
|
||||
return this._renderDisabled()
|
||||
}
|
||||
|
||||
this._updateGcTimer()
|
||||
|
||||
return this._renderForcedGcWarning()
|
||||
}
|
||||
}
|
||||
|
||||
export default ForcedGcWarning
|
||||
@@ -11,7 +11,6 @@ import EQ from 'css-element-queries/src/ElementQueries'
|
||||
import { RunnablesErrorModel } from './runnables/runnable-error'
|
||||
import appState, { AppState } from './lib/app-state'
|
||||
import events, { Runner, Events } from './lib/events'
|
||||
import ForcedGcWarning from './lib/forced-gc-warning'
|
||||
import runnablesStore, { RunnablesStore } from './runnables/runnables-store'
|
||||
import scroller, { Scroller } from './lib/scroller'
|
||||
import statsStore, { StatsStore } from './header/stats-store'
|
||||
@@ -84,7 +83,6 @@ class Reporter extends Component<SingleReporterProps | MultiReporterProps> {
|
||||
runnablesStore,
|
||||
scroller,
|
||||
error,
|
||||
events,
|
||||
statsStore,
|
||||
experimentalStudioEnabled,
|
||||
renderReporterHeader = (props: ReporterHeaderProps) => <Header {...props}/>,
|
||||
@@ -115,11 +113,6 @@ class Reporter extends Component<SingleReporterProps | MultiReporterProps> {
|
||||
spec={spec}
|
||||
/>
|
||||
))}
|
||||
|
||||
<ForcedGcWarning
|
||||
appState={appState}
|
||||
events={events}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ export const ReporterContainer = namedObserver('ReporterContainer',
|
||||
specRunId={props.state.specRunId}
|
||||
allSpecs={props.state.multiSpecs}
|
||||
error={errorMessages.reporterError(props.state.scriptError, props.state.spec.relative)}
|
||||
firefoxGcInterval={props.config.firefoxGcInterval}
|
||||
resetStatsOnSpecChange={props.state.runMode === 'single'}
|
||||
renderReporterHeader={renderReporterHeader}
|
||||
experimentalStudioEnabled={false}
|
||||
|
||||
@@ -21,7 +21,7 @@ ws.on('connect', () => {
|
||||
ws.emit('runner:connected')
|
||||
})
|
||||
|
||||
const driverToReporterEvents = 'paused before:firefox:force:gc after:firefox:force:gc'.split(' ')
|
||||
const driverToReporterEvents = 'paused'.split(' ')
|
||||
const driverToLocalAndReporterEvents = 'run:start run:end'.split(' ')
|
||||
const driverToSocketEvents = 'backend:request automation:request mocha recorder:frame'.split(' ')
|
||||
const driverTestEvents = 'test:before:run:async test:after:run'.split(' ')
|
||||
@@ -497,7 +497,6 @@ export const eventManager = {
|
||||
})
|
||||
|
||||
reporterBus.emit('reporter:start', {
|
||||
firefoxGcInterval: Cypress.getFirefoxGcInterval(),
|
||||
startTime: Cypress.runner.getStartTime(),
|
||||
numPassed: state.passed,
|
||||
numFailed: state.failed,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const helpers = require('../support/helpers')
|
||||
|
||||
const { shouldHaveTestResults, getRunState, cleanseRunStateMap } = helpers
|
||||
const { runIsolatedCypress, snapshotMochaEvents, getAutCypress } = helpers.createCypress({ config: { retries: 2, isTextTerminal: true, firefoxGcInterval: null } })
|
||||
const { runIsolatedCypress, snapshotMochaEvents, getAutCypress } = helpers.createCypress({ config: { retries: 2, isTextTerminal: true } })
|
||||
const { sinon } = Cypress
|
||||
const match = Cypress.sinon.match
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ class App extends Component {
|
||||
spec={spec}
|
||||
autoScrollingEnabled={this.props.config.state.autoScrollingEnabled}
|
||||
error={errorMessages.reporterError(this.props.state.scriptError, spec.relative)}
|
||||
firefoxGcInterval={this.props.config.firefoxGcInterval}
|
||||
experimentalStudioEnabled={this.props.config.experimentalStudio}
|
||||
/>}
|
||||
</div>
|
||||
|
||||
@@ -87,15 +87,6 @@ describe('<App />', () => {
|
||||
expect(component.find(Reporter)).to.have.prop('autoScrollingEnabled', true)
|
||||
})
|
||||
|
||||
it('renders the <Reporter /> with the firefoxGcInterval flag', () => {
|
||||
const props = createProps()
|
||||
|
||||
props.config.firefoxGcInterval = 111
|
||||
const component = shallowRender(<App {...props} />)
|
||||
|
||||
expect(component.find(Reporter)).to.have.prop('firefoxGcInterval', 111)
|
||||
})
|
||||
|
||||
it('renders the runner container with `left` set as the width of the reporter', () => {
|
||||
const props = createProps()
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ exports['e2e config applies defaultCommandTimeout globally 1'] = `
|
||||
|
||||
(Screenshots)
|
||||
|
||||
- /XXX/XXX/XXX/cypress/screenshots/dom_times_out_spec.js/short defaultCommandTimeo (1920x1080)
|
||||
- /XXX/XXX/XXX/cypress/screenshots/dom_times_out_spec.js/short defaultCommandTimeo (1280x720)
|
||||
ut -- times out looking for a missing element (failed).png
|
||||
|
||||
|
||||
|
||||
@@ -426,9 +426,13 @@ export = {
|
||||
if (isHeadless) {
|
||||
args.push('--headless')
|
||||
|
||||
// set default headless size to 1920x1080
|
||||
// set default headless size to 1280x720
|
||||
// https://github.com/cypress-io/cypress/issues/6210
|
||||
args.push('--window-size=1920,1080')
|
||||
args.push('--window-size=1280,720')
|
||||
|
||||
// set default headless DPR to 1
|
||||
// https://github.com/cypress-io/cypress/issues/17375
|
||||
args.push('--force-device-scale-factor=1')
|
||||
}
|
||||
|
||||
// force ipv4
|
||||
|
||||
@@ -21,6 +21,12 @@ let timings = {
|
||||
collections: [] as any[],
|
||||
}
|
||||
|
||||
let driver
|
||||
|
||||
const sendMarionette = (data) => {
|
||||
return driver.send(new Command(data))
|
||||
}
|
||||
|
||||
const getTabId = (tab) => {
|
||||
return _.get(tab, 'browsingContextID')
|
||||
}
|
||||
@@ -254,15 +260,11 @@ export default {
|
||||
getDelayMsForRetry,
|
||||
})
|
||||
|
||||
const driver = new Marionette.Drivers.Promises({
|
||||
driver = new Marionette.Drivers.Promises({
|
||||
port,
|
||||
tries: 1, // marionette-client has its own retry logic which we want to avoid
|
||||
})
|
||||
|
||||
const sendMarionette = (data) => {
|
||||
return driver.send(new Command(data))
|
||||
}
|
||||
|
||||
debug('firefox: navigating page with webdriver')
|
||||
|
||||
const onError = (from, reject?) => {
|
||||
@@ -315,4 +317,19 @@ export default {
|
||||
// even though Marionette is not used past this point, we have to keep the session open
|
||||
// or else `acceptInsecureCerts` will cease to apply and SSL validation prompts will appear.
|
||||
},
|
||||
|
||||
async windowFocus () {
|
||||
// in order to utilize focusmanager.testingmode and trick browser into being in focus even when not focused
|
||||
// this is critical for headless mode since otherwise the browser never gains focus
|
||||
return sendMarionette({
|
||||
name: 'WebDriver:ExecuteScript',
|
||||
parameters: {
|
||||
'args': [],
|
||||
'script': `return (() => {
|
||||
top.focus()
|
||||
}).apply(null, arguments)\
|
||||
`,
|
||||
},
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -503,10 +503,10 @@ export async function open (browser: Browser, url, options: any = {}, automation
|
||||
debug('launch in firefox', { url, args: launchOptions.args })
|
||||
|
||||
const browserInstance = await launch(browser, 'about:blank', launchOptions.args, {
|
||||
// sets headless resolution to 1920x1080 by default
|
||||
// sets headless resolution to 1280x720 by default
|
||||
// user can overwrite this default with these env vars or --height, --width arguments
|
||||
MOZ_HEADLESS_WIDTH: '1920',
|
||||
MOZ_HEADLESS_HEIGHT: '1081',
|
||||
MOZ_HEADLESS_WIDTH: '1280',
|
||||
MOZ_HEADLESS_HEIGHT: '721',
|
||||
})
|
||||
|
||||
try {
|
||||
|
||||
@@ -107,13 +107,6 @@ export const options = [
|
||||
defaultValue: '',
|
||||
validation: v.isString,
|
||||
isFolder: true,
|
||||
}, {
|
||||
name: 'firefoxGcInterval',
|
||||
defaultValue: {
|
||||
runMode: 1,
|
||||
openMode: null,
|
||||
},
|
||||
validation: v.isValidFirefoxGcInterval,
|
||||
}, {
|
||||
name: 'fixturesFolder',
|
||||
defaultValue: 'cypress/fixtures',
|
||||
@@ -331,5 +324,9 @@ export const breakingOptions = [
|
||||
name: 'experimentalShadowDomSupport',
|
||||
errorKey: 'EXPERIMENTAL_SHADOW_DOM_REMOVED',
|
||||
isWarning: true,
|
||||
}, {
|
||||
name: 'firefoxGcInterval',
|
||||
errorKey: 'FIREFOX_GC_INTERVAL_REMOVED',
|
||||
isWarning: true,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -940,6 +940,13 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) {
|
||||
return stripIndent`\
|
||||
The \`experimentalRunEvents\` configuration option was removed in Cypress version \`6.7.0\`. It is no longer necessary when listening to run events in the plugins file.
|
||||
|
||||
You can safely remove this option from your config.`
|
||||
case 'FIREFOX_GC_INTERVAL_REMOVED':
|
||||
return stripIndent`\
|
||||
The \`firefoxGcInterval\` configuration option was removed in Cypress version \`8.0.0\`. It was introduced to work around a bug in Firefox 79 and below.
|
||||
|
||||
Since Cypress no longer supports Firefox 85 and below in Cypress 8, this option was removed.
|
||||
|
||||
You can safely remove this option from your config.`
|
||||
case 'INCOMPATIBLE_PLUGIN_RETRIES':
|
||||
return stripIndent`\
|
||||
@@ -980,6 +987,8 @@ const getMsgByType = function (type, arg1 = {}, arg2, arg3) {
|
||||
|
||||
https://on.cypress.io/component-testing
|
||||
`
|
||||
case 'UNSUPPORTED_BROWSER_VERSION':
|
||||
return arg1
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,8 +543,8 @@ const getChromeProps = (writeVideoFrame) => {
|
||||
const getElectronProps = (isHeaded, writeVideoFrame, onError) => {
|
||||
return _
|
||||
.chain({
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
width: 1280,
|
||||
height: 720,
|
||||
show: isHeaded,
|
||||
onCrashed () {
|
||||
const err = errors.get('RENDERER_CRASHED')
|
||||
@@ -1259,11 +1259,6 @@ module.exports = {
|
||||
},
|
||||
|
||||
runSpecs (options = {}) {
|
||||
_.defaults(options, {
|
||||
// only non-Electron browsers run headed by default
|
||||
headed: options.browser.name !== 'electron',
|
||||
})
|
||||
|
||||
const { config, browser, sys, headed, outputPath, specs, specPattern, beforeSpecRun, afterSpecRun, runUrl, parallel, group, tag, testingType } = options
|
||||
|
||||
const isHeadless = !headed
|
||||
@@ -1552,7 +1547,7 @@ module.exports = {
|
||||
trashAssets(config),
|
||||
])
|
||||
.spread((sys = {}, browser = {}, specs = []) => {
|
||||
// return only what is return to the specPattern
|
||||
// return only what is return to the specPattern
|
||||
if (specPattern) {
|
||||
specPattern = specsUtil.getPatternRelativeToProjectRoot(specPattern, projectRoot)
|
||||
}
|
||||
@@ -1567,6 +1562,10 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
|
||||
if (browser.unsupportedVersion && browser.warning) {
|
||||
errors.throw('UNSUPPORTED_BROWSER_VERSION', browser.warning)
|
||||
}
|
||||
|
||||
if (browser.family === 'chromium') {
|
||||
chromePolicyCheck.run(onWarning)
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ import { checkSupportFile } from './project_utils'
|
||||
// and are required when creating a project.
|
||||
// TODO: Figure out how to type this better.
|
||||
type ReceivedCypressOptions =
|
||||
Partial<Pick<Cypress.RuntimeConfigOptions, 'hosts' | 'projectName' | 'clientRoute' | 'devServerPublicPathRoute' | 'supportFolder' | 'namespace' | 'report' | 'socketIoCookie' | 'configFile' | 'isTextTerminal' | 'isNewProject' | 'proxyUrl' | 'browsers'>>
|
||||
& Partial<Pick<Cypress.ResolvedConfigOptions, 'experimentalSourceRewriting' | 'fixturesFolder' | 'reporter' | 'reporterOptions' | 'screenshotsFolder' | 'pluginsFile' | 'supportFile' | 'integrationFolder' | 'baseUrl' | 'viewportHeight' | 'viewportWidth' | 'port' | 'experimentalInteractiveRunEvents'>>
|
||||
Partial<Pick<Cypress.RuntimeConfigOptions, 'hosts' | 'projectName' | 'clientRoute' | 'devServerPublicPathRoute' | 'namespace' | 'report' | 'socketIoCookie' | 'configFile' | 'isTextTerminal' | 'isNewProject' | 'proxyUrl' | 'browsers'>>
|
||||
& Partial<Pick<Cypress.ResolvedConfigOptions, 'supportFolder' | 'experimentalSourceRewriting' | 'fixturesFolder' | 'reporter' | 'reporterOptions' | 'screenshotsFolder' | 'pluginsFile' | 'supportFile' | 'integrationFolder' | 'baseUrl' | 'viewportHeight' | 'viewportWidth' | 'port' | 'experimentalInteractiveRunEvents'>>
|
||||
|
||||
export interface Cfg extends ReceivedCypressOptions {
|
||||
projectRoot: string
|
||||
@@ -678,7 +678,7 @@ export class ProjectBase<TServer extends ServerE2E | ServerCt> extends EE {
|
||||
|
||||
return {
|
||||
...browser,
|
||||
warning: errors.getMsgByType('CHROME_WEB_SECURITY_NOT_SUPPORTED', browser.name),
|
||||
warning: browser.warning || errors.getMsgByType('CHROME_WEB_SECURITY_NOT_SUPPORTED', browser.name),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -365,6 +365,8 @@ export class SocketBase {
|
||||
return firefoxUtil.log()
|
||||
case 'firefox:force:gc':
|
||||
return firefoxUtil.collectGarbage()
|
||||
case 'firefox:window:focus':
|
||||
return firefoxUtil.windowFocus()
|
||||
case 'get:fixture':
|
||||
return getFixture(args[0], args[1])
|
||||
case 'read:file':
|
||||
|
||||
@@ -121,25 +121,6 @@ const isValidRetriesConfig = (key, value) => {
|
||||
return errMsg(key, value, 'a positive number or null or an object with keys "openMode" and "runMode" with values of numbers or nulls')
|
||||
}
|
||||
|
||||
const isValidFirefoxGcInterval = (key, value) => {
|
||||
const isIntervalValue = (val) => {
|
||||
if (isNumber(val)) {
|
||||
return val >= 0
|
||||
}
|
||||
|
||||
return val == null
|
||||
}
|
||||
|
||||
if (isIntervalValue(value)
|
||||
|| (_.isEqual(_.keys(value), ['runMode', 'openMode'])
|
||||
&& isIntervalValue(value.runMode)
|
||||
&& isIntervalValue(value.openMode))) {
|
||||
return true
|
||||
}
|
||||
|
||||
return errMsg(key, value, 'a positive number or null or an object with "openMode" and "runMode" as keys and positive numbers or nulls as values')
|
||||
}
|
||||
|
||||
const isPlainObject = (key, value) => {
|
||||
if (value == null || _.isPlainObject(value)) {
|
||||
return true
|
||||
@@ -283,8 +264,6 @@ module.exports = {
|
||||
|
||||
isValidBrowserList,
|
||||
|
||||
isValidFirefoxGcInterval,
|
||||
|
||||
isValidRetriesConfig,
|
||||
|
||||
isValidConfig,
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
"supertest-session": "4.0.0",
|
||||
"through2": "2.0.5",
|
||||
"ts-loader": "7.0.4",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"tsconfig-paths": "3.10.1",
|
||||
"webpack": "4.43.0",
|
||||
"ws": "5.2.3",
|
||||
"xvfb": "cypress-io/node-xvfb#22e3783c31d81ebe64d8c0df491ea00cdc74726a",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
diff --git a/node_modules/tsconfig-paths/lib/register.js b/node_modules/tsconfig-paths/lib/register.js
|
||||
index c12b996..8beea8c 100644
|
||||
index 311c7fd..ac9feec 100644
|
||||
--- a/node_modules/tsconfig-paths/lib/register.js
|
||||
+++ b/node_modules/tsconfig-paths/lib/register.js
|
||||
@@ -51,7 +51,7 @@ function register(explicitParams) {
|
||||
explicitParams: explicitParams
|
||||
explicitParams: explicitParams,
|
||||
});
|
||||
if (configLoaderResult.resultType === "failed") {
|
||||
- console.warn(configLoaderResult.message + ". tsconfig-paths will be skipped");
|
||||
@@ -84,4 +84,10 @@ describe('e2e headless', function () {
|
||||
project: Fixtures.projectPath('screen-size'),
|
||||
spec: 'default_size.spec.js',
|
||||
})
|
||||
|
||||
e2e.it('launches at DPR 1x', {
|
||||
headed: false,
|
||||
project: Fixtures.projectPath('screen-size'),
|
||||
spec: 'device_pixel_ratio.spec.js',
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1048,8 +1048,8 @@ describe('lib/cypress', () => {
|
||||
// when we work with the browsers we set a few extra flags
|
||||
const chrome = _.find(TYPICAL_BROWSERS, { name: 'chrome' })
|
||||
const launchedChrome = R.merge(chrome, {
|
||||
isHeadless: false,
|
||||
isHeaded: true,
|
||||
isHeadless: true,
|
||||
isHeaded: false,
|
||||
})
|
||||
|
||||
expect(args[0], 'found and used Chrome').to.deep.eq(launchedChrome)
|
||||
|
||||
@@ -19,18 +19,13 @@ function parse (obj) {
|
||||
const str = JSON.stringify(obj, [
|
||||
'usedJSHeapSize',
|
||||
'totalJSHeapSize',
|
||||
|
||||
'jsHeapSizeLimit',
|
||||
])
|
||||
|
||||
return JSON.parse(str)
|
||||
}
|
||||
const stats = () => {
|
||||
const { firefoxGcInterval, firefoxGcInOpenMode } = Cypress.config()
|
||||
|
||||
cy.task('console', {
|
||||
firefoxGcInterval,
|
||||
firefoxGcInOpenMode,
|
||||
numTests: NUM_TESTS,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
describe('windowSize', () => {
|
||||
it('spawns with correct default size', () => {
|
||||
// assert the browser was spawned at 1920x1080 and is full size
|
||||
// assert the browser was spawned at 1280x720 and is full size
|
||||
// normally e2e tests spawn at fixed size, but this spec should be spawned without passing any width/height arguments in plugins file.
|
||||
// TODO: look into fixing screen/available height and width
|
||||
expect({
|
||||
@@ -11,12 +11,12 @@ describe('windowSize', () => {
|
||||
// availWidth: top.screen.availWidth,
|
||||
// availHeight: top.screen.availHeight,
|
||||
}).deep.eq({
|
||||
innerWidth: 1920,
|
||||
innerHeight: 1080,
|
||||
// screenWidth: 1920,
|
||||
// screenHeight: 1080,
|
||||
// availWidth: 1920,
|
||||
// availHeight: 1080,
|
||||
innerWidth: 1280,
|
||||
innerHeight: 720,
|
||||
// screenWidth: 1280,
|
||||
// screenHeight: 720,
|
||||
// availWidth: 1280,
|
||||
// availHeight: 720,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
describe('devicePixelRatio', () => {
|
||||
it('has DPR of 1', () => {
|
||||
// assert the browser was spawned with DPR of 1
|
||||
expect(window.devicePixelRatio).to.equal(1)
|
||||
})
|
||||
})
|
||||
@@ -4,6 +4,7 @@
|
||||
module.exports = (on) => {
|
||||
on('before:browser:launch', (browser, options) => {
|
||||
// options.args.push('-width', '1280', '-height', '1024')
|
||||
// options.args.push('--force-device-scale-factor=2')
|
||||
|
||||
// return options
|
||||
})
|
||||
|
||||
@@ -99,7 +99,7 @@ describe('lib/browsers/chrome', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('sets default window size in headless mode', function () {
|
||||
it('sets default window size and DPR in headless mode', function () {
|
||||
chrome._writeExtension.restore()
|
||||
|
||||
return chrome.open({ isHeadless: true, isHeaded: false }, 'http://', {}, this.automation)
|
||||
@@ -108,7 +108,8 @@ describe('lib/browsers/chrome', () => {
|
||||
|
||||
expect(args).to.include.members([
|
||||
'--headless',
|
||||
'--window-size=1920,1080',
|
||||
'--window-size=1280,720',
|
||||
'--force-device-scale-factor=1',
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -853,38 +853,6 @@ describe('lib/config', () => {
|
||||
})
|
||||
})
|
||||
|
||||
context('firefoxGcInterval', () => {
|
||||
it('passes if a number', function () {
|
||||
this.setup({ firefoxGcInterval: 1 })
|
||||
|
||||
return this.expectValidationPasses()
|
||||
})
|
||||
|
||||
it('passes if null', function () {
|
||||
this.setup({ firefoxGcInterval: null })
|
||||
|
||||
return this.expectValidationPasses()
|
||||
})
|
||||
|
||||
it('passes if correctly shaped object', function () {
|
||||
this.setup({ firefoxGcInterval: { runMode: 1, openMode: null } })
|
||||
|
||||
return this.expectValidationPasses()
|
||||
})
|
||||
|
||||
it('fails if string', function () {
|
||||
this.setup({ firefoxGcInterval: 'foo' })
|
||||
|
||||
return this.expectValidationFails('a positive number or null or an object')
|
||||
})
|
||||
|
||||
it('fails if invalid object', function () {
|
||||
this.setup({ firefoxGcInterval: { foo: 'bar' } })
|
||||
|
||||
return this.expectValidationFails('a positive number or null or an object')
|
||||
})
|
||||
})
|
||||
|
||||
function pemCertificate () {
|
||||
return {
|
||||
clientCertificates: [
|
||||
@@ -1433,6 +1401,16 @@ describe('lib/config', () => {
|
||||
expect(warning).to.be.calledWith('EXPERIMENTAL_NETWORK_STUBBING_REMOVED')
|
||||
})
|
||||
|
||||
it('warns if firefoxGcInterval is passed', async function () {
|
||||
const warning = sinon.spy(errors, 'warning')
|
||||
|
||||
await this.defaults('firefoxGcInterval', true, {
|
||||
firefoxGcInterval: true,
|
||||
})
|
||||
|
||||
expect(warning).to.be.calledWith('FIREFOX_GC_INTERVAL_REMOVED')
|
||||
})
|
||||
|
||||
describe('.resolved', () => {
|
||||
it('sets reporter and port to cli', () => {
|
||||
const obj = {
|
||||
@@ -1465,7 +1443,6 @@ describe('lib/config', () => {
|
||||
experimentalSourceRewriting: { value: false, from: 'default' },
|
||||
experimentalStudio: { value: false, from: 'default' },
|
||||
fileServerFolder: { value: '', from: 'default' },
|
||||
firefoxGcInterval: { value: { openMode: null, runMode: 1 }, from: 'default' },
|
||||
fixturesFolder: { value: 'cypress/fixtures', from: 'default' },
|
||||
hosts: { value: null, from: 'default' },
|
||||
ignoreTestFiles: { value: '*.hot-update.js', from: 'default' },
|
||||
@@ -1571,7 +1548,6 @@ describe('lib/config', () => {
|
||||
},
|
||||
},
|
||||
fileServerFolder: { value: '', from: 'default' },
|
||||
firefoxGcInterval: { value: { openMode: null, runMode: 1 }, from: 'default' },
|
||||
fixturesFolder: { value: 'cypress/fixtures', from: 'default' },
|
||||
hosts: { value: null, from: 'default' },
|
||||
ignoreTestFiles: { value: '*.hot-update.js', from: 'default' },
|
||||
|
||||
@@ -100,9 +100,9 @@ describe('lib/modes/run', () => {
|
||||
it('sets width and height', () => {
|
||||
const props = runMode.getElectronProps()
|
||||
|
||||
expect(props.width).to.eq(1920)
|
||||
expect(props.width).to.eq(1280)
|
||||
|
||||
expect(props.height).to.eq(1080)
|
||||
expect(props.height).to.eq(720)
|
||||
})
|
||||
|
||||
it('sets show to boolean', () => {
|
||||
@@ -701,6 +701,15 @@ describe('lib/modes/run', () => {
|
||||
.to.be.rejectedWith(/invalid browser family in/)
|
||||
})
|
||||
|
||||
it('throws an error if unsupportedVersion', () => {
|
||||
const browser = { displayName: 'SomeBrowser', warning: 'blah blah', unsupportedVersion: true }
|
||||
|
||||
sinon.stub(browsers, 'ensureAndGetByNameOrPath').resolves(browser)
|
||||
|
||||
return expect(runMode.run())
|
||||
.to.be.rejectedWith('blah blah')
|
||||
})
|
||||
|
||||
it('shows no warnings for chrome browser', () => {
|
||||
return runMode.run({ browser: 'chrome' })
|
||||
.then(() => {
|
||||
|
||||
@@ -108,8 +108,10 @@ class Dropdown extends Component<Props> {
|
||||
}
|
||||
|
||||
_onSelect (item: object) {
|
||||
this.setState({ open: false })
|
||||
this.props.onSelect(item)
|
||||
const retval = this.props.onSelect(item)
|
||||
const open = _.isBoolean(retval) ? retval : false
|
||||
|
||||
this.setState({ open })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/bin/bash
|
||||
if [ $SKIP_DEPCHECK ]; then exit 0; fi
|
||||
|
||||
yarn check --integrity
|
||||
|
||||
if [ $? -ne 0 ];
|
||||
then
|
||||
if [ $? -ne 0 ]; then
|
||||
echo 'Your dependencies are out of date; installing the correct dependencies...'
|
||||
yarn
|
||||
fi
|
||||
|
||||
22
yarn.lock
22
yarn.lock
@@ -7917,11 +7917,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
|
||||
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
|
||||
|
||||
"@types/json5@^0.0.29":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
||||
|
||||
"@types/keyv@*":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
|
||||
@@ -24264,7 +24259,7 @@ json5@^1.0.1:
|
||||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
json5@^2.1.0, json5@^2.1.2, json5@^2.1.3:
|
||||
json5@^2.1.0, json5@^2.1.2, json5@^2.1.3, json5@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
|
||||
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
|
||||
@@ -31047,7 +31042,7 @@ pretty-error@^2.0.2, pretty-error@^2.1.1:
|
||||
|
||||
pretty-format@26.4.0, pretty-format@^24.9.0, pretty-format@^26.6.2:
|
||||
version "26.4.0"
|
||||
resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.0.tgz#c08073f531429e9e5024049446f42ecc9f933a3b"
|
||||
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.4.0.tgz#c08073f531429e9e5024049446f42ecc9f933a3b"
|
||||
integrity sha512-mEEwwpCseqrUtuMbrJG4b824877pM5xald3AkilJ47Po2YLr97/siejYQHqj2oDQBeJNbu+Q0qUuekJ8F0NAPg==
|
||||
dependencies:
|
||||
"@jest/types" "^26.3.0"
|
||||
@@ -37421,13 +37416,12 @@ tsconfig-paths-webpack-plugin@^3.3.0, tsconfig-paths-webpack-plugin@^3.5.1:
|
||||
enhanced-resolve "^5.7.0"
|
||||
tsconfig-paths "^3.9.0"
|
||||
|
||||
tsconfig-paths@3.9.0, tsconfig-paths@^3.9.0:
|
||||
version "3.9.0"
|
||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
|
||||
integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==
|
||||
tsconfig-paths@3.10.1, tsconfig-paths@^3.9.0:
|
||||
version "3.10.1"
|
||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz#79ae67a68c15289fdf5c51cb74f397522d795ed7"
|
||||
integrity sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==
|
||||
dependencies:
|
||||
"@types/json5" "^0.0.29"
|
||||
json5 "^1.0.1"
|
||||
json5 "^2.2.0"
|
||||
minimist "^1.2.0"
|
||||
strip-bom "^3.0.0"
|
||||
|
||||
@@ -38961,7 +38955,7 @@ vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
|
||||
|
||||
vue-template-compiler@2.6.12, vue-template-compiler@^2.6.11:
|
||||
version "2.6.12"
|
||||
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
|
||||
resolved "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
|
||||
integrity sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==
|
||||
dependencies:
|
||||
de-indent "^1.0.2"
|
||||
|
||||
Reference in New Issue
Block a user