mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-02 04:50:06 -05:00
Merge branch develop into 9.0-release
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
14.16.0
|
||||
14.17.0
|
||||
|
||||
Vendored
-8
@@ -23,14 +23,6 @@
|
||||
"execute": false,
|
||||
"command": "yarn cypress:run --project ../project"
|
||||
},
|
||||
{
|
||||
"name": "cypress open (CT)",
|
||||
"focus": true,
|
||||
"onlySingle": true,
|
||||
"execute": true,
|
||||
"cwd": "[cwd]/packages/server-ct",
|
||||
"command": "yarn cypress:open"
|
||||
},
|
||||
{
|
||||
"name": "packages/server test-e2e",
|
||||
"focus": true,
|
||||
|
||||
+13
-5
@@ -278,6 +278,9 @@ Here is a list of the core packages in this repository with a short description,
|
||||
| [example](./packages/example) | `@packages/example` | Our example kitchen-sink application. |
|
||||
| [extension](./packages/extension) | `@packages/extension` | The Cypress Chrome browser extension |
|
||||
| [https-proxy](./packages/https-proxy) | `@packages/https-proxy` | This does https proxy for handling http certs and traffic. |
|
||||
| [net-stubbing](./packages/net-stubbing) | `@packages/net-stubbing` | Contains server side code for Cypress' network stubbing features. |
|
||||
| [network](./packages/networ ) | `@packages/network` | Various utilities related to networking. |
|
||||
| [proxy](./packages/proxy) | `@packages/proxy` | Code for Cypress' network proxy layer. |
|
||||
| [launcher](./packages/launcher) | `@packages/launcher` | Finds and launches browsers installed on your system. |
|
||||
| [reporter](./packages/reporter) | `@packages/reporter` | The reporter shows the running results of the tests (The Command Log UI). |
|
||||
| [root](./packages/root) | `@packages/root` | Dummy package pointing at the root of the repository. |
|
||||
@@ -285,8 +288,8 @@ Here is a list of the core packages in this repository with a short description,
|
||||
| [runner-ct](./packages/runner-ct) | `@packages/runner-ct` | The runner for component testing |
|
||||
| [runner-shared](./packages/runner-shared) | `@packages/runner-shared` | The shared components between the `runner` and the `runner-ct` packages |
|
||||
| [server](./packages/server) | `@packages/server` | The <3 of Cypress. This orchestrates everything. The backend node process. |
|
||||
| [server-ct](./packages/server-ct) | `@packages/server-ct` | Some Component Testing specific overrides. Mostly extends functionality from `@packages/server` |
|
||||
| [socket](./packages/socket) | `@packages/socket` | A wrapper around socket.io to provide common libraries. |
|
||||
| [static](./packages/static) | `@packages/static` | Serves static assets used in the Cypress GUI. |
|
||||
| [ts](./packages/ts) | `@packages/ts` | A centralized version of typescript. |
|
||||
|
||||
Public packages live within the [`npm`](./npm) folder and are standalone modules that get independently published to npm under the `@cypress/` namespace. These packages generally contain extensions, plugins, or other packages that are complementary to, yet independent of, the main Cypress app.
|
||||
@@ -295,10 +298,15 @@ Here is a list of the npm packages in this repository:
|
||||
|
||||
| Folder Name | Package Name | Purpose |
|
||||
| :----------------------------------------------------- | :--------------------------------- | :--------------------------------------------------------------------------- |
|
||||
| [eslint-plugin-dev](./npm/eslint-plugin-dev) | `@cypress/eslint-plugin-dev` | Eslint plugin for internal development. |
|
||||
| [react](./npm/react) | `@cypress/react` | Cypress component testing for React. |
|
||||
| [vue](./npm/vue) | `@cypress/vue` | Cypress component testing for Vue. |
|
||||
| [webpack-preprocessor](./npm/webpack-preprocessor) | `@cypress/webpack-preprocessor` | Cypress preprocessor for bundling JavaScript via webpack. |
|
||||
| [angular](./npm/angular) | `@cypress/angular` | Cypress component testing for Angular. |
|
||||
| [create-cypress-tests](./npm/create-cypress-tests) | `@cypress/create-cypress-tests` | Tooling to scaffold Cypress configuration and demo test files. |
|
||||
| [eslint-plugin-dev](./npm/eslint-plugin-dev) | `@cypress/eslint-plugin-dev` | Eslint plugin for internal development. |
|
||||
| [mount-utils](./npm/mount-utils) | `@cypress/mount-utils` | Common functionality for Vue/React/Angular adapters. |
|
||||
| [react](./npm/react) | `@cypress/react` | Cypress component testing for React. |
|
||||
| [vite-dev-server](./npm/vite-dev-server) | `@cypress/vite-dev-server` | Vite powered dev server for Component Testing. |
|
||||
| [webpack-preprocessor](./npm/webpack-preprocessor) | `@cypress/webpack-preprocessor` | Cypress preprocessor for bundling JavaScript via webpack. |
|
||||
| [webpack-dev-server](./npm/webpack-dev-server) | `@cypress/webpack-dev-server` | Webpack powered dev server for Component Testing. |
|
||||
| [vue](./npm/vue) | `@cypress/vue` | Cypress component testing for Vue. |
|
||||
|
||||
We try to tag all issues with a `pkg/` or `npm/` tag describing the appropriate package the work is required in. For public packages, we use their qualified package name: For example, issues relating to the webpack preprocessor are tagged under [`npm: @cypress/webpack-preprocessor`](https://github.com/cypress-io/cypress/labels/npm%3A%20%40cypress%2Fwebpack-preprocessor) label and issues related to the `driver` package are tagged with the [`pkg/driver`](https://github.com/cypress-io/cypress/labels/pkg%2Fdriver) label.
|
||||
|
||||
|
||||
+2
-2
@@ -2,13 +2,13 @@ branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
- windows-code-signing
|
||||
- fix-test-other-projects
|
||||
- /win*/
|
||||
|
||||
# https://www.appveyor.com/docs/lang/nodejs-iojs/
|
||||
environment:
|
||||
# use matching version of Node.js
|
||||
nodejs_version: "14.16.0"
|
||||
nodejs_version: "14.17.0"
|
||||
# encode secure variables which will NOT be used
|
||||
# in pull requests
|
||||
# https://www.appveyor.com/docs/build-configuration/#secure-variables
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"chrome:beta": "93.0.4577.18",
|
||||
"chrome:stable": "92.0.4515.107"
|
||||
"chrome:beta": "94.0.4606.54",
|
||||
"chrome:stable": "94.0.4606.54"
|
||||
}
|
||||
|
||||
+19
-16
@@ -8,7 +8,7 @@ macBuildFilters: &macBuildFilters
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/fix/mac-build
|
||||
- tgriesser/chore/fix-release
|
||||
|
||||
defaults: &defaults
|
||||
parallelism: 1
|
||||
@@ -42,6 +42,7 @@ onlyMainBranches: &onlyMainBranches
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
|
||||
@@ -49,7 +50,7 @@ executors:
|
||||
# the Docker image with Cypress dependencies and Chrome browser
|
||||
cy-doc:
|
||||
docker:
|
||||
- image: cypress/browsers:node14.16.0-chrome90-ff88
|
||||
- image: cypress/browsers:node14.17.0-chrome91-ff89
|
||||
# by default, we use "small" to save on CI costs. bump on a per-job basis if needed.
|
||||
resource_class: small
|
||||
environment:
|
||||
@@ -58,7 +59,7 @@ executors:
|
||||
# Docker image with non-root "node" user
|
||||
non-root-docker-user:
|
||||
docker:
|
||||
- image: cypress/browsers:node14.16.0-chrome90-ff88
|
||||
- image: cypress/browsers:node14.17.0-chrome91-ff89
|
||||
user: node
|
||||
environment:
|
||||
PLATFORM: linux
|
||||
@@ -303,6 +304,7 @@ commands:
|
||||
dpkg -i /usr/src/google-chrome-<<parameters.channel>>_<<parameters.version>>_amd64.deb ; \
|
||||
apt-get install -f -y && \
|
||||
rm -f /usr/src/google-chrome-<<parameters.channel>>_<<parameters.version>>_amd64.deb
|
||||
which google-chrome-<<parameters.channel>> || (printf "\n\033[0;31mChrome was not successfully downloaded - bailing\033[0m\n\n" && exit 1)
|
||||
echo "Location of Google Chrome Installation: `which google-chrome-<<parameters.channel>>`"
|
||||
echo "Google Chrome Version: `google-chrome-<<parameters.channel>> --version`"
|
||||
|
||||
@@ -373,6 +375,7 @@ commands:
|
||||
PERCY_ENABLE=${PERCY_TOKEN:-0} \
|
||||
PERCY_PARALLEL_TOTAL=-1 \
|
||||
$cmd yarn workspace @packages/runner cypress:run --record --parallel --group runner-integration-<<parameters.browser>> --browser <<parameters.browser>>
|
||||
- verify-mocha-results
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
- store_artifacts:
|
||||
@@ -407,6 +410,7 @@ commands:
|
||||
else
|
||||
echo "skipping percy screenshots uploading"
|
||||
fi
|
||||
- verify-mocha-results
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
- store_artifacts:
|
||||
@@ -1030,18 +1034,6 @@ jobs:
|
||||
path: /tmp/cypress
|
||||
- store-npm-logs
|
||||
|
||||
server-ct-unit-tests:
|
||||
<<: *defaults
|
||||
parallelism: 1
|
||||
steps:
|
||||
- restore_cached_workspace
|
||||
- run: yarn test-unit --scope @packages/server-ct
|
||||
- verify-mocha-results:
|
||||
expectedResultCount: 1
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
- store-npm-logs
|
||||
|
||||
server-integration-tests:
|
||||
<<: *defaults
|
||||
resource_class: medium
|
||||
@@ -1126,6 +1118,7 @@ jobs:
|
||||
|
||||
runner-integration-tests-electron:
|
||||
<<: *defaults
|
||||
resource_class: medium
|
||||
parallelism: 2
|
||||
steps:
|
||||
- run-runner-integration-tests:
|
||||
@@ -1150,6 +1143,7 @@ jobs:
|
||||
|
||||
driver-integration-tests-chrome-beta:
|
||||
<<: *defaults
|
||||
resource_class: medium
|
||||
parallelism: 5
|
||||
steps:
|
||||
- run-driver-integration-tests:
|
||||
@@ -1488,7 +1482,7 @@ jobs:
|
||||
- run:
|
||||
name: Check current branch to persist artifacts
|
||||
command: |
|
||||
if [[ "$CIRCLE_BRANCH" != "develop" ]]; then
|
||||
if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "tgriesser/chore/fix-release" ]]; then
|
||||
echo "Not uploading artifacts or posting install comment for this branch."
|
||||
circleci-agent step halt
|
||||
fi
|
||||
@@ -2080,6 +2074,7 @@ linux-workflow: &linux-workflow
|
||||
# Any attempts to automate this are welcome
|
||||
# If CircleCI provided an "after all" hook, then this wouldn't be necessary
|
||||
- npm-release:
|
||||
context: test-runner:npm-release
|
||||
requires:
|
||||
- build
|
||||
- npm-eslint-plugin-dev
|
||||
@@ -2123,6 +2118,7 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- build
|
||||
- test-kitchensink:
|
||||
@@ -2134,6 +2130,7 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- build
|
||||
- create-build-artifacts:
|
||||
@@ -2183,6 +2180,7 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
- test-npm-module-and-verify-binary:
|
||||
@@ -2190,6 +2188,7 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
- test-binary-against-staging:
|
||||
@@ -2198,6 +2197,7 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
|
||||
@@ -2222,6 +2222,7 @@ linux-workflow: &linux-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- create-build-artifacts
|
||||
|
||||
@@ -2293,6 +2294,7 @@ mac-workflow: &mac-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- darwin-create-build-artifacts
|
||||
|
||||
@@ -2304,6 +2306,7 @@ mac-workflow: &mac-workflow
|
||||
branches:
|
||||
only:
|
||||
- develop
|
||||
- tgriesser/chore/fix-release
|
||||
requires:
|
||||
- darwin-create-build-artifacts
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ const request = require('@cypress/request')
|
||||
const Promise = require('bluebird')
|
||||
const requestProgress = require('request-progress')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const getProxyForUrl = require('proxy-from-env').getProxyForUrl
|
||||
|
||||
const { throwFormErrorText, errors } = require('../errors')
|
||||
const fs = require('../fs')
|
||||
@@ -16,12 +17,9 @@ const util = require('../util')
|
||||
|
||||
const defaultBaseUrl = 'https://download.cypress.io/'
|
||||
|
||||
const getProxyUrl = () => {
|
||||
return process.env.HTTPS_PROXY ||
|
||||
process.env.https_proxy ||
|
||||
const getProxyForUrlWithNpmConfig = (url) => {
|
||||
return getProxyForUrl(url) ||
|
||||
process.env.npm_config_https_proxy ||
|
||||
process.env.HTTP_PROXY ||
|
||||
process.env.http_proxy ||
|
||||
process.env.npm_config_proxy ||
|
||||
null
|
||||
}
|
||||
@@ -205,7 +203,7 @@ const verifyDownloadedFile = (filename, expectedSize, expectedChecksum) => {
|
||||
// {filename: ..., downloaded: true}
|
||||
const downloadFromUrl = ({ url, downloadDestination, progress, ca }) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const proxy = getProxyUrl()
|
||||
const proxy = getProxyForUrlWithNpmConfig(url)
|
||||
|
||||
debug('Downloading package', {
|
||||
url,
|
||||
@@ -357,6 +355,6 @@ const start = (opts) => {
|
||||
module.exports = {
|
||||
start,
|
||||
getUrl,
|
||||
getProxyUrl,
|
||||
getProxyForUrlWithNpmConfig,
|
||||
getCA,
|
||||
}
|
||||
|
||||
+2
-1
@@ -20,7 +20,7 @@
|
||||
"unit": "cross-env BLUEBIRD_DEBUG=1 NODE_ENV=test mocha --reporter mocha-multi-reporters --reporter-options configFile=../mocha-reporter-config.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cypress/request": "^2.88.5",
|
||||
"@cypress/request": "^2.88.6",
|
||||
"@cypress/xvfb": "^1.2.4",
|
||||
"@types/node": "^14.14.31",
|
||||
"@types/sinonjs__fake-timers": "^6.0.2",
|
||||
@@ -54,6 +54,7 @@
|
||||
"minimist": "^1.2.5",
|
||||
"ospath": "^1.2.2",
|
||||
"pretty-bytes": "^5.6.0",
|
||||
"proxy-from-env": "1.0.0",
|
||||
"ramda": "~0.27.1",
|
||||
"request-progress": "^3.0.0",
|
||||
"supports-color": "^8.1.1",
|
||||
|
||||
@@ -313,28 +313,60 @@ describe('lib/tasks/download', function () {
|
||||
})
|
||||
|
||||
context('with proxy env vars', () => {
|
||||
const testUriHttp = 'http://anything.com'
|
||||
const testUriHttps = 'https://anything.com'
|
||||
|
||||
beforeEach(function () {
|
||||
this.env = _.clone(process.env)
|
||||
// add a default no_proxy which does not match the testUri
|
||||
process.env.NO_PROXY = 'localhost,.org'
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
process.env = this.env
|
||||
})
|
||||
|
||||
it('prefers https_proxy over http_proxy', () => {
|
||||
process.env.HTTP_PROXY = 'foo'
|
||||
expect(download.getProxyUrl()).to.eq('foo')
|
||||
process.env.https_proxy = 'bar'
|
||||
expect(download.getProxyUrl()).to.eq('bar')
|
||||
it('uses http_proxy on http request', () => {
|
||||
process.env.http_proxy = 'http://foo'
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttp)).to.eq('http://foo')
|
||||
})
|
||||
|
||||
it('ignores http_proxy on https request', () => {
|
||||
process.env.http_proxy = 'http://foo'
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttps)).to.eq(null)
|
||||
process.env.https_proxy = 'https://bar'
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttps)).to.eq('https://bar')
|
||||
})
|
||||
|
||||
it('falls back to npm_config_proxy', () => {
|
||||
process.env.npm_config_proxy = 'foo'
|
||||
expect(download.getProxyUrl()).to.eq('foo')
|
||||
process.env.npm_config_https_proxy = 'bar'
|
||||
expect(download.getProxyUrl()).to.eq('bar')
|
||||
process.env.https_proxy = 'baz'
|
||||
expect(download.getProxyUrl()).to.eq('baz')
|
||||
process.env.npm_config_proxy = 'http://foo'
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttps)).to.eq('http://foo')
|
||||
process.env.npm_config_https_proxy = 'https://bar'
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttps)).to.eq('https://bar')
|
||||
process.env.https_proxy = 'https://baz'
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttps)).to.eq('https://baz')
|
||||
})
|
||||
|
||||
it('respects no_proxy on http and https requests', () => {
|
||||
process.env.NO_PROXY = 'localhost,.com'
|
||||
|
||||
process.env.http_proxy = 'http://foo'
|
||||
process.env.https_proxy = 'https://bar'
|
||||
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttp)).to.eq(null)
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttps)).to.eq(null)
|
||||
})
|
||||
|
||||
it('ignores no_proxy for npm proxy configs, prefers https over http', () => {
|
||||
process.env.NO_PROXY = 'localhost,.com'
|
||||
|
||||
process.env.npm_config_proxy = 'http://foo'
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttp)).to.eq('http://foo')
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttps)).to.eq('http://foo')
|
||||
|
||||
process.env.npm_config_https_proxy = 'https://bar'
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttp)).to.eq('https://bar')
|
||||
expect(download.getProxyForUrlWithNpmConfig(testUriHttps)).to.eq('https://bar')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Vendored
+79
-12
@@ -22,6 +22,19 @@ declare namespace Cypress {
|
||||
password: string
|
||||
}
|
||||
|
||||
interface RemoteState {
|
||||
auth?: {
|
||||
username: string
|
||||
password: string
|
||||
}
|
||||
domainName: string
|
||||
strategy: 'file' | 'http'
|
||||
origin: string
|
||||
fileServer: string
|
||||
props: Record<string, any>
|
||||
visiting: string
|
||||
}
|
||||
|
||||
interface Backend {
|
||||
/**
|
||||
* Firefox only: Force Cypress to run garbage collection routines.
|
||||
@@ -982,7 +995,7 @@ declare namespace Cypress {
|
||||
* .its('contentType')
|
||||
* .should('eq', 'text/html')
|
||||
*/
|
||||
document(options?: Partial<Loggable>): Chainable<Document>
|
||||
document(options?: Partial<Loggable & Timeoutable>): Chainable<Document>
|
||||
|
||||
/**
|
||||
* Iterate through an array like structure (arrays or objects with a length property).
|
||||
@@ -1958,7 +1971,7 @@ declare namespace Cypress {
|
||||
*
|
||||
* @see https://on.cypress.io/title
|
||||
*/
|
||||
title(options?: Partial<Loggable>): Chainable<string>
|
||||
title(options?: Partial<Loggable & Timeoutable>): Chainable<string>
|
||||
|
||||
/**
|
||||
* Trigger an event on a DOM element.
|
||||
@@ -2060,7 +2073,7 @@ declare namespace Cypress {
|
||||
* @alias cy.location('href')
|
||||
* @see https://on.cypress.io/url
|
||||
*/
|
||||
url(options?: Partial<Loggable & Timeoutable>): Chainable<string>
|
||||
url(options?: Partial<UrlOptions>): Chainable<string>
|
||||
|
||||
/**
|
||||
* Control the size and orientation of the screen for your application.
|
||||
@@ -2488,6 +2501,47 @@ declare namespace Cypress {
|
||||
cmdKey: boolean
|
||||
}
|
||||
|
||||
interface PEMCert {
|
||||
/**
|
||||
* Path to the certificate file, relative to project root.
|
||||
*/
|
||||
cert: string
|
||||
/**
|
||||
* Path to the private key file, relative to project root.
|
||||
*/
|
||||
key: string
|
||||
/**
|
||||
* Path to a text file containing the passphrase, relative to project root.
|
||||
*/
|
||||
passphrase?: string
|
||||
}
|
||||
|
||||
interface PFXCert {
|
||||
/**
|
||||
* Path to the certificate container, relative to project root.
|
||||
*/
|
||||
pfx: string
|
||||
/**
|
||||
* Path to a text file containing the passphrase, relative to project root.
|
||||
*/
|
||||
passphrase?: string
|
||||
}
|
||||
|
||||
interface ClientCertificate {
|
||||
/**
|
||||
* URL to match requests against. Wildcards following [minimatch](https://github.com/isaacs/minimatch) rules are supported.
|
||||
*/
|
||||
url: string
|
||||
/**
|
||||
* Paths to one or more CA files to validate certs against, relative to project root.
|
||||
*/
|
||||
ca?: string[]
|
||||
/**
|
||||
* A PEM format certificate/private key pair or PFX certificate container
|
||||
*/
|
||||
certs: PEMCert[] | PFXCert[]
|
||||
}
|
||||
|
||||
interface ResolvedConfigOptions {
|
||||
/**
|
||||
* Url used as prefix for [cy.visit()](https://on.cypress.io/visit) or [cy.request()](https://on.cypress.io/request) command’s url
|
||||
@@ -2750,6 +2804,11 @@ declare namespace Cypress {
|
||||
* @default {}
|
||||
*/
|
||||
e2e: Omit<ResolvedConfigOptions, TestingType>
|
||||
|
||||
/**
|
||||
* An array of objects defining the certificates
|
||||
*/
|
||||
clientCertificates: ClientCertificate[]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2810,19 +2869,15 @@ declare namespace Cypress {
|
||||
projectName: string
|
||||
projectRoot: string
|
||||
proxyUrl: string
|
||||
remote: RemoteState
|
||||
report: boolean
|
||||
reporterRoute: string
|
||||
reporterUrl: string
|
||||
socketId: null | string
|
||||
socketIoCookie: string
|
||||
socketIoRoute: string
|
||||
spec: {
|
||||
absolute: string
|
||||
name: string
|
||||
relative: string
|
||||
specFilter: null | string
|
||||
specType: 'integration' | 'component'
|
||||
}
|
||||
spec: Cypress['spec'] | null
|
||||
specs: Array<Cypress['spec']>
|
||||
xhrRoute: string
|
||||
xhrUrl: string
|
||||
}
|
||||
@@ -3173,6 +3228,18 @@ declare namespace Cypress {
|
||||
eventConstructor: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to change the default behavior of .url()
|
||||
*/
|
||||
interface UrlOptions extends Loggable, Timeoutable {
|
||||
/**
|
||||
* Whether the url is decoded
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
decode: boolean
|
||||
}
|
||||
|
||||
/** Options to change the default behavior of .writeFile */
|
||||
interface WriteFileOptions extends Loggable {
|
||||
flag: string
|
||||
@@ -5263,7 +5330,7 @@ declare namespace Cypress {
|
||||
tag?: string
|
||||
}
|
||||
|
||||
interface DevServerOptions {
|
||||
interface DevServerConfig {
|
||||
specs: Spec[]
|
||||
config: ResolvedConfigOptions & RuntimeConfigOptions
|
||||
devServerEvents: NodeJS.EventEmitter
|
||||
@@ -5282,7 +5349,7 @@ declare namespace Cypress {
|
||||
(action: 'before:spec', fn: (spec: Spec) => void | Promise<void>): void
|
||||
(action: 'before:browser:launch', fn: (browser: Browser, browserLaunchOptions: BrowserLaunchOptions) => void | BrowserLaunchOptions | Promise<BrowserLaunchOptions>): void
|
||||
(action: 'file:preprocessor', fn: (file: FileObject) => string | Promise<string>): void
|
||||
(action: 'dev-server:start', fn: (file: DevServerOptions) => Promise<ResolvedDevServerConfig>): void
|
||||
(action: 'dev-server:start', fn: (file: DevServerConfig) => Promise<ResolvedDevServerConfig>): void
|
||||
(action: 'task', tasks: Tasks): void
|
||||
}
|
||||
|
||||
|
||||
@@ -497,6 +497,11 @@ namespace CypressLocationTests {
|
||||
cy.location('pathname') // $ExpectType Chainable<string>
|
||||
}
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/17399
|
||||
namespace CypressUrlTests {
|
||||
cy.url({decode: true}).should('contain', '사랑')
|
||||
}
|
||||
|
||||
namespace CypressBrowserTests {
|
||||
Cypress.isBrowser('chrome')// $ExpectType boolean
|
||||
Cypress.isBrowser('firefox')// $ExpectType boolean
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"name": "@cypress/angular",
|
||||
"version": "0.0.0-development",
|
||||
"description": "Test Angular components using Cypress",
|
||||
"private": true,
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
@@ -62,7 +63,7 @@
|
||||
"tslib": "^2.2.0",
|
||||
"tslint": "5.20.1",
|
||||
"typescript": "4.2.4",
|
||||
"webpack-dev-server": "3.11.2",
|
||||
"webpack-dev-server": "4.0.0",
|
||||
"zone.js": "0.11.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -84,5 +85,12 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/cypress-io/cypress.git"
|
||||
},
|
||||
"homepage": "https://on.cypress.io/component-testing"
|
||||
}
|
||||
"homepage": "https://on.cypress.io/component-testing",
|
||||
"author": "Gleb Bahmutov <gleb.bahmutov@gmail.com>",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Jean-Michel Leclercq",
|
||||
"social": "@LeJeanbono"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# [@cypress/schematic-v1.5.1](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.5.0...@cypress/schematic-v1.5.1) (2021-09-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cypress/schematic:** add edge to list of allowed browsers ([#17637](https://github.com/cypress-io/cypress/issues/17637)) ([49de24f](https://github.com/cypress-io/cypress/commit/49de24f6178e0ef7bfd654c3efc0bfa8008e962e))
|
||||
|
||||
# [@cypress/schematic-v1.5.0](https://github.com/cypress-io/cypress/compare/@cypress/schematic-v1.4.2...@cypress/schematic-v1.5.0) (2021-07-20)
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { JsonObject } from '@angular-devkit/core'
|
||||
export interface CypressBuilderOptions extends JsonObject {
|
||||
baseUrl: string
|
||||
configFile: string | false
|
||||
browser: 'electron' | 'chrome' | 'chromium' | 'canary' | 'firefox' | string
|
||||
browser: 'electron' | 'chrome' | 'chromium' | 'canary' | 'firefox' | 'edge' | string
|
||||
devServerTarget: string
|
||||
env: Record<string, string>
|
||||
quiet: boolean
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
"chrome",
|
||||
"chromium",
|
||||
"canary",
|
||||
"firefox"
|
||||
"firefox",
|
||||
"edge"
|
||||
]
|
||||
},
|
||||
"devServerTarget": {
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# [@cypress/react-v5.10.0](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.9.4...@cypress/react-v5.10.0) (2021-09-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow usage of @react/plugins with cypress.config.js ([#17738](https://github.com/cypress-io/cypress/issues/17738)) ([da4b1e0](https://github.com/cypress-io/cypress/commit/da4b1e06ce33945aabddda0e6e175dc0e1b488a5))
|
||||
|
||||
# [@cypress/react-v5.9.4](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.9.3...@cypress/react-v5.9.4) (2021-08-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not throw when alt path is found in next ([#17658](https://github.com/cypress-io/cypress/issues/17658)) ([ee7e203](https://github.com/cypress-io/cypress/commit/ee7e203fa059efeac45c7a18526e563643e76d77)), closes [#17476](https://github.com/cypress-io/cypress/issues/17476)
|
||||
|
||||
# [@cypress/react-v5.9.3](https://github.com/cypress-io/cypress/compare/@cypress/react-v5.9.2...@cypress/react-v5.9.3) (2021-08-03)
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts')
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
|
||||
/**
|
||||
* @type Cypress.PluginConfig
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
|
||||
@@ -7,10 +7,10 @@ Use the plugin:
|
||||
|
||||
// import your craco.config.js
|
||||
const cracoConfig = require('../../craco.config.js')
|
||||
const injectDevServer = require('@cypress/react/plugins/craco')
|
||||
const devServer = require('@cypress/react/plugins/craco')
|
||||
|
||||
module.exports = (on, config) => {
|
||||
injectDevServer(on, config, cracoConfig)
|
||||
devServer(on, config, cracoConfig)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
const cracoConfig = require('../../craco.config.js')
|
||||
const injectDevServer = require('@cypress/react/plugins/craco')
|
||||
// @ts-check
|
||||
|
||||
const cracoConfig = require('../../craco.config.js')
|
||||
const devServer = require('@cypress/react/plugins/craco')
|
||||
|
||||
/**
|
||||
* @type Cypress.PluginConfig
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
injectDevServer(on, config, cracoConfig)
|
||||
devServer(on, config, cracoConfig)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -38,10 +38,10 @@ Here we are adding some Component Testing specific options, hence the `"componen
|
||||
The last thing we need to is tell Cypress to use `@cypress/webpack-dev-server` for component tests. Plugins are explained in detail in the [Cypress documentation](https://docs.cypress.io/guides/tooling/plugins-guide#Installing-plugins). By default plugins are loaded from `cypress/plugins/index.js`. Create that file and add:
|
||||
|
||||
```js
|
||||
const injectDevServer = require("@cypress/react/plugins/react-scripts")
|
||||
const devServer = require("@cypress/react/plugins/react-scripts")
|
||||
|
||||
module.exports = (on, config) => {
|
||||
injectDevServer(on, config)
|
||||
devServer(on, config)
|
||||
return config
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// @ts-check
|
||||
|
||||
const findReactScriptsWebpackConfig = require('@cypress/react/plugins/react-scripts/findReactScriptsWebpackConfig')
|
||||
const { startDevServer } = require('@cypress/webpack-dev-server')
|
||||
const _ = require('lodash')
|
||||
|
||||
/**
|
||||
* @type Cypress.PluginConfig
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
const map = _.map([4, 8], (n) => n * 2)
|
||||
|
||||
@@ -10,9 +15,9 @@ module.exports = (on, config) => {
|
||||
const webpackConfig = findReactScriptsWebpackConfig(config)
|
||||
|
||||
const rules = webpackConfig.module.rules.find((rule) => !!rule.oneOf).oneOf
|
||||
const babelRule = rules.find((rule) => /babel-loader/.test(rule.loader))
|
||||
const babelRule = rules.find((rule) => typeof rule.loader === 'string' && /babel-loader/.test(rule.loader))
|
||||
|
||||
babelRule.options.plugins.push(require.resolve('babel-plugin-istanbul'))
|
||||
typeof babelRule.options !== 'string' && babelRule.options.plugins.push(require.resolve('babel-plugin-istanbul'))
|
||||
|
||||
on('dev-server:start', (options) => {
|
||||
return startDevServer({ options, webpackConfig })
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const injectNextDevServer = require('@cypress/react/plugins/next')
|
||||
const devServer = require('@cypress/react/plugins/next')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
injectNextDevServer(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
In order to reuse next's webpack configuration and all the custom configuration defined in `next.config.js` connect special plugin in [plugin file](./cypress/plugins/index.js)
|
||||
|
||||
```js
|
||||
const preprocessor = require('@cypress/react/plugins/next')
|
||||
const devServer = require('@cypress/react/plugins/next')
|
||||
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const injectNextDevServer = require('@cypress/react/plugins/next')
|
||||
const devServer = require('@cypress/react/plugins/next')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
injectNextDevServer(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts')
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
const injectDevServer = require('@cypress/react/plugins/react-scripts')
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
injectDevServer(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts')
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
// load Webpack file preprocessor that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const injectWebpackDevServer = require('@cypress/react/plugins/load-webpack')
|
||||
// @ts-check
|
||||
|
||||
// load Webpack file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const devServer = require('@cypress/react/plugins/load-webpack')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
injectWebpackDevServer(on, config, {
|
||||
devServer(on, config, {
|
||||
webpackFilename: 'webpack.config.js',
|
||||
})
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts')
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
const { initPlugin: initSnapshots } = require('cypress-plugin-snapshots/plugin')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
// initialize the snapshots plugin following
|
||||
// https://github.com/meinaart/cypress-plugin-snapshots
|
||||
initSnapshots(on, config)
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const injectReactScriptsDevServer = require('@cypress/react/plugins/react-scripts')
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
injectReactScriptsDevServer(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
|
||||
@@ -31,14 +31,14 @@ npm test
|
||||
|
||||
## Specs
|
||||
|
||||
See spec files [src/\*.spec.js](src). The specs are bundled using [babel.config.js](babel.config.js) settings via [cypress/plugins/index.js](cypress/plugins/index.js) file that includes file preprocessor.
|
||||
See spec files [src/\*.spec.js](src). The specs are bundled using [babel.config.js](babel.config.js) settings via [cypress/plugins/index.js](cypress/plugins/index.js) file that includes file devServer.
|
||||
|
||||
```js
|
||||
// let's bundle spec files and the components they include using
|
||||
// the same bundling settings as the project by loading .babelrc
|
||||
const preprocessor = require('@cypress/react/plugins/babelrc')
|
||||
const devServer = require('@cypress/react/plugins/babel')
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
return config
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
// @ts-check
|
||||
|
||||
// let's bundle spec files and the components they include using
|
||||
// the same bundling settings as the project by loading .babelrc
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const injectWebpackWithBabelDevServer = require('@cypress/react/plugins/babel')
|
||||
const devServer = require('@cypress/react/plugins/babel')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
injectWebpackWithBabelDevServer(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
|
||||
@@ -31,14 +31,14 @@ npm test
|
||||
|
||||
## Specs
|
||||
|
||||
See spec files [src/\*.spec.js](src). The specs are bundled using [.babelrc](.babelrc) settings via [cypress/plugins/index.js](cypress/plugins/index.js) file that includes file preprocessor
|
||||
See spec files [src/\*.spec.js](src). The specs are bundled using [.babelrc](.babelrc) settings via [cypress/plugins/index.js](cypress/plugins/index.js) file that includes file devServer
|
||||
|
||||
```js
|
||||
// let's bundle spec files and the components they include using
|
||||
// the same bundling settings as the project by loading .babelrc
|
||||
const preprocessor = require('@cypress/react/plugins/babelrc')
|
||||
const devServer = require('@cypress/react/plugins/babel')
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
return config
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
// @ts-check
|
||||
|
||||
// let's bundle spec files and the components they include using
|
||||
// the same bundling settings as the project by loading .babelrc
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const injectWebpackWithBabelDevServer = require('@cypress/react/plugins/babel')
|
||||
const devServer = require('@cypress/react/plugins/babel')
|
||||
|
||||
/**
|
||||
* @type Cypress.PluginConfig
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
injectWebpackWithBabelDevServer(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts')
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
addMatchImageSnapshotPlugin(on, config)
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
return config
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts')
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
return config
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
require('@applitools/eyes-cypress')(module)
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/cypress-react-unit-test#install
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts')
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
// @ts-ignore
|
||||
const happoTask = require('happo-cypress/task')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
on('task', happoTask)
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
// load file preprocessor that comes with this plugin
|
||||
// https://github.com/bahmutov/@cypress/react#install
|
||||
const preprocessor = require('@cypress/react/plugins/react-scripts')
|
||||
// @ts-check
|
||||
|
||||
// load file devServer that comes with this plugin
|
||||
// https://github.com/bahmutov/@cypress/react#install
|
||||
const devServer = require('@cypress/react/plugins/react-scripts')
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
preprocessor(on, config)
|
||||
devServer(on, config)
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
require('@cypress/react/plugins/load-webpack')(on, config, {
|
||||
// from the root of the project (folder with cypress.json file)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# example: webpack-options
|
||||
|
||||
> The Webpack preprocessor in [cypress/plugins/index.js](cypress/plugins/index.js) adds the Babel React preset to the list of default Webpack plugins. This allows Cypress to transpile JSX code in [cypress/component/Test.cy-spec.js](cypress/component/Test.cy-spec.js) file.
|
||||
> The Webpack devServer in [cypress/plugins/index.js](cypress/plugins/index.js) adds the Babel React preset to the list of default Webpack plugins. This allows Cypress to transpile JSX code in [cypress/component/Test.cy-spec.js](cypress/component/Test.cy-spec.js) file.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -3,8 +3,11 @@ const path = require('path')
|
||||
const { startDevServer } = require('@cypress/webpack-dev-server')
|
||||
const babelConfig = require('../../babel.config')
|
||||
|
||||
// Cypress Webpack preprocessor includes Babel env preset,
|
||||
// but to transpile JSX code we need to add Babel React preset
|
||||
/**
|
||||
* Cypress Webpack devServer includes Babel env preset,
|
||||
* but to transpile JSX code we need to add Babel React preset
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
/** @type import("webpack").Configuration */
|
||||
const webpackConfig = {
|
||||
|
||||
+29
-3
@@ -1,19 +1,22 @@
|
||||
{
|
||||
"name": "@cypress/react",
|
||||
"version": "0.0.0-development",
|
||||
"description": "Unit test React components using Cypress",
|
||||
"description": "Test React components using Cypress",
|
||||
"main": "dist/cypress-react.cjs.js",
|
||||
"scripts": {
|
||||
"build": "rimraf dist && yarn rollup -c rollup.config.js",
|
||||
"build": "rimraf dist && yarn transpile-plugins && yarn rollup -c rollup.config.js",
|
||||
"build-prod": "yarn build",
|
||||
"cy:open": "node ../../scripts/cypress.js open-ct",
|
||||
"cy:open:debug": "node --inspect-brk ../../scripts/start.js --component-testing --run-project ${PWD}",
|
||||
"cy:run": "node ../../scripts/cypress.js run-ct",
|
||||
"cy:run:debug": "node --inspect-brk ../../scripts/start.js --component-testing --run-project ${PWD}",
|
||||
"pretest": "yarn transpile",
|
||||
"test": "yarn cy:run",
|
||||
"test": "yarn test-unit && yarn test-component",
|
||||
"test-unit": "mocha -r @packages/ts/register test/**/*.spec.*",
|
||||
"test-component": "yarn cy:run",
|
||||
"test-ci": "node ../../scripts/run-ct-examples.js --examplesList=./examples.env",
|
||||
"transpile": "tsc",
|
||||
"transpile-plugins": "yarn transpile --project ./plugins",
|
||||
"watch": "yarn build --watch --watch.exclude ./dist/**/*"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -118,6 +121,7 @@
|
||||
"url": "https://github.com/cypress-io/cypress.git"
|
||||
},
|
||||
"homepage": "https://github.com/cypress-io/cypress/blob/master/npm/react/#readme",
|
||||
"author": "Gleb Bahmutov <gleb.bahmutov@gmail.com>",
|
||||
"bugs": "https://github.com/cypress-io/cypress/issues/new?assignees=&labels=npm%3A%20%40cypress%2Freact&template=1-bug-report.md&title=",
|
||||
"keywords": [
|
||||
"react",
|
||||
@@ -126,6 +130,28 @@
|
||||
"test",
|
||||
"testing"
|
||||
],
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Dmitriy Kovalenko",
|
||||
"social": "@dmtrKovalenko"
|
||||
},
|
||||
{
|
||||
"name": "Brian Mann",
|
||||
"social": "@brian-mann"
|
||||
},
|
||||
{
|
||||
"name": "Barthélémy Ledoux",
|
||||
"social": "@elevatebart"
|
||||
},
|
||||
{
|
||||
"name": "Lachlan Miller",
|
||||
"social": "@lmiller1990"
|
||||
},
|
||||
{
|
||||
"name": "Jessica Sachs",
|
||||
"social": "@JessicaSachs"
|
||||
}
|
||||
],
|
||||
"unpkg": "dist/cypress-react.browser.js",
|
||||
"module": "dist/cypress-react.esm-bundler.js",
|
||||
"peerDependenciesMeta": {
|
||||
|
||||
@@ -43,7 +43,7 @@ const webpackConfigLoadsBabel = {
|
||||
* return config
|
||||
* }
|
||||
*/
|
||||
module.exports = (on, config, { setWebpackConfig } = { setWebpackConfig: null }) => {
|
||||
module.exports = (config, { setWebpackConfig } = { setWebpackConfig: null }) => {
|
||||
debug('env object %o', config.env)
|
||||
|
||||
debug('initial environments %o', {
|
||||
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
import { Configuration } from "webpack";
|
||||
|
||||
declare namespace legacyDevServer {
|
||||
interface CypressBabelDevServerConfig {
|
||||
/**
|
||||
* Allows to adjust the webpackConfig that our dev-server will use
|
||||
* @param config configuration generated by the plugin
|
||||
* @returns modified final configuration
|
||||
*/
|
||||
setWebpackConfig?(config:Configuration): Configuration
|
||||
}
|
||||
|
||||
/**
|
||||
* Type helper to make writing `CypressBabelDevServerConfig` easier
|
||||
*/
|
||||
function defineDevServerConfig(devServerConfig: CypressBabelDevServerConfig): CypressBabelDevServerConfig
|
||||
|
||||
/**
|
||||
* Sets up a webpack dev server with the proper configuration for babel transpilation
|
||||
* @param cypressDevServerConfig comes from the `devServer()` function first argument
|
||||
* @param devServerConfig additional config object (create an empty object to see how to use it)
|
||||
* @returns the resolved dev server object that cypress can use to start testing
|
||||
*/
|
||||
function devServer(cypressDevServerConfig: Cypress.DevServerConfig, devServerConfig?: CypressBabelDevServerConfig): Cypress.ResolvedDevServerConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a webpack dev server with the proper configuration for babel transpilation
|
||||
* @param on comes from the argument of the `pluginsFile` function
|
||||
* @param config comes from the argument of the `pluginsFile` function
|
||||
* @param devServerConfig additional config object (create an empty object it to see how to use it)
|
||||
*/
|
||||
declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: legacyDevServer.CypressBabelDevServerConfig): void
|
||||
|
||||
export = legacyDevServer;
|
||||
@@ -1,12 +1,24 @@
|
||||
const getBabelWebpackConfig = require('./getBabelWebpackConfig')
|
||||
const { startDevServer } = require('@cypress/webpack-dev-server')
|
||||
const getBabelWebpackConfig = require('./getBabelWebpackConfig')
|
||||
const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server')
|
||||
|
||||
module.exports = (on, config, moduleOptions) => {
|
||||
on('dev-server:start', async (options) => {
|
||||
return startDevServer({ options, webpackConfig: getBabelWebpackConfig(on, config, moduleOptions) })
|
||||
function devServer (cypressDevServerConfig, devServerConfig) {
|
||||
return startDevServer({
|
||||
options: cypressDevServerConfig,
|
||||
webpackConfig: getBabelWebpackConfig(cypressDevServerConfig.config, devServerConfig),
|
||||
})
|
||||
}
|
||||
|
||||
// Legacy signature
|
||||
module.exports = getLegacyDevServer(devServer, (config) => {
|
||||
config.env.reactDevtools = true
|
||||
|
||||
return config
|
||||
})
|
||||
|
||||
// New signature
|
||||
module.exports.devServer = devServer
|
||||
|
||||
module.exports.defineDevServerConfig = function (devServerConfig) {
|
||||
return devServerConfig
|
||||
}
|
||||
|
||||
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
declare namespace legacyDevServer {
|
||||
interface CypressCracoDevServerConfig {
|
||||
/**
|
||||
* The object exported of your craco.config.js file
|
||||
*/
|
||||
cracoConfig: any
|
||||
}
|
||||
|
||||
/**
|
||||
* Type helper to make writing `CypressCracoDevServerConfig` easier
|
||||
*/
|
||||
function defineDevServerConfig(devServerConfig: CypressCracoDevServerConfig): CypressCracoDevServerConfig
|
||||
|
||||
/**
|
||||
* Sets up a dev server for using Cypress compoennt testing with CRACO (https://github.com/gsoft-inc/craco)
|
||||
* @param cypressDevServerConfig comes from the `devServer()` function first argument
|
||||
* @param devServerConfig additional config object (create an empty object to see how to use it)
|
||||
* @returns the resolved dev server object that cypress can use to start testing
|
||||
*/
|
||||
function devServer(cypressDevServerConfig: Cypress.DevServerConfig, devServerConfig: CypressCracoDevServerConfig): Cypress.ResolvedDevServerConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a dev server for using Cypress compoennt testing with CRACO (https://github.com/gsoft-inc/craco)
|
||||
* @param on comes from the argument of the `pluginsFile` function
|
||||
* @param config comes from the argument of the `pluginsFile` function
|
||||
* @param cracoConfig the object exported of your craco.config.js file
|
||||
*/
|
||||
declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, cracoConfig: any): void
|
||||
|
||||
export = legacyDevServer;
|
||||
@@ -1,17 +1,27 @@
|
||||
const { startDevServer } = require('@cypress/webpack-dev-server')
|
||||
const { createWebpackDevConfig } = require('@craco/craco')
|
||||
const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server')
|
||||
|
||||
module.exports = (on, config, cracoConfig) => {
|
||||
if (!cracoConfig) {
|
||||
throw Error('craco config is required.')
|
||||
}
|
||||
|
||||
on('dev-server:start', (options) => {
|
||||
return startDevServer({
|
||||
options,
|
||||
webpackConfig: createWebpackDevConfig(cracoConfig),
|
||||
})
|
||||
function devServer (cypressDevServerConfig, cracoConfig) {
|
||||
return startDevServer({
|
||||
options: cypressDevServerConfig,
|
||||
webpackConfig: createWebpackDevConfig(cracoConfig),
|
||||
})
|
||||
}
|
||||
|
||||
// Legacy signature
|
||||
module.exports = getLegacyDevServer(devServer, (config) => {
|
||||
config.env.reactDevtools = true
|
||||
|
||||
return config
|
||||
})
|
||||
|
||||
// New signature
|
||||
// - Note that this also includes a change to the second argument!
|
||||
module.exports.devServer = (cypressDevServerConfig, { cracoConfig }) => {
|
||||
return devServer(cypressDevServerConfig, cracoConfig)
|
||||
}
|
||||
|
||||
module.exports.defineDevServerConfig = function (devServerConfig) {
|
||||
return devServerConfig
|
||||
}
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
declare namespace legacyDevServer {
|
||||
interface CypressWebpackDevServerConfig {
|
||||
/**
|
||||
* Location of the weppack.config Cypress should use
|
||||
*/
|
||||
webpackFilename?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Type helper to make writing `CypressWebpackDevServerConfig` easier
|
||||
*/
|
||||
function defineDevServerConfig(devServerConfig: CypressWebpackDevServerConfig): CypressWebpackDevServerConfig
|
||||
|
||||
/**
|
||||
* Sets up a webpack dev server with the proper configuration for babel transpilation
|
||||
* @param cypressDevServerConfig comes from the `devServer()` function first argument
|
||||
* @param devServerConfig additional config object (create an empty object to see how to use it)
|
||||
* @returns the resolved dev server object that cypress can use to start testing
|
||||
*/
|
||||
function devServer(cypressDevServerConfig: Cypress.DevServerConfig, devServerConfig?: CypressWebpackDevServerConfig): Cypress.ResolvedDevServerConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a webpack dev server with the proper configuration for babel transpilation
|
||||
* @param on comes from the argument of the `pluginsFile` function
|
||||
* @param config comes from the argument of the `pluginsFile` function
|
||||
* @param devServerConfig additional config object (create an empty object to see how to use it)
|
||||
*/
|
||||
declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: legacyDevServer.CypressWebpackDevServerConfig): void
|
||||
|
||||
export = legacyDevServer;
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-check
|
||||
const path = require('path')
|
||||
const { startDevServer } = require('@cypress/webpack-dev-server')
|
||||
const tryLoadWebpackConfig = require('../utils/tryLoadWebpackConfig')
|
||||
const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server')
|
||||
|
||||
/** @type {(config: Cypress.PluginConfigOptions, path: string) => string} */
|
||||
function normalizeWebpackPath (config, webpackConfigPath) {
|
||||
@@ -9,27 +9,35 @@ function normalizeWebpackPath (config, webpackConfigPath) {
|
||||
? webpackConfigPath
|
||||
: path.resolve(config.projectRoot, webpackConfigPath)
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects dev-server based on the webpack config file.
|
||||
*
|
||||
* **Important:** `webpackFilename` path is relative to the project root (cypress.json location)
|
||||
* @type {(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, options: { webpackFilename: string }) => Cypress.PluginConfigOptions}
|
||||
*/
|
||||
function injectWebpackDevServer (on, config, { webpackFilename }) {
|
||||
const webpackConfig = tryLoadWebpackConfig(normalizeWebpackPath(config, webpackFilename))
|
||||
function devServer (cypressDevServerConfig, { webpackFilename }) {
|
||||
const webpackConfig = tryLoadWebpackConfig(normalizeWebpackPath(cypressDevServerConfig.config, webpackFilename))
|
||||
|
||||
if (!webpackConfig) {
|
||||
throw new Error(`Can not load webpack config from path ${webpackFilename}.`)
|
||||
}
|
||||
|
||||
on('dev-server:start', async (options) => {
|
||||
return startDevServer({ options, webpackConfig })
|
||||
return startDevServer({
|
||||
options: cypressDevServerConfig,
|
||||
webpackConfig,
|
||||
})
|
||||
}
|
||||
|
||||
// Legacy signature
|
||||
module.exports = getLegacyDevServer(devServer, (config) => {
|
||||
config.env.reactDevtools = true
|
||||
|
||||
return config
|
||||
}
|
||||
})
|
||||
|
||||
module.exports = injectWebpackDevServer
|
||||
// New signature
|
||||
module.exports.devServer = devServer
|
||||
|
||||
module.exports.defineDevServerConfig = function (devServerConfig) {
|
||||
return devServerConfig
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/// <reference types="next" />
|
||||
const debug = require('debug')('@cypress/react')
|
||||
const getNextJsBaseWebpackConfig = require('next/dist/build/webpack-config').default
|
||||
const { findPagesDir } = require('../../dist/next/findPagesDir')
|
||||
|
||||
async function getNextWebpackConfig (config) {
|
||||
let loadConfig
|
||||
@@ -14,9 +15,9 @@ async function getNextWebpackConfig (config) {
|
||||
// is not in the next-server folder anymore.
|
||||
// @ts-ignore
|
||||
loadConfig = require('next/dist/server/config').default
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
|
||||
throw e
|
||||
}
|
||||
const nextConfig = await loadConfig('development', config.projectRoot)
|
||||
const nextWebpackConfig = await getNextJsBaseWebpackConfig(
|
||||
@@ -26,7 +27,7 @@ async function getNextWebpackConfig (config) {
|
||||
config: nextConfig,
|
||||
dev: true,
|
||||
isServer: false,
|
||||
pagesDir: config.projectRoot,
|
||||
pagesDir: findPagesDir(config.projectRoot),
|
||||
entrypoints: {},
|
||||
rewrites: { fallback: [], afterFiles: [], beforeFiles: [] },
|
||||
},
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
const existsSync = (file: string) => {
|
||||
try {
|
||||
fs.accessSync(file, fs.constants.F_OK)
|
||||
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Next allows the `pages` directory to be located at either
|
||||
* `${projectRoot}/pages` or `${projectRoot}/src/pages`.
|
||||
* If neither is found, return projectRoot
|
||||
*/
|
||||
export function findPagesDir (projectRoot: string) {
|
||||
// prioritize ./pages over ./src/pages
|
||||
let pagesDir = path.join(projectRoot, 'pages')
|
||||
|
||||
if (existsSync(pagesDir)) {
|
||||
return pagesDir
|
||||
}
|
||||
|
||||
pagesDir = path.join(projectRoot, 'src/pages')
|
||||
if (existsSync(pagesDir)) {
|
||||
return pagesDir
|
||||
}
|
||||
|
||||
return projectRoot
|
||||
}
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Sets up a Cypress component testing environment for your NextJs application
|
||||
* @param on comes from the argument of the `pluginsFile` function
|
||||
* @param config comes from the argument of the `pluginsFile` function
|
||||
*/
|
||||
declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions): void
|
||||
|
||||
declare namespace legacyDevServer {
|
||||
/**
|
||||
* Sets up a Cypress component testing environment for your NextJs application
|
||||
* @param cypressDevServerConfig comes from the `devServer()` function first argument
|
||||
* @returns the resolved dev server object that cypress can use to start testing
|
||||
*/
|
||||
function devServer(cypressDevServerConfig: Cypress.DevServerConfig): Cypress.ResolvedDevServerConfig
|
||||
}
|
||||
|
||||
export = legacyDevServer;
|
||||
@@ -1,21 +1,26 @@
|
||||
const findNextWebpackConfig = require('./findNextWebpackConfig')
|
||||
const path = require('path')
|
||||
const findNextWebpackConfig = require('./findNextWebpackConfig')
|
||||
const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server')
|
||||
|
||||
module.exports = (on, config) => {
|
||||
on('dev-server:start', async (options) => {
|
||||
const webpackConfig = await findNextWebpackConfig(config)
|
||||
async function devServer (cypressDevServerConfig) {
|
||||
const webpackConfig = await findNextWebpackConfig(cypressDevServerConfig.config)
|
||||
|
||||
// require('webpack') now points to nextjs bundled version
|
||||
const { startDevServer } = require('@cypress/webpack-dev-server')
|
||||
// require('webpack') now points to nextjs bundled version
|
||||
const { startDevServer } = require('@cypress/webpack-dev-server')
|
||||
|
||||
return startDevServer({
|
||||
options,
|
||||
webpackConfig,
|
||||
template: path.resolve(__dirname, 'index-template.html'),
|
||||
})
|
||||
return startDevServer({
|
||||
options: cypressDevServerConfig,
|
||||
webpackConfig,
|
||||
template: path.resolve(__dirname, 'index-template.html'),
|
||||
})
|
||||
}
|
||||
|
||||
// Legacy signature
|
||||
module.exports = getLegacyDevServer(devServer, (config) => {
|
||||
config.env.reactDevtools = true
|
||||
|
||||
return config
|
||||
}
|
||||
})
|
||||
|
||||
// New signature
|
||||
module.exports.devServer = devServer
|
||||
|
||||
@@ -20,7 +20,7 @@ module.exports = function findReactScriptsWebpackConfig (config, {
|
||||
}
|
||||
|
||||
// because for react-scripts user doesn't have direct access to webpack webpackConfig
|
||||
// we must implicitly inject everything required to run tests
|
||||
// we must implicitly setup everything required to run tests
|
||||
addCypressToWebpackEslintRulesInPlace(webpackConfig)
|
||||
|
||||
getTranspileFolders(config).forEach((cypressFolder) => {
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
declare namespace legacyDevServer {
|
||||
interface CypressCRADevServerConfig {
|
||||
/**
|
||||
* Location of the weppack.config Cypress should use
|
||||
*/
|
||||
webpackConfigPath?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Type helper to make writing `CypressCRADevServerConfig` easier
|
||||
*/
|
||||
function defineDevServerConfig(devServerConfig: CypressCRADevServerConfig): CypressCRADevServerConfig
|
||||
|
||||
/**
|
||||
* Sets up a Cypress component testing environment for your Create React App environment
|
||||
* @param cypressDevServerConfig comes from the `devServer()` function first argument
|
||||
* @param devServerConfig additional config object (create an empty object to see how to use it)
|
||||
* @returns the resolved dev server object that cypress can use to start testing
|
||||
*/
|
||||
function devServer(cypressDevServerConfig: Cypress.DevServerConfig, devServerConfig?: CypressCRADevServerConfig): Cypress.ResolvedDevServerConfig
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a Cypress component testing environment for your Create React App environment
|
||||
* @param on comes from the argument of the `pluginsFile` function
|
||||
* @param config comes from the argument of the `pluginsFile` function
|
||||
* @param devServerConfig additional config object (create an empty object to see how to use it)
|
||||
*/
|
||||
declare function legacyDevServer(on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions, devServerConfig?: legacyDevServer.CypressCRADevServerConfig): void
|
||||
|
||||
export = legacyDevServer;
|
||||
+21
-17
@@ -1,26 +1,30 @@
|
||||
const { startDevServer } = require('@cypress/webpack-dev-server')
|
||||
const findReactScriptsWebpackConfig = require('./findReactScriptsWebpackConfig')
|
||||
const { getLegacyDevServer } = require('../utils/legacy-setup-dev-server')
|
||||
|
||||
module.exports = (
|
||||
on,
|
||||
config, {
|
||||
webpackConfigPath,
|
||||
} = {
|
||||
webpackConfigPath: 'react-scripts/config/webpack.config',
|
||||
},
|
||||
) => {
|
||||
on('dev-server:start', async (options) => {
|
||||
return startDevServer({
|
||||
options,
|
||||
webpackConfig: findReactScriptsWebpackConfig(config, {
|
||||
webpackConfigPath,
|
||||
}),
|
||||
})
|
||||
function devServer (cypressDevServerConfig, {
|
||||
webpackConfigPath,
|
||||
} = {
|
||||
webpackConfigPath: 'react-scripts/config/webpack.config',
|
||||
}) {
|
||||
return startDevServer({
|
||||
options: cypressDevServerConfig,
|
||||
webpackConfig: findReactScriptsWebpackConfig(cypressDevServerConfig.config, {
|
||||
webpackConfigPath,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
// Legacy signature
|
||||
module.exports = getLegacyDevServer(devServer, (config) => {
|
||||
config.env.reactDevtools = true
|
||||
|
||||
// IMPORTANT to return the config object
|
||||
// with the any changed environment variables
|
||||
return config
|
||||
})
|
||||
|
||||
// New signature
|
||||
module.exports.devServer = devServer
|
||||
|
||||
module.exports.defineDevServerConfig = function (devServerConfig) {
|
||||
return devServerConfig
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"types": [
|
||||
"cypress",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": ["./**/*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
function getLegacyDevServer (devServer, postProcessConfig = (config) => config) {
|
||||
return (on, config, ...args) => {
|
||||
on('dev-server:start', (cypressDevServerConfig) => {
|
||||
return devServer(cypressDevServerConfig, ...args)
|
||||
})
|
||||
|
||||
return postProcessConfig(config)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { getLegacyDevServer }
|
||||
@@ -0,0 +1,19 @@
|
||||
import { expect } from 'chai'
|
||||
import * as path from 'path'
|
||||
import { findPagesDir } from '../../plugins/next/findPagesDir'
|
||||
|
||||
describe('Next.js findPagesDir', () => {
|
||||
it('should find the correct pagesDir', () => {
|
||||
const nextPluginFixturePath = path.join(__dirname, '../fixtures/next-plugin')
|
||||
|
||||
let projectRoot = nextPluginFixturePath
|
||||
|
||||
expect(findPagesDir(projectRoot)).to.equal(projectRoot)
|
||||
|
||||
projectRoot = path.join(nextPluginFixturePath, 'next-project-one')
|
||||
expect(findPagesDir(projectRoot)).to.equal(path.join(projectRoot, 'pages'))
|
||||
|
||||
projectRoot = path.join(nextPluginFixturePath, 'next-project-two')
|
||||
expect(findPagesDir(projectRoot)).to.equal(path.join(projectRoot, 'src/pages'))
|
||||
})
|
||||
})
|
||||
@@ -1,3 +1,33 @@
|
||||
# [@cypress/vite-dev-server-v2.1.0](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.0.8...@cypress/vite-dev-server-v2.1.0) (2021-09-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow usage of @react/plugins with cypress.config.js ([#17738](https://github.com/cypress-io/cypress/issues/17738)) ([da4b1e0](https://github.com/cypress-io/cypress/commit/da4b1e06ce33945aabddda0e6e175dc0e1b488a5))
|
||||
|
||||
# [@cypress/vite-dev-server-v2.0.8](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.0.7...@cypress/vite-dev-server-v2.0.8) (2021-08-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent vite from crashing where there are no support files or specs found ([#17624](https://github.com/cypress-io/cypress/issues/17624)) ([ae0ea87](https://github.com/cypress-io/cypress/commit/ae0ea87802168c524ee5cfe04d0aa59a46195a7d)), closes [#17373](https://github.com/cypress-io/cypress/issues/17373)
|
||||
* publish the types for vite-dev-server ([#17786](https://github.com/cypress-io/cypress/issues/17786)) ([a94ff69](https://github.com/cypress-io/cypress/commit/a94ff69d09564140ad0cc890771175396eb351cc)), closes [#17648](https://github.com/cypress-io/cypress/issues/17648)
|
||||
* repair re-run of vite-dev-server issues ([4139631](https://github.com/cypress-io/cypress/commit/4139631b159bac159bd6d2d4c020b5d8b3aa0fa7))
|
||||
|
||||
# [@cypress/vite-dev-server-v2.0.7](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.0.6...@cypress/vite-dev-server-v2.0.7) (2021-08-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **vite-dev-server:** chain update all specs when changing child ([#17693](https://github.com/cypress-io/cypress/issues/17693)) ([66e8896](https://github.com/cypress-io/cypress/commit/66e8896b66207e9ce2d1a5dd9f66f73fe58a1e7e)), closes [#17691](https://github.com/cypress-io/cypress/issues/17691)
|
||||
|
||||
# [@cypress/vite-dev-server-v2.0.6](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.0.5...@cypress/vite-dev-server-v2.0.6) (2021-08-10)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent vite from crashing where there are no support files or s… ([#17641](https://github.com/cypress-io/cypress/issues/17641)) ([1d2b053](https://github.com/cypress-io/cypress/commit/1d2b053322eb36935928122e4552563a7f98f35d)), closes [#17624](https://github.com/cypress-io/cypress/issues/17624) [#17373](https://github.com/cypress-io/cypress/issues/17373)
|
||||
|
||||
# [@cypress/vite-dev-server-v2.0.5](https://github.com/cypress-io/cypress/compare/@cypress/vite-dev-server-v2.0.4...@cypress/vite-dev-server-v2.0.5) (2021-08-04)
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import Hello from './Hello.vue'
|
||||
|
||||
describe('Hello', () => {
|
||||
it('shows error for short text', () => {
|
||||
cy.viewport(300, 200)
|
||||
cy.viewport(500, 800)
|
||||
mount(Hello)
|
||||
// use the component like a real user
|
||||
cy.findByRole('textbox').type('abc')
|
||||
|
||||
@@ -3,12 +3,16 @@
|
||||
<input v-model="username" />
|
||||
<div v-if="error" class="error">{{ error }}</div>
|
||||
<img src="./logo.png" />
|
||||
<Card/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Card from "../Card/Card.vue"
|
||||
|
||||
export default {
|
||||
name: "Hello",
|
||||
components: { Card },
|
||||
data() {
|
||||
return {
|
||||
username: "",
|
||||
|
||||
@@ -34,7 +34,8 @@
|
||||
"files": [
|
||||
"dist",
|
||||
"client",
|
||||
"index.html"
|
||||
"index.html",
|
||||
"index.d.ts"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
@@ -4,14 +4,7 @@ const debug = debugFn('cypress:vite-dev-server:vite')
|
||||
|
||||
export { StartDevServerOptions }
|
||||
|
||||
type DoneCallback = () => unknown
|
||||
|
||||
export interface ResolvedDevServerConfig {
|
||||
port: number
|
||||
close: (done?: DoneCallback) => void
|
||||
}
|
||||
|
||||
export async function startDevServer (startDevServerArgs: StartDevServerOptions): Promise<ResolvedDevServerConfig> {
|
||||
export async function startDevServer (startDevServerArgs: StartDevServerOptions): Promise<Cypress.ResolvedDevServerConfig> {
|
||||
const viteDevServer = await createDevServer(startDevServerArgs)
|
||||
|
||||
const app = await viteDevServer.listen()
|
||||
|
||||
@@ -34,8 +34,8 @@ interface Spec{
|
||||
|
||||
export const makeCypressPlugin = (
|
||||
projectRoot: string,
|
||||
supportFilePath: string,
|
||||
devServerEvents: EventEmitter,
|
||||
supportFilePath: string | false,
|
||||
devServerEvents: NodeJS.EventEmitter,
|
||||
specs: Spec[],
|
||||
): Plugin => {
|
||||
let base = '/'
|
||||
@@ -93,8 +93,10 @@ export const makeCypressPlugin = (
|
||||
let moduleImporters = server.moduleGraph.fileToModulesMap.get(file)
|
||||
let iterationNumber = 0
|
||||
|
||||
const exploredFiles = new Set<string>()
|
||||
|
||||
// until we reached a point where the current module is imported by no other
|
||||
while (moduleImporters && moduleImporters.size) {
|
||||
while (moduleImporters?.size) {
|
||||
if (iterationNumber > HMR_DEPENDENCY_LOOKUP_MAX_ITERATION) {
|
||||
debug(`max hmr iteration reached: ${HMR_DEPENDENCY_LOOKUP_MAX_ITERATION}; Rerun will not happen on this file change.`)
|
||||
|
||||
@@ -108,19 +110,22 @@ export const makeCypressPlugin = (
|
||||
debug('handleHotUpdate - support compile success')
|
||||
devServerEvents.emit('dev-server:compile:success')
|
||||
|
||||
// if we update support we know we have to re-run it all
|
||||
// no need to ckeck further
|
||||
return []
|
||||
}
|
||||
|
||||
if (mod.file && specsPathsSet.has(mod.file)) {
|
||||
debug('handleHotUpdate - spec compile success', mod.file)
|
||||
devServerEvents.emit('dev-server:compile:success', { specFile: mod.file })
|
||||
|
||||
return []
|
||||
// if we find one spec, does not mean we are done yet,
|
||||
// there could be other spec files to re-run
|
||||
// see https://github.com/cypress-io/cypress/issues/17691
|
||||
}
|
||||
}
|
||||
|
||||
// get all the modules that import the current one
|
||||
moduleImporters = getImporters(moduleImporters)
|
||||
moduleImporters = getImporters(moduleImporters, exploredFiles)
|
||||
iterationNumber += 1
|
||||
}
|
||||
|
||||
@@ -129,11 +134,22 @@ export const makeCypressPlugin = (
|
||||
}
|
||||
}
|
||||
|
||||
function getImporters (modules: Set<ModuleNode>): Set<ModuleNode> {
|
||||
/**
|
||||
* Gets all the modules that import the set of modules passed in parameters
|
||||
* @param modules the set of module whose dependents to return
|
||||
* @param alreadyExploredFiles set of files that have already been looked at and should be avoided in case of circular dependency
|
||||
* @returns a set of ModuleMode that import directly the current modules
|
||||
*/
|
||||
function getImporters (modules: Set<ModuleNode>, alreadyExploredFiles: Set<string>): Set<ModuleNode> {
|
||||
const allImporters = new Set<ModuleNode>()
|
||||
|
||||
modules.forEach((m) => {
|
||||
m.importers.forEach((imp) => allImporters.add(imp))
|
||||
if (m.file && !alreadyExploredFiles.has(m.file)) {
|
||||
alreadyExploredFiles.add(m.file)
|
||||
m.importers.forEach((imp) => {
|
||||
allImporters.add(imp)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return allImporters
|
||||
|
||||
@@ -6,25 +6,18 @@ import { makeCypressPlugin } from './makeCypressPlugin'
|
||||
|
||||
const debug = Debug('cypress:vite-dev-server:start')
|
||||
|
||||
interface Options {
|
||||
specs: Cypress.Cypress['spec'][]
|
||||
config: Record<string, string>
|
||||
devServerEvents: EventEmitter
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface StartDevServerOptions {
|
||||
/**
|
||||
* the Cypress options object
|
||||
* the Cypress dev server configuration object
|
||||
*/
|
||||
options: Options
|
||||
options: Cypress.DevServerConfig
|
||||
/**
|
||||
* By default, vite will use your vite.config file to
|
||||
* Start the server. If you need additional plugins or
|
||||
* to override some options, you can do so using this.
|
||||
* @optional
|
||||
*/
|
||||
viteConfig?: UserConfig
|
||||
viteConfig?: Omit<UserConfig, 'base' | 'root'>
|
||||
}
|
||||
|
||||
const resolveServerConfig = async ({ viteConfig, options }: StartDevServerOptions): Promise<InlineConfig> => {
|
||||
@@ -59,7 +52,14 @@ const resolveServerConfig = async ({ viteConfig, options }: StartDevServerOption
|
||||
// Ask vite to pre-optimize all dependencies of the specs
|
||||
finalConfig.optimizeDeps = finalConfig.optimizeDeps || {}
|
||||
|
||||
finalConfig.optimizeDeps.entries = [...options.specs.map((spec) => spec.relative), supportFile]
|
||||
// pre-optimizea all the specs
|
||||
if ((options.specs && options.specs.length)) {
|
||||
finalConfig.optimizeDeps.entries = [...options.specs.map((spec) => spec.relative)]
|
||||
// only optimize a supportFile is it is not false or undefined
|
||||
if (supportFile) {
|
||||
finalConfig.optimizeDeps.entries.push(supportFile)
|
||||
}
|
||||
}
|
||||
|
||||
debug(`the resolved server config is ${JSON.stringify(finalConfig, null, 2)}`)
|
||||
|
||||
|
||||
@@ -76,11 +76,22 @@
|
||||
"url": "https://github.com/cypress-io/cypress.git"
|
||||
},
|
||||
"homepage": "https://github.com/cypress-io/cypress/blob/master/npm/vue/#readme",
|
||||
"author": "Gleb Bahmutov <gleb.bahmutov@gmail.com>",
|
||||
"bugs": "https://github.com/cypress-io/cypress/issues/new?assignees=&labels=npm%3A%20%40cypress%2Fvue&template=1-bug-report.md&title=",
|
||||
"keywords": [
|
||||
"cypress",
|
||||
"vue"
|
||||
],
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Jessica Sachs",
|
||||
"social": "@JessicaSachs"
|
||||
},
|
||||
{
|
||||
"name": "Amir Rustamzadeh",
|
||||
"social": "@amirrustam"
|
||||
}
|
||||
],
|
||||
"module": "dist/cypress-vue.esm-bundler.js",
|
||||
"peerDependenciesMeta": {
|
||||
"@cypress/webpack-dev-server": {
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
# [@cypress/webpack-dev-server-v1.6.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v1.5.0...@cypress/webpack-dev-server-v1.6.0) (2021-09-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow usage of @react/plugins with cypress.config.js ([#17738](https://github.com/cypress-io/cypress/issues/17738)) ([da4b1e0](https://github.com/cypress-io/cypress/commit/da4b1e06ce33945aabddda0e6e175dc0e1b488a5))
|
||||
|
||||
# [@cypress/webpack-dev-server-v1.5.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v1.4.0...@cypress/webpack-dev-server-v1.5.0) (2021-08-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* support webpack-dev-server v4 ([#17918](https://github.com/cypress-io/cypress/issues/17918)) ([16e4759](https://github.com/cypress-io/cypress/commit/16e4759e0196f68c5f0525efb020211337748f94))
|
||||
|
||||
# [@cypress/webpack-dev-server-v1.4.0](https://github.com/cypress-io/cypress/compare/@cypress/webpack-dev-server-v1.3.1...@cypress/webpack-dev-server-v1.4.0) (2021-06-17)
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"build-prod": "tsc",
|
||||
"test": "tsc && mocha -r @packages/ts/register test/**/*.spec.ts test/*.spec.ts --exit",
|
||||
"test": "node ./test-wds-3.js",
|
||||
"test-all": "tsc && mocha -r @packages/ts/register test/**/*.spec.ts test/*.spec.ts --exit",
|
||||
"watch": "tsc -w"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -16,7 +17,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/webpack": ">=4",
|
||||
"@types/webpack-dev-server": "^3.11.1",
|
||||
"@types/webpack-dev-server": "^4.0.0",
|
||||
"chai": "^4.2.0",
|
||||
"html-webpack-plugin": "4.x",
|
||||
"mocha": "^8.1.3",
|
||||
@@ -24,7 +25,7 @@
|
||||
"speed-measure-webpack-plugin": "1.4.2",
|
||||
"typescript": "^4.2.3",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
"webpack-dev-server": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"html-webpack-plugin": ">=4",
|
||||
|
||||
@@ -2,6 +2,7 @@ import { debug as debugFn } from 'debug'
|
||||
import { AddressInfo } from 'net'
|
||||
import { Server } from 'http'
|
||||
import { start as createDevServer, StartDevServer } from './startServer'
|
||||
import { webpackDevServerFacts } from './webpackDevServerFacts'
|
||||
|
||||
const debug = debugFn('cypress:webpack-dev-server:webpack')
|
||||
|
||||
@@ -17,26 +18,41 @@ export { StartDevServer }
|
||||
export async function startDevServer (startDevServerArgs: StartDevServer, exitProcess = process.exit) {
|
||||
const webpackDevServer = await createDevServer(startDevServerArgs, exitProcess)
|
||||
|
||||
return new Promise<ResolvedDevServerConfig>((resolve) => {
|
||||
const httpSvr = webpackDevServer.listen(0, '127.0.0.1', () => {
|
||||
// webpack-dev-server v3 returns `http.Server`.
|
||||
// v4 returns a Promise that resolves `http.Server`.
|
||||
// use Promise.resolve to make sure we get the `http.Server`,
|
||||
// regardless of webpack-dev-server version.
|
||||
Promise.resolve(httpSvr).then((server: Server) => {
|
||||
return new Promise<ResolvedDevServerConfig>(async (resolve, reject) => {
|
||||
if (webpackDevServerFacts.isV3()) {
|
||||
const server: Server = webpackDevServer.listen(0, '127.0.0.1', () => {
|
||||
// FIXME: handle address returning a string
|
||||
const port = (server.address() as AddressInfo).port
|
||||
|
||||
debug('Component testing webpack server started on port', port)
|
||||
|
||||
return resolve({
|
||||
resolve({
|
||||
port,
|
||||
close: (done?: DoneCallback) => {
|
||||
httpSvr.close()
|
||||
server.close()
|
||||
done?.()
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (webpackDevServerFacts.isV4()) {
|
||||
await webpackDevServer.start()
|
||||
|
||||
resolve({
|
||||
// @ts-expect-error @types do not yet support v4
|
||||
port: webpackDevServer.options.port,
|
||||
close: (done?: DoneCallback) => {
|
||||
webpackDevServer.stop()
|
||||
done?.()
|
||||
},
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
reject(webpackDevServerFacts.unsupported())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import Debug from 'debug'
|
||||
import webpack from 'webpack'
|
||||
import WebpackDevServer from 'webpack-dev-server'
|
||||
import webpackDevServerPkg from 'webpack-dev-server/package.json'
|
||||
import { makeWebpackConfig, UserWebpackDevServerOptions } from './makeWebpackConfig'
|
||||
import { webpackDevServerFacts } from './webpackDevServerFacts'
|
||||
|
||||
export interface StartDevServer extends UserWebpackDevServerOptions {
|
||||
/* this is the Cypress options object */
|
||||
options: Cypress.DevServerOptions
|
||||
/* this is the Cypress dev server configuration object */
|
||||
options: Cypress.DevServerConfig
|
||||
/* support passing a path to the user's webpack config */
|
||||
webpackConfig?: Record<string, any>
|
||||
/* base html template to render in AUT */
|
||||
@@ -53,25 +53,35 @@ export async function start ({ webpackConfig: userWebpackConfig, template, optio
|
||||
hot: false,
|
||||
}
|
||||
|
||||
if (webpackDevServerPkg.version.match(/3\./)) {
|
||||
if (webpackDevServerFacts.isV3()) {
|
||||
debug('using webpack-dev-server v3')
|
||||
webpackDevServerConfig = {
|
||||
...webpackDevServerConfig,
|
||||
// @ts-ignore ignore webpack-dev-server v3 type errors
|
||||
inline: false,
|
||||
publicPath: devServerPublicPathRoute,
|
||||
noInfo: false,
|
||||
}
|
||||
} else if (webpackDevServerPkg.version.match(/4\./)) {
|
||||
|
||||
// @ts-ignore ignore webpack-dev-server v3 type errors
|
||||
return new WebpackDevServer(compiler, webpackDevServerConfig)
|
||||
}
|
||||
|
||||
if (webpackDevServerFacts.isV4()) {
|
||||
debug('using webpack-dev-server v4')
|
||||
webpackDevServerConfig = {
|
||||
host: 'localhost',
|
||||
port: 'auto',
|
||||
...userWebpackConfig?.devServer,
|
||||
devMiddleware: {
|
||||
publicPath: devServerPublicPathRoute,
|
||||
},
|
||||
hot: false,
|
||||
}
|
||||
} else {
|
||||
throw Error(`@cypress/webpack-dev-server only supports webpack-dev-server v3 and v4. Found: ${webpackDevServerPkg.version}.`)
|
||||
|
||||
// @ts-expect-error Webpack types are clashing between Webpack and WebpackDevServer
|
||||
return new WebpackDevServer(webpackDevServerConfig, compiler)
|
||||
}
|
||||
|
||||
// @ts-ignore types for webpack v5 are incorrect?
|
||||
return new WebpackDevServer(compiler, webpackDevServerConfig)
|
||||
throw webpackDevServerFacts.unsupported()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import webpackDevServerPkg from 'webpack-dev-server/package.json'
|
||||
|
||||
export const webpackDevServerFacts = {
|
||||
version: webpackDevServerPkg.version,
|
||||
isV3 (version = webpackDevServerPkg.version) {
|
||||
return /^3\./.test(version)
|
||||
},
|
||||
isV4 (version = webpackDevServerPkg.version) {
|
||||
return /^4\./.test(version)
|
||||
},
|
||||
unsupported () {
|
||||
return Error(`@cypress/webpack-dev-server only supports webpack-dev-server v3 and v4. Found: ${webpackDevServerFacts.version}.`)
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
const execa = require('execa')
|
||||
const pkg = require('./package.json')
|
||||
const fs = require('fs')
|
||||
|
||||
/**
|
||||
* This file installs WebpackDevServer 3 and runs the tests for the dev-server.
|
||||
* We read package.json, update the webpack version, then re-run yarn install.
|
||||
* After it finishes, pass or fail,
|
||||
* we revert the package.json back to the original state.
|
||||
*
|
||||
* The tests for the example projects (inside of examples) run with WebpackDevServer 3.
|
||||
* This ensures we have some coverage for both versions.
|
||||
*/
|
||||
const main = async () => {
|
||||
const originalPkg = JSON.stringify(pkg, null, 2)
|
||||
|
||||
const resetPkg = async () => {
|
||||
fs.writeFileSync('package.json', originalPkg, 'utf8')
|
||||
await execa('yarn', ['install'], { stdio: 'inherit' })
|
||||
}
|
||||
|
||||
const checkExit = async ({ exitCode }) => {
|
||||
if (typeof exitCode !== 'number') {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Finished with missing exit code from execa (received ${exitCode})`)
|
||||
}
|
||||
|
||||
await resetPkg()
|
||||
process.exit(exitCode)
|
||||
}
|
||||
|
||||
pkg.devDependencies['webpack-dev-server'] = '3.11.0'
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[@cypress/webpack-dev-server]: updating package.json...')
|
||||
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2))
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[@cypress/webpack-dev-server]: install dependencies...')
|
||||
await execa('yarn', ['install'], { stdio: 'inherit' })
|
||||
|
||||
const { exitCode } = await execa('yarn', ['test-all'], { stdio: 'inherit' })
|
||||
|
||||
await checkExit({ exitCode })
|
||||
}
|
||||
|
||||
// execute main function if called from command line
|
||||
if (require.main === module) {
|
||||
main()
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import webpack from 'webpack'
|
||||
import path from 'path'
|
||||
import sinon from 'sinon'
|
||||
import { expect } from 'chai'
|
||||
import { EventEmitter } from 'events'
|
||||
import http from 'http'
|
||||
import fs from 'fs'
|
||||
import { webpackDevServerFacts } from '../src/webpackDevServerFacts'
|
||||
|
||||
import { startDevServer } from '../'
|
||||
|
||||
@@ -34,11 +34,11 @@ const requestSpecFile = (port: number) => {
|
||||
|
||||
const root = path.join(__dirname, '..')
|
||||
|
||||
const webpackConfig: webpack.Configuration = {
|
||||
output: {
|
||||
path: root,
|
||||
publicPath: root,
|
||||
},
|
||||
const webpackConfig = {
|
||||
devServer: webpackDevServerFacts.isV3()
|
||||
? { contentBase: root }
|
||||
: { static: { directory: root } },
|
||||
|
||||
}
|
||||
|
||||
const specs: Cypress.Cypress['spec'][] = [
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { expect } from 'chai'
|
||||
import { webpackDevServerFacts } from '../../src/webpackDevServerFacts'
|
||||
|
||||
describe('webpackDevServerFacts', () => {
|
||||
it('should detect v3', () => {
|
||||
expect(webpackDevServerFacts.isV3('3.0.0')).equals(true)
|
||||
expect(webpackDevServerFacts.isV3('3.1.4')).equals(true)
|
||||
expect(webpackDevServerFacts.isV3('4.0.0')).equals(false)
|
||||
expect(webpackDevServerFacts.isV3('4.3.0')).equals(false)
|
||||
})
|
||||
|
||||
it('should detect v4', () => {
|
||||
expect(webpackDevServerFacts.isV4('3.0.0')).equals(false)
|
||||
expect(webpackDevServerFacts.isV4('3.1.4')).equals(false)
|
||||
expect(webpackDevServerFacts.isV4('3.4.4')).equals(false)
|
||||
expect(webpackDevServerFacts.isV4('4.0.0')).equals(true)
|
||||
expect(webpackDevServerFacts.isV4('4.3.0')).equals(true)
|
||||
})
|
||||
})
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cypress",
|
||||
"version": "8.2.0",
|
||||
"version": "8.4.1",
|
||||
"description": "Cypress.io end to end testing tool",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -77,7 +77,7 @@
|
||||
"@cypress/env-or-json-file": "2.0.0",
|
||||
"@cypress/github-commit-status-check": "1.5.0",
|
||||
"@cypress/questions-remain": "1.0.1",
|
||||
"@cypress/request": "2.88.5",
|
||||
"@cypress/request": "2.88.6",
|
||||
"@cypress/request-promise": "4.2.6",
|
||||
"@fellow/eslint-plugin-coffee": "0.4.13",
|
||||
"@percy/cli": "1.0.0-beta.48",
|
||||
@@ -160,7 +160,7 @@
|
||||
"lint-staged": "11.0.0",
|
||||
"listr2": "3.8.3",
|
||||
"lodash": "4.17.21",
|
||||
"make-empty-github-commit": "1.2.0",
|
||||
"make-empty-github-commit": "cypress-io/make-empty-github-commit#4a592aedb776ba2f4cc88979055315a53eec42ee",
|
||||
"minimist": "1.2.5",
|
||||
"mocha": "3.5.3",
|
||||
"mocha-banner": "1.1.2",
|
||||
@@ -196,7 +196,7 @@
|
||||
"yarn-deduplicate": "3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.16.0",
|
||||
"node": ">=14.17.0",
|
||||
"yarn": ">=1.17.3"
|
||||
},
|
||||
"productName": "Cypress",
|
||||
|
||||
@@ -132,7 +132,6 @@
|
||||
"integrationFolder": "/Users/jennifer/Dev/Projects/cypress-example-kitchensink/cypress/integration",
|
||||
"isHeadless": false,
|
||||
"isNewProject": false,
|
||||
"javascripts": [],
|
||||
"morgan": true,
|
||||
"namespace": "__cypress",
|
||||
"numTestsKeptInMemory": 50,
|
||||
|
||||
@@ -852,34 +852,101 @@ describe('Runs List', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('displays empty message', () => {
|
||||
cy.contains('To record your first')
|
||||
})
|
||||
context('a/b control group', function () {
|
||||
beforeEach(function () {
|
||||
this.getProjectStatus.resolve({
|
||||
orgId: '0',
|
||||
})
|
||||
})
|
||||
|
||||
it('opens project id guide on clicking "Why?"', () => {
|
||||
cy.contains('Why?').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWith('https://on.cypress.io/what-is-a-project-id')
|
||||
it('displays empty message', () => {
|
||||
cy.contains('To record your first run')
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('opens project id guide on clicking "Why?"', () => {
|
||||
cy.contains('Why?').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWithMatch({ url: 'https://on.cypress.io/what-is-a-project-id' })
|
||||
})
|
||||
})
|
||||
|
||||
it('opens dashboard on clicking "Cypress Dashboard"', () => {
|
||||
cy.contains('Cypress Dashboard').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWith(`https://on.cypress.io/dashboard/projects/${this.config.projectId}/runs`)
|
||||
})
|
||||
})
|
||||
|
||||
it('shows tooltip on hover of copy to clipboard', () => {
|
||||
cy.get('#code-record-command').find('.action-copy').trigger('mouseover')
|
||||
cy.get('.cy-tooltip').should('contain', 'Copy to clipboard')
|
||||
cy.get('#code-record-command').find('.action-copy').trigger('mouseout')
|
||||
})
|
||||
|
||||
it('copies record key command to clipboard', () => {
|
||||
cy.get('#code-record-command').find('.action-copy').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.setClipboardText).to.be.calledWith(`cypress run --record --key <record-key>`)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('opens dashboard on clicking "Cypress Dashboard"', () => {
|
||||
cy.contains('Cypress Dashboard').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWith(`https://on.cypress.io/dashboard/projects/${this.config.projectId}/runs`)
|
||||
context('a/b test group', function () {
|
||||
beforeEach(function () {
|
||||
this.getProjectStatus.resolve({
|
||||
orgId: '1',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('shows tooltip on hover of copy to clipboard', () => {
|
||||
cy.get('#code-record-command').find('.action-copy').trigger('mouseover')
|
||||
cy.get('.cy-tooltip').should('contain', 'Copy to clipboard')
|
||||
cy.get('#code-record-command').find('.action-copy').trigger('mouseout')
|
||||
})
|
||||
it('displays empty message', () => {
|
||||
cy.contains('How to record your first run')
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('copies record key command to clipboard', () => {
|
||||
cy.get('#code-record-command').find('.action-copy').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.setClipboardText).to.be.calledWith(`cypress run --record --key <record-key>`)
|
||||
it('displays tooltip with project id info', () => {
|
||||
cy.get('.help-text').eq(0).find('a').trigger('mouseover')
|
||||
cy.get('.cy-tooltip').should('contain', 'This helps Cypress uniquely identify your project')
|
||||
.contains('Learn more').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWithMatch({ url: 'https://on.cypress.io/what-is-a-project-id' })
|
||||
})
|
||||
})
|
||||
|
||||
it('displays tooltip with record run command info', () => {
|
||||
cy.get('.help-text').eq(1).find('a').trigger('mouseover')
|
||||
cy.get('.cy-tooltip').should('contain', 'Close this application and run this command')
|
||||
.contains('Learn more').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWithMatch({ url: 'https://on.cypress.io/recording-project-runs' })
|
||||
})
|
||||
})
|
||||
|
||||
it('shows tooltip on hover of copy to clipboard', () => {
|
||||
cy.get('#code-record-command').find('.action-copy').trigger('mouseover')
|
||||
cy.get('.cy-tooltip').should('contain', 'Copy to clipboard')
|
||||
cy.get('#code-record-command').find('.action-copy').trigger('mouseout')
|
||||
})
|
||||
|
||||
it('copies record key command to clipboard', () => {
|
||||
cy.get('#code-record-command').find('.action-copy').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.setClipboardText).to.be.calledWith(`cypress run --record --key <record-key>`)
|
||||
})
|
||||
})
|
||||
|
||||
it('displays run in ci panel with link', () => {
|
||||
cy.contains('Run in CI').parents('.panel').contains('Show me how').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWithMatch({ url: 'https://on.cypress.io/ci' })
|
||||
})
|
||||
})
|
||||
|
||||
it('displays sample project panel with link', () => {
|
||||
cy.contains('Sample Project').parents('.panel').contains('See the sample').click()
|
||||
.then(function () {
|
||||
expect(this.ipc.externalOpen).to.be.calledWithMatch({ url: 'https://on.cypress.io/rwa-dashboard' })
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -75,7 +75,7 @@ const onSubmitNewProject = function (orgId) {
|
||||
|
||||
it('displays empty runs page', function () {
|
||||
cy.get('.setup-project').should('not.exist')
|
||||
cy.contains('To record your first')
|
||||
cy.contains('How to record your first')
|
||||
cy.contains('cypress run --record --key record-key-123')
|
||||
})
|
||||
|
||||
|
||||
@@ -282,4 +282,10 @@ export default class Project {
|
||||
serialize () {
|
||||
return _.pick(this, cacheProps)
|
||||
}
|
||||
|
||||
getTestGroup (numGroups) {
|
||||
const numKey = this.orgId && this.orgId.length ? this.orgId.charCodeAt(0) : 0
|
||||
|
||||
return numKey % numGroups
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +137,17 @@ const closeProject = (project) => {
|
||||
])
|
||||
}
|
||||
|
||||
const updateProjectStatus = (project) => {
|
||||
return ipc.getProjectStatus(project.clientDetails())
|
||||
.then((projectDetails) => {
|
||||
project.update(projectDetails)
|
||||
})
|
||||
.catch(ipc.isUnauthed, ipc.handleUnauthed)
|
||||
.catch((err) => {
|
||||
project.setApiError(err)
|
||||
})
|
||||
}
|
||||
|
||||
const openProject = (project) => {
|
||||
specsStore.loading(true)
|
||||
|
||||
@@ -145,17 +156,6 @@ const openProject = (project) => {
|
||||
project.setError(err)
|
||||
}
|
||||
|
||||
const updateProjectStatus = () => {
|
||||
return ipc.getProjectStatus(project.clientDetails())
|
||||
.then((projectDetails) => {
|
||||
project.update(projectDetails)
|
||||
})
|
||||
.catch(ipc.isUnauthed, ipc.handleUnauthed)
|
||||
.catch((err) => {
|
||||
project.setApiError(err)
|
||||
})
|
||||
}
|
||||
|
||||
const updateConfig = (config) => {
|
||||
project.update({
|
||||
id: config.projectId,
|
||||
@@ -199,9 +199,9 @@ const openProject = (project) => {
|
||||
project.setLoading(false)
|
||||
getSpecs(setProjectError)
|
||||
|
||||
projectPollingId = setInterval(updateProjectStatus, 10000)
|
||||
projectPollingId = setInterval(() => updateProjectStatus(project), 10000)
|
||||
|
||||
return updateProjectStatus()
|
||||
return updateProjectStatus(project)
|
||||
})
|
||||
.catch(setProjectError)
|
||||
}
|
||||
@@ -242,6 +242,7 @@ const getRecordKeys = () => {
|
||||
|
||||
export default {
|
||||
loadProjects,
|
||||
updateProjectStatus,
|
||||
openProject,
|
||||
reopenProject,
|
||||
closeProject,
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
import React, { Component } from 'react'
|
||||
import { observer } from 'mobx-react'
|
||||
import Tooltip from '@cypress/react-tooltip'
|
||||
import Loader from 'react-loader'
|
||||
|
||||
import ipc from '../lib/ipc'
|
||||
import projectsApi from '../projects/projects-api'
|
||||
import { configFileFormatted } from '../lib/config-file-formatted'
|
||||
|
||||
@observer
|
||||
class RunsListEmpty extends Component {
|
||||
componentDidMount () {
|
||||
this._updateProjectStatus()
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this._updateProjectStatus()
|
||||
}
|
||||
|
||||
_updateProjectStatus = () => {
|
||||
const { project } = this.props
|
||||
|
||||
if (!project.orgId) {
|
||||
projectsApi.updateProjectStatus(project)
|
||||
}
|
||||
}
|
||||
|
||||
_openProjectIdGuide = (e, utm_medium = 'Empty Runs Tab') => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen({
|
||||
url: 'https://on.cypress.io/what-is-a-project-id',
|
||||
params: {
|
||||
utm_medium,
|
||||
utm_campaign: 'ProjectId',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_openRuns = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen(`https://on.cypress.io/dashboard/projects/${this.props.project.id}/runs`)
|
||||
}
|
||||
|
||||
_openCiGuide = (e, utm_medium = 'Empty Runs Tab') => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen({
|
||||
url: 'https://on.cypress.io/ci',
|
||||
params: {
|
||||
utm_medium,
|
||||
utm_campaign: 'CI',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_openRunGuide = (e, utm_medium = 'Empty Runs Tab') => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen({
|
||||
url: 'https://on.cypress.io/recording-project-runs',
|
||||
params: {
|
||||
utm_medium,
|
||||
utm_campaign: 'Runs Guide',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_openSampleProject = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen({
|
||||
url: 'https://on.cypress.io/rwa-dashboard',
|
||||
params: {
|
||||
utm_medium: 'Empty Runs Tab',
|
||||
utm_camptain: 'Sample Project',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
_recordCommand = () => {
|
||||
return `cypress run --record --key ${this.props.recordKey || '<record-key>'}`
|
||||
}
|
||||
|
||||
_control = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className='first-run-instructions'>
|
||||
<h4 className='center'>
|
||||
To record your first run...
|
||||
</h4>
|
||||
<h5>
|
||||
<span>
|
||||
1. <code>projectId: {this.props.project.id}</code> has been saved to your {configFileFormatted(this.props.project.configFile)}.{' '}
|
||||
Make sure to check this file into source control.
|
||||
</span>
|
||||
<a onClick={(e) => this._openProjectIdGuide(e, 'Control Empty Runs Tab')}>
|
||||
<i className='fas fa-question-circle' />{' '}
|
||||
Why?
|
||||
</a>
|
||||
</h5>
|
||||
<h5>
|
||||
<span>
|
||||
2. Run this command now, or in CI.
|
||||
</span>
|
||||
<a onClick={(e) => this._openCiGuide(e, 'Control Empty Runs Tab')}>
|
||||
<i className='fas fa-question-circle' />{' '}
|
||||
Need help?
|
||||
</a>
|
||||
</h5>
|
||||
<pre id="code-record-command" className="copy-to-clipboard">
|
||||
<a className="action-copy" onClick={() => ipc.setClipboardText(this._recordCommand())}>
|
||||
<Tooltip
|
||||
title='Copy to clipboard'
|
||||
placement='top'
|
||||
className='cy-tooltip'
|
||||
>
|
||||
<i className='fas fa-clipboard' />
|
||||
</Tooltip>
|
||||
</a>
|
||||
<code>{this._recordCommand()}</code>
|
||||
</pre>
|
||||
<hr />
|
||||
<p className='alert alert-default'>
|
||||
<i className='fas fa-info-circle' />{' '}
|
||||
Recorded runs will show up{' '}
|
||||
<a href='#' onClick={(e) => this._openRunGuide(e, 'Control Empty Runs Tab')}>here</a>{' '}
|
||||
and on your{' '}
|
||||
<a href='#' onClick={this._openRuns}>Cypress Dashboard Service</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
_new = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className='first-run-instructions new-first-run-instructions'>
|
||||
<h4>
|
||||
How to record your first run
|
||||
</h4>
|
||||
<p className='subtitle'>
|
||||
Recording test runs to the Dashboard enables you to run tests faster with parallelization and load balancing, debug failed tests in CI with screenshots and videos, and identify flaky tests.
|
||||
</p>
|
||||
<div className='step'>
|
||||
<span>
|
||||
1. <code>projectId: {this.props.project.id}</code> has been saved to your {configFileFormatted(this.props.project.configFile)}.{' '}
|
||||
Make sure to check this file into source control.
|
||||
</span>
|
||||
<span className='help-text'>
|
||||
<Tooltip
|
||||
className='tooltip-text-left cy-tooltip'
|
||||
title={<span>This helps Cypress uniquely identify your project. If altered or deleted, analytics and load balancing will not function properly. <a onClick={this._openProjectIdGuide}>Learn more</a></span>}
|
||||
>
|
||||
<a><i className='fas fa-question-circle' /></a>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<div className='step'>
|
||||
<span>
|
||||
2. Run this command now, or in CI.
|
||||
</span>
|
||||
<span className='help-text'>
|
||||
<Tooltip
|
||||
className='tooltip-text-left cy-tooltip'
|
||||
title={<span>Close this application and run this command with <code className='tooltip-code'>npx</code> or <code className='tooltip-code'>yarn</code> in your terminal. <a onClick={this._openRunGuide}>Learn more</a></span>}
|
||||
>
|
||||
<a><i className='fas fa-question-circle' /></a>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<pre id="code-record-command" className="copy-to-clipboard">
|
||||
<a className="action-copy" onClick={() => ipc.setClipboardText(this._recordCommand())}>
|
||||
<Tooltip
|
||||
title='Copy to clipboard'
|
||||
placement='top'
|
||||
className='cy-tooltip'
|
||||
>
|
||||
<i className='fas fa-clipboard' />
|
||||
</Tooltip>
|
||||
</a>
|
||||
<code>{this._recordCommand()}</code>
|
||||
</pre>
|
||||
<hr />
|
||||
<div className='panel-wrapper'>
|
||||
<div className='panel'>
|
||||
<div className='panel-icon panel-icon-small'>
|
||||
<i className='fas fa-infinity fa-fw' />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<strong>Run in CI</strong>
|
||||
<br />
|
||||
Cypress was designed to be run in your CI, enabling parallel test runs and rich test analytics. <a onClick={this._openCiGuide}>Show me how</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='panel'>
|
||||
<div className='panel-icon'>
|
||||
<i className='fas fa-tasks fa-fw' />
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<strong>Sample Project</strong>
|
||||
<br />
|
||||
Want to see what a recorded run looks like? See an example project in the Dashboard. <a onClick={this._openSampleProject}>See the sample</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { project } = this.props
|
||||
|
||||
if (!project.orgId) {
|
||||
return <Loader color='#888' scale={0.5}/>
|
||||
}
|
||||
|
||||
if (project.getTestGroup(2)) {
|
||||
return this._new()
|
||||
}
|
||||
|
||||
return this._control()
|
||||
}
|
||||
}
|
||||
|
||||
export default RunsListEmpty
|
||||
@@ -2,10 +2,8 @@ import _ from 'lodash'
|
||||
import React, { Component } from 'react'
|
||||
import { observer } from 'mobx-react'
|
||||
import Loader from 'react-loader'
|
||||
import Tooltip from '@cypress/react-tooltip'
|
||||
|
||||
import ipc from '../lib/ipc'
|
||||
import { configFileFormatted } from '../lib/config-file-formatted'
|
||||
import authStore from '../auth/auth-store'
|
||||
import RunsStore from './runs-store'
|
||||
import errors from '../lib/errors'
|
||||
@@ -21,6 +19,7 @@ import PermissionMessage from './permission-message'
|
||||
import ProjectNotSetup from './project-not-setup'
|
||||
import DashboardBanner from './dashboard-banner'
|
||||
import WhatIsDashboard from './what-is-dashboard'
|
||||
import RunsListEmpty from './runs-list-empty'
|
||||
|
||||
@observer
|
||||
class RunsList extends Component {
|
||||
@@ -45,8 +44,8 @@ class RunsList extends Component {
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this._getRecordKeys()
|
||||
this._handlePolling()
|
||||
this._getRecordKeys()
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
@@ -204,7 +203,7 @@ class RunsList extends Component {
|
||||
// OR they have setup CI
|
||||
}
|
||||
|
||||
return this._empty()
|
||||
return <RunsListEmpty project={this.props.project} recordKey={this.state.recordKey} />
|
||||
}
|
||||
//--------End Run States----------//
|
||||
|
||||
@@ -320,79 +319,6 @@ class RunsList extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
_empty () {
|
||||
const recordCommand = `cypress run --record --key ${this.state.recordKey || '<record-key>'}`
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='first-run-instructions'>
|
||||
<h4>
|
||||
To record your first run...
|
||||
</h4>
|
||||
<h5>
|
||||
<span>
|
||||
1. <code>projectId: {this.props.project.id}</code> has been saved to your {configFileFormatted(this.props.project.configFile)}.{' '}
|
||||
Make sure to check this file into source control.
|
||||
</span>
|
||||
<a onClick={this._openProjectIdGuide}>
|
||||
<i className='fas fa-question-circle' />{' '}
|
||||
Why?
|
||||
</a>
|
||||
</h5>
|
||||
<h5>
|
||||
<span>
|
||||
2. Run this command now, or in CI.
|
||||
</span>
|
||||
<a onClick={this._openCiGuide}>
|
||||
<i className='fas fa-question-circle' />{' '}
|
||||
Need help?
|
||||
</a>
|
||||
</h5>
|
||||
<pre id="code-record-command" className="copy-to-clipboard">
|
||||
<a className="action-copy" onClick={() => ipc.setClipboardText(recordCommand)}>
|
||||
<Tooltip
|
||||
title='Copy to clipboard'
|
||||
placement='top'
|
||||
className='cy-tooltip'
|
||||
>
|
||||
<i className='fas fa-clipboard' />
|
||||
</Tooltip>
|
||||
</a>
|
||||
<code>{recordCommand}</code>
|
||||
</pre>
|
||||
<hr />
|
||||
<p className='alert alert-default'>
|
||||
<i className='fas fa-info-circle' />{' '}
|
||||
Recorded runs will show up{' '}
|
||||
<a href='#' onClick={this._openRunGuide}>here</a>{' '}
|
||||
and on your{' '}
|
||||
<a href='#' onClick={this._openRuns}>Cypress Dashboard Service</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
_openRunGuide = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen('https://on.cypress.io/recording-project-runs')
|
||||
}
|
||||
|
||||
_openRuns = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen(`https://on.cypress.io/dashboard/projects/${this.props.project.id}/runs`)
|
||||
}
|
||||
|
||||
_openCiGuide = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen('https://on.cypress.io/guides/continuous-integration')
|
||||
}
|
||||
|
||||
_openProjectIdGuide = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen('https://on.cypress.io/what-is-a-project-id')
|
||||
}
|
||||
|
||||
_openDashboard = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen({
|
||||
@@ -404,6 +330,11 @@ class RunsList extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
_openRuns = (e) => {
|
||||
e.preventDefault()
|
||||
ipc.externalOpen(`https://on.cypress.io/dashboard/projects/${this.props.project.id}/runs`)
|
||||
}
|
||||
|
||||
_openRun = (buildNumber) => {
|
||||
ipc.externalOpen(`https://on.cypress.io/dashboard/projects/${this.props.project.id}/runs/${buildNumber}`)
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
.first-run-instructions {
|
||||
padding: 40px 130px;
|
||||
|
||||
&.new-first-run-instructions {
|
||||
padding: 40px 100px;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -49,6 +53,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
.step {
|
||||
display: flex;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
margin: 20px 0 10px;
|
||||
line-height: 18px;
|
||||
|
||||
.help-text {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.alert {
|
||||
border-radius: 3px;
|
||||
border: 1px solid #eee;
|
||||
@@ -74,7 +90,8 @@
|
||||
margin-top: 25px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
h4, .center {
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -85,6 +102,41 @@
|
||||
border-radius: 3px;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.panel-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 20px;
|
||||
|
||||
.panel {
|
||||
border: 1px solid #E5E5E5;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
font-size: 13px;
|
||||
padding: 12px;
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.panel-icon {
|
||||
color: $brand-primary;
|
||||
font-size: 18px;
|
||||
padding-right: 12px;
|
||||
|
||||
&.panel-icon-small {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.runs {
|
||||
|
||||
@@ -150,4 +150,16 @@ pre.copy-to-clipboard {
|
||||
color: #E2E8F0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cy-tooltip {
|
||||
&.tooltip-text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tooltip-code {
|
||||
color: #fff;
|
||||
background-color: #252831;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"projectId": "ypt4pf",
|
||||
"baseUrl": "http://localhost:3500",
|
||||
"testFiles": "**/*",
|
||||
"hosts": {
|
||||
"*.foobar.com": "127.0.0.1"
|
||||
},
|
||||
|
||||
@@ -213,6 +213,10 @@
|
||||
<input type="checkbox" name="colors" value="blue" />
|
||||
<input type="checkbox" name="colors" value="green" />
|
||||
<input type="checkbox" name="colors" value="red" />
|
||||
<input type="checkbox" name="dogs" value="husky" />
|
||||
<input type="checkbox" name="dogs" value="poodle" />
|
||||
<input type="checkbox" name="dogs" value="on" />
|
||||
<input type="checkbox" name="dogs" data-no-value="true" />
|
||||
<input type="tel">
|
||||
</form>
|
||||
|
||||
|
||||
@@ -523,6 +523,18 @@ describe('src/cy/commands/actions/check', () => {
|
||||
|
||||
cy.get(':checkbox:first').check().should('have.class', 'checked')
|
||||
})
|
||||
|
||||
it('throws when cmd recieves values but subject has no value attribute', function (done) {
|
||||
cy.get('[name=dogs]').check(['husky', 'poodle', 'on']).then(($chk) => {
|
||||
expect($chk.length).to.eq(4)
|
||||
})
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include(' cannot be checked/unchecked because it has no \`value\` attribute')
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
@@ -1074,6 +1086,18 @@ describe('src/cy/commands/actions/check', () => {
|
||||
|
||||
cy.get(':checkbox:first').uncheck().should('have.class', 'unchecked')
|
||||
})
|
||||
|
||||
it('throws when cmd recieves values but subject has no value attribute', function (done) {
|
||||
cy.get('[name=dogs]').uncheck(['husky', 'poodle', 'on']).then(($chk) => {
|
||||
expect($chk.length).to.eq(4)
|
||||
})
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.include(' cannot be checked/unchecked because it has no \`value\` attribute')
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.log', () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { $ } = Cypress.$Cypress
|
||||
const { _ } = Cypress
|
||||
const { $ } = window.Cypress.$Cypress
|
||||
const { _ } = window.Cypress
|
||||
|
||||
describe('src/cy/commands/actions/scroll', () => {
|
||||
before(() => {
|
||||
|
||||
@@ -65,7 +65,6 @@ describe('src/cy/commands/actions/select', () => {
|
||||
expect($select.val()).to.equal('same')
|
||||
expect($select.find('option:selected')).to.have.text('Uhura')
|
||||
expect($select[0].selectedIndex).to.equal(2)
|
||||
expect($select[0].selectedOptions[0]).to.eql($select.find('option:selected')[0])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -74,7 +73,6 @@ describe('src/cy/commands/actions/select', () => {
|
||||
expect($select.val()).to.equal('same')
|
||||
expect($select.find('option:selected')).to.have.text('Uhura')
|
||||
expect($select[0].selectedIndex).to.equal(2)
|
||||
expect($select[0].selectedOptions[0]).to.eql($select.find('option:selected')[0])
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -24,8 +24,6 @@ const expectTextEndsWith = (expected) => {
|
||||
}
|
||||
}
|
||||
|
||||
const isChromium = Cypress.isBrowser({ family: 'chromium' })
|
||||
|
||||
describe('src/cy/commands/actions/type - #type', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/fixtures/dom.html')
|
||||
@@ -1659,7 +1657,7 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
href="#"
|
||||
target="_blank" alt="area" />
|
||||
</map>
|
||||
<img usemap="#map" src="/__cypress/static/favicon.ico" alt="image" />
|
||||
<img usemap="#map" src="/fixtures/media/cypress.png" alt="image" />
|
||||
`).prependTo(cy.$$('body'))
|
||||
|
||||
let keydown = cy.stub()
|
||||
@@ -2028,12 +2026,8 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
.type(' f\n{backspace}')
|
||||
.type('{moveToStart}{del}')
|
||||
.then(($el) => {
|
||||
if (isChromium) {
|
||||
expect(stub).callCount(5)
|
||||
expect($el[0].value).eq('oo bar baz ')
|
||||
} else {
|
||||
expect(stub, 'should NOT send beforeinput unless in chromium based browser').not.called
|
||||
}
|
||||
expect(stub).callCount(5)
|
||||
expect($el[0].value).eq('oo bar baz ')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2076,12 +2070,8 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
.type(' f\n{backspace}')
|
||||
.type('{moveToStart}{del}')
|
||||
.then(($el) => {
|
||||
if (isChromium) {
|
||||
expect(stub).callCount(5)
|
||||
expect($el[0].value).eq('oo bar baz f')
|
||||
} else {
|
||||
expect(stub, 'should NOT send beforeinput unless in chromium based browser').not.called
|
||||
}
|
||||
expect(stub).callCount(5)
|
||||
expect($el[0].value).eq('oo bar baz f')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2124,12 +2114,8 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
.type(' f\n{backspace}')
|
||||
.type('{moveToStart}{del}')
|
||||
.then(($el) => {
|
||||
if (isChromium) {
|
||||
expect(stub).callCount(5)
|
||||
expect($el[0].textContent).eq('oo bar baz f')
|
||||
} else {
|
||||
expect(stub, 'should NOT send beforeinput unless in chromium based browser').not.called
|
||||
}
|
||||
expect(stub).callCount(5)
|
||||
expect($el[0].textContent).eq('oo bar baz f')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2169,11 +2155,7 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
.type('{ctrl}{backspace}')
|
||||
.type('{ctrl}{shift}{backspace}')
|
||||
.then(($el) => {
|
||||
if (isChromium) {
|
||||
expect(stub).callCount(4)
|
||||
} else {
|
||||
expect(stub, 'should NOT send beforeinput unless in chromium based browser').not.called
|
||||
}
|
||||
expect(stub).callCount(4)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2190,12 +2172,8 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
})
|
||||
.type('foo')
|
||||
.then(($el) => {
|
||||
if (isChromium) {
|
||||
expect(callCount).eq(3)
|
||||
expect($el[0].value).eq('foo bar baz')
|
||||
} else {
|
||||
expect(callCount, 'should NOT send beforeinput unless in chromium based browser').eq(0)
|
||||
}
|
||||
expect(callCount).eq(3)
|
||||
expect($el[0].value).eq('foo bar baz')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -2573,17 +2551,15 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
// eslint-disable-next-line
|
||||
console.table(table.data, table.columns)
|
||||
|
||||
const beforeinput = Cypress.isBrowser('firefox') ? '' : ' beforeinput,'
|
||||
|
||||
expect(table.name).to.eq('Keyboard Events')
|
||||
const expectedTable = {
|
||||
1: { 'Details': '{ code: KeyH, which: 72 }', Typed: 'h', 'Events Fired': `keydown, keypress,${beforeinput} textInput, input, keyup`, 'Active Modifiers': null, 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
1: { 'Details': '{ code: KeyH, which: 72 }', Typed: 'h', 'Events Fired': `keydown, keypress, beforeinput, textInput, input, keyup`, 'Active Modifiers': null, 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
2: { 'Details': '{ code: ControlLeft, which: 17 }', Typed: '{ctrl}', 'Events Fired': 'keydown', 'Active Modifiers': 'ctrl', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
3: { 'Details': '{ code: AltLeft, which: 18 }', Typed: '{alt}', 'Events Fired': 'keydown', 'Active Modifiers': 'alt, ctrl', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
4: { 'Details': '{ code: Equal, which: 187 }', Typed: '+', 'Events Fired': 'keydown, keyup', 'Active Modifiers': 'alt, ctrl', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
5: { 'Details': '{ code: AltLeft, which: 18 }', Typed: '{alt}', 'Events Fired': 'keyup', 'Active Modifiers': 'ctrl', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
6: { 'Details': '{ code: ControlLeft, which: 17 }', Typed: '{ctrl}', 'Events Fired': 'keyup', 'Active Modifiers': null, 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
7: { 'Details': '{ code: KeyI, which: 73 }', Typed: 'i', 'Events Fired': `keydown, keypress,${beforeinput} textInput, input, keyup`, 'Active Modifiers': null, 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
7: { 'Details': '{ code: KeyI, which: 73 }', Typed: 'i', 'Events Fired': `keydown, keypress, beforeinput, textInput, input, keyup`, 'Active Modifiers': null, 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
}
|
||||
|
||||
// uncomment for debugging
|
||||
@@ -3484,20 +3460,18 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
// eslint-disable-next-line
|
||||
console.table(table.data, table.columns)
|
||||
|
||||
const beforeInput = isChromium ? 'beforeinput, ' : ''
|
||||
|
||||
expect(table.name).to.eq('Keyboard Events')
|
||||
const expectedTable = {
|
||||
1: { 'Details': '{ code: MetaLeft, which: 91 }', Typed: '{cmd}', 'Events Fired': 'keydown', 'Active Modifiers': 'meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
2: { 'Details': '{ code: AltLeft, which: 18 }', Typed: '{option}', 'Events Fired': 'keydown', 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
3: { 'Details': '{ code: KeyF, which: 70 }', Typed: 'f', 'Events Fired': `keydown, keypress, ${beforeInput}textInput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
4: { 'Details': '{ code: KeyO, which: 79 }', Typed: 'o', 'Events Fired': `keydown, keypress, ${beforeInput}textInput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
5: { 'Details': '{ code: KeyO, which: 79 }', Typed: 'o', 'Events Fired': `keydown, keypress, ${beforeInput}textInput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
6: { 'Details': '{ code: Enter, which: 13 }', Typed: '{enter}', 'Events Fired': `keydown, keypress, ${beforeInput}keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
7: { 'Details': '{ code: KeyB, which: 66 }', Typed: 'b', 'Events Fired': `keydown, keypress, ${beforeInput}textInput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
3: { 'Details': '{ code: KeyF, which: 70 }', Typed: 'f', 'Events Fired': `keydown, keypress, beforeinput, textInput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
4: { 'Details': '{ code: KeyO, which: 79 }', Typed: 'o', 'Events Fired': `keydown, keypress, beforeinput, textInput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
5: { 'Details': '{ code: KeyO, which: 79 }', Typed: 'o', 'Events Fired': `keydown, keypress, beforeinput, textInput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
6: { 'Details': '{ code: Enter, which: 13 }', Typed: '{enter}', 'Events Fired': `keydown, keypress, beforeinput, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
7: { 'Details': '{ code: KeyB, which: 66 }', Typed: 'b', 'Events Fired': `keydown, keypress, beforeinput, textInput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
8: { 'Details': '{ code: ArrowLeft, which: 37 }', Typed: '{leftarrow}', 'Events Fired': 'keydown, keyup', 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
9: { 'Details': '{ code: Delete, which: 46 }', Typed: '{del}', 'Events Fired': `keydown, ${beforeInput}input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
10: { 'Details': '{ code: Enter, which: 13 }', Typed: '{enter}', 'Events Fired': `keydown, keypress, ${beforeInput}keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
9: { 'Details': '{ code: Delete, which: 46 }', Typed: '{del}', 'Events Fired': `keydown, beforeinput, input, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
10: { 'Details': '{ code: Enter, which: 13 }', Typed: '{enter}', 'Events Fired': `keydown, keypress, beforeinput, keyup`, 'Active Modifiers': 'alt, meta', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
11: { 'Details': '{ code: MetaLeft, which: 91 }', Typed: '{cmd}', 'Events Fired': 'keyup', 'Active Modifiers': 'alt', 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
12: { 'Details': '{ code: AltLeft, which: 18 }', Typed: '{option}', 'Events Fired': 'keyup', 'Active Modifiers': null, 'Prevented Default': null, 'Target Element': $input[0] },
|
||||
}
|
||||
@@ -3513,10 +3487,8 @@ describe('src/cy/commands/actions/type - #type', () => {
|
||||
cy.get(':text:first').type('f').then(function ($el) {
|
||||
const table = this.lastLog.invoke('consoleProps').table[2]()
|
||||
|
||||
const beforeInput = isChromium ? 'beforeinput, ' : ''
|
||||
|
||||
expect(table.data).to.deep.eq({
|
||||
1: { Typed: 'f', 'Events Fired': `keydown, keypress, ${beforeInput}textInput, input, keyup`, 'Active Modifiers': null, Details: '{ code: KeyF, which: 70 }', 'Prevented Default': null, 'Target Element': $el[0] },
|
||||
1: { Typed: 'f', 'Events Fired': `keydown, keypress, beforeinput, textInput, input, keyup`, 'Active Modifiers': null, Details: '{ code: KeyF, which: 70 }', 'Prevented Default': null, 'Target Element': $el[0] },
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1197,6 +1197,20 @@ describe('src/cy/commands/assertions', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('escape markdown', () => {
|
||||
// https://github.com/cypress-io/cypress/issues/17357
|
||||
it('images', (done) => {
|
||||
const text = 'hello world '
|
||||
const result = 'hello world ````'
|
||||
|
||||
expectMarkdown(
|
||||
() => expect(text).to.equal(text),
|
||||
`expected **${result}** to equal **${result}**`,
|
||||
done,
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('chai overrides', () => {
|
||||
|
||||
@@ -30,6 +30,15 @@ describe('src/cy/commands/location', () => {
|
||||
cy.url().should('include', '/baz.html')
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/17399
|
||||
it('url decode option', () => {
|
||||
// encodeURI() is used below because we cannot visit the site without it.
|
||||
// For the curious, 사랑 means "love" in Korean.
|
||||
cy.visit(encodeURI('/custom-headers?x=사랑'))
|
||||
|
||||
cy.url({ decode: true }).should('contain', '사랑')
|
||||
})
|
||||
|
||||
describe('assertion verification', () => {
|
||||
beforeEach(function () {
|
||||
cy.on('log:added', (attrs, log) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getDisplayUrlMatcher } from '@packages/driver/src/cy/net-stubbing/route-matcher-log'
|
||||
import { RouteMatcherOptions } from '@packages/net-stubbing/lib/external-types'
|
||||
import type { RouteMatcherOptions } from '@packages/net-stubbing/lib/external-types'
|
||||
|
||||
const testFail = (cb, expectedDocsUrl = 'https://on.cypress.io/intercept') => {
|
||||
cy.on('fail', (err) => {
|
||||
@@ -1638,12 +1638,10 @@ describe('network stubbing', { retries: 2 }, function () {
|
||||
delay: 5000,
|
||||
}).as('create')
|
||||
|
||||
cy.window().then((win) => {
|
||||
win.eval(
|
||||
`fetch("/post-only", {
|
||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||
});`,
|
||||
)
|
||||
cy.then(() => {
|
||||
fetch('/post-only', {
|
||||
method: 'POST', // *GET, POST, PUT, DELETE, etc.
|
||||
})
|
||||
})
|
||||
|
||||
cy.wait('@create', { timeout: 500 })
|
||||
@@ -2127,6 +2125,61 @@ describe('network stubbing', { retries: 2 }, function () {
|
||||
cy.get('#request').click()
|
||||
cy.get('#result').should('contain', 'client')
|
||||
})
|
||||
|
||||
it('works with reply', () => {
|
||||
cy.intercept({
|
||||
method: 'POST',
|
||||
times: 1,
|
||||
url: '/post-only',
|
||||
},
|
||||
(req) => {
|
||||
req.reply('stubbed data')
|
||||
}).as('interceptor')
|
||||
|
||||
cy.visit('fixtures/request.html')
|
||||
|
||||
cy.get('#request').click()
|
||||
cy.get('#result').should('contain', 'stubbed data')
|
||||
|
||||
cy.get('#request').click()
|
||||
cy.get('#result').should('contain', 'client')
|
||||
})
|
||||
|
||||
it('works with reply and fallthrough', () => {
|
||||
let times = 0
|
||||
|
||||
cy.intercept({
|
||||
method: 'POST',
|
||||
times: 3,
|
||||
url: '/post-only',
|
||||
},
|
||||
(req) => {
|
||||
req.reply(`${req.body === 'foo' ? 'foo' : 'nothing'} stubbed data ${times++}`)
|
||||
})
|
||||
|
||||
cy.intercept({
|
||||
method: 'POST',
|
||||
times: 2,
|
||||
url: '/post-only',
|
||||
},
|
||||
(req) => {
|
||||
req.body = 'foo'
|
||||
})
|
||||
|
||||
cy.visit('fixtures/request.html')
|
||||
|
||||
cy.get('#request').click()
|
||||
cy.get('#result').should('contain', 'foo stubbed data 0')
|
||||
|
||||
cy.get('#request').click()
|
||||
cy.get('#result').should('contain', 'foo stubbed data 1')
|
||||
|
||||
cy.get('#request').click()
|
||||
cy.get('#result').should('contain', 'nothing stubbed data 2')
|
||||
|
||||
cy.get('#request').click()
|
||||
cy.get('#result').should('contain', 'client')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -2628,6 +2681,31 @@ describe('network stubbing', { retries: 2 }, function () {
|
||||
.wait('@get')
|
||||
})
|
||||
|
||||
// https://github.com/cypress-io/cypress/issues/17084
|
||||
it('does not overwrite the json-related content-type header', () => {
|
||||
cy.intercept('/json-content-type', (req) => {
|
||||
req.on('response', (res) => {
|
||||
res.send({
|
||||
statusCode: 500,
|
||||
headers: {
|
||||
'content-type': 'application/problem+json',
|
||||
'access-control-allow-origin': '*',
|
||||
},
|
||||
body: {
|
||||
status: 500,
|
||||
title: 'Internal Server Error',
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
return fetch('/json-content-type')
|
||||
.then((res) => {
|
||||
expect(res.headers.get('content-type')).to.eq('application/problem+json')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('body parsing', function () {
|
||||
[
|
||||
'application/json',
|
||||
@@ -3049,7 +3127,7 @@ describe('network stubbing', { retries: 2 }, function () {
|
||||
})
|
||||
})
|
||||
|
||||
context('waiting and aliasing', function () {
|
||||
context('waiting and aliasing', { defaultCommandTimeout: 10000 }, function () {
|
||||
const testFailWaiting = (cb) => testFail(cb, 'https://on.cypress.io/wait')
|
||||
|
||||
it('can wait on a single response using "alias"', function () {
|
||||
|
||||
@@ -735,7 +735,7 @@ describe('src/cy/commands/waiting', () => {
|
||||
cy.wait('@foo', '@bar')
|
||||
})
|
||||
|
||||
it('throws when passed caallback function', (done) => {
|
||||
it('throws when passed callback function', (done) => {
|
||||
cy.on('fail', (err) => {
|
||||
expect(err.message).to.eq('`cy.wait()` was passed invalid arguments. You cannot pass a function. If you would like to wait on the result of a `cy.wait()`, use `cy.then()`.')
|
||||
expect(err.docsUrl).to.eq('https://on.cypress.io/wait')
|
||||
|
||||
@@ -1026,14 +1026,25 @@ describe('src/cy/commands/xhr', () => {
|
||||
})
|
||||
|
||||
it('sets err on log when caused by code errors', function (done) {
|
||||
cy.on('fail', (err) => {
|
||||
done = _.once(done)
|
||||
cy.once('fail', (err) => {
|
||||
// suppress failure
|
||||
})
|
||||
|
||||
cy.on('log:changed', () => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('name')).to.eq('request')
|
||||
expect(lastLog.get('error').message).contain('foo is not defined')
|
||||
if (!lastLog || lastLog.get('name') !== 'request') return
|
||||
|
||||
done()
|
||||
try {
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('error').message).contain('foo is not defined')
|
||||
|
||||
done()
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('assertion failure', err)
|
||||
}
|
||||
})
|
||||
|
||||
cy.window().then((win) => {
|
||||
@@ -1047,17 +1058,27 @@ describe('src/cy/commands/xhr', () => {
|
||||
})
|
||||
|
||||
it('causes errors caused by onreadystatechange callback function', function (done) {
|
||||
done = _.once(done)
|
||||
const e = new Error('onreadystatechange caused this error')
|
||||
|
||||
cy.on('fail', (err) => {
|
||||
cy.once('fail', (err) => {
|
||||
// suppress failure
|
||||
})
|
||||
|
||||
cy.on('log:changed', () => {
|
||||
const { lastLog } = this
|
||||
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('name')).to.eq('request')
|
||||
expect(err.message).to.include(lastLog.get('error').message)
|
||||
expect(err.message).to.include(e.message)
|
||||
if (!lastLog || lastLog.get('name') !== 'request') return
|
||||
|
||||
done()
|
||||
try {
|
||||
expect(this.logs.length).to.eq(1)
|
||||
expect(lastLog.get('name')).to.eq('request')
|
||||
expect(e.message).to.include(lastLog.get('error').message)
|
||||
done()
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('assertion failure', err)
|
||||
}
|
||||
})
|
||||
|
||||
cy
|
||||
@@ -2563,7 +2584,9 @@ describe('src/cy/commands/xhr', () => {
|
||||
|
||||
xhr.open('GET', '/timeout?ms=999')
|
||||
xhr.send()
|
||||
xhr.abort()
|
||||
|
||||
// allow the request time to make it out of the browser so proxy logging has a chance to see it
|
||||
requestAnimationFrame(() => xhr.abort())
|
||||
|
||||
cy.wrap(null).should(() => {
|
||||
expect(log.get('state')).to.eq('failed')
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const { $ } = Cypress
|
||||
const $SnapshotsCss = require('../../../src/cy/snapshots_css')
|
||||
const $SnapshotsCss = require('../../../src/cy/snapshots_css').default
|
||||
|
||||
const normalizeStyles = (styles) => {
|
||||
return styles
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const browserProps = require('@packages/driver/src/cypress/browser')
|
||||
import browserProps from '@packages/driver/src/cypress/browser'
|
||||
|
||||
describe('src/cypress/browser', () => {
|
||||
beforeEach(function () {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user