diff --git a/circle.yml b/circle.yml index 17b91e86be..32efdaa287 100644 --- a/circle.yml +++ b/circle.yml @@ -1195,6 +1195,7 @@ jobs: desktop-gui-component-tests: <<: *defaults + resource_class: medium parallelism: 1 steps: - restore_cached_workspace diff --git a/packages/driver/cypress/integration/commands/net_stubbing_spec.ts b/packages/driver/cypress/integration/commands/net_stubbing_spec.ts index f6ad3dd45a..599174dcc2 100644 --- a/packages/driver/cypress/integration/commands/net_stubbing_spec.ts +++ b/packages/driver/cypress/integration/commands/net_stubbing_spec.ts @@ -680,6 +680,38 @@ describe('network stubbing', { retries: { runMode: 2, openMode: 0 } }, function cy.intercept('/foo', { middleware: true }) }) + context('with an unexpected number of arguments', function () { + it('cy.intercept(url, handler?)', function (done) { + testFail((err) => { + expect(err.message).to.include('The `cy.intercept(url, handler?)` signature accepts a maximum of 2 arguments, but 3 arguments were passed.') + done() + }) + + // @ts-ignore + cy.intercept('/url', { forceNetworkError: true }, () => {}) + }) + + it('cy.intercept(url, mergeRouteMatcher, handler)', function (done) { + testFail((err) => { + expect(err.message).to.include('The `cy.intercept(url, mergeRouteMatcher, handler)` signature accepts a maximum of 3 arguments, but 4 arguments were passed.') + done() + }) + + // @ts-ignore + cy.intercept('/url', { middleware: true }, { forceNetworkError: true }, () => {}) + }) + + it('cy.intercept(method, url, handler?)', function (done) { + testFail((err) => { + expect(err.message).to.include('The `cy.intercept(method, url, handler?)` signature accepts a maximum of 3 arguments, but 4 arguments were passed.') + done() + }) + + // @ts-ignore + cy.intercept('POST', '/url', { forceNetworkError: true }, () => {}) + }) + }) + context('with invalid RouteMatcher', function () { it('requires unique header names', function (done) { testFail((err) => { @@ -737,7 +769,7 @@ describe('network stubbing', { retries: { runMode: 2, openMode: 0 } }, function }) it('times must be a positive integer', function (done) { - cy.on('fail', function (err) { + testFail((err) => { expect(err.message).to.include('`times` must be a positive integer.') done() }) @@ -745,6 +777,15 @@ describe('network stubbing', { retries: { runMode: 2, openMode: 0 } }, function cy .intercept({ times: 9.75 }) }) + + it('string hostname must be a valid domain name', function (done) { + testFail((err) => { + expect(err.message).to.include('`hostname` must be a valid host name or domain name.') + done() + }) + + cy.intercept({ hostname: 'http://website.web' }) + }) }) context('with invalid handler', function () { diff --git a/packages/driver/package.json b/packages/driver/package.json index 176d64fcab..c254ef88cf 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -47,6 +47,7 @@ "errorhandler": "1.5.1", "eventemitter2": "6.4.2", "express": "4.17.1", + "is-valid-domain": "0.0.19", "jquery": "3.1.1", "jquery.scrollto": "2.1.3", "js-cookie": "2.2.1", diff --git a/packages/driver/src/cy/net-stubbing/add-command.ts b/packages/driver/src/cy/net-stubbing/add-command.ts index d6f6c62700..bbb7a2886d 100644 --- a/packages/driver/src/cy/net-stubbing/add-command.ts +++ b/packages/driver/src/cy/net-stubbing/add-command.ts @@ -26,6 +26,7 @@ import { import { registerEvents } from './events' import $errUtils from '../../cypress/error_utils' import $utils from '../../cypress/utils' +import isValidDomain from 'is-valid-domain' const lowercaseFieldNames = (headers: { [fieldName: string]: any }) => _.mapKeys(headers, (v, k) => _.toLower(k)) @@ -129,6 +130,10 @@ function validateRouteMatcherOptions (routeMatcher: RouteMatcherOptions): { isVa } } + if (_.isString(routeMatcher.hostname) && !isValidDomain(routeMatcher.hostname, { allowUnicode: true })) { + return err('`hostname` must be a valid host name or domain name.') + } + if (_.has(routeMatcher, 'port') && !isNumberMatcher(routeMatcher.port)) { return err('`port` must be a number or a list of numbers.') } @@ -234,6 +239,17 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, } function intercept (matcher: RouteMatcher, handler?: RouteHandler | StringMatcher | RouteMatcherOptions, arg2?: RouteHandler) { + const checkExtraArguments = (overload: string[]) => { + if (arguments.length > overload.length) { + $errUtils.throwErrByPath('net_stubbing.intercept.extra_arguments', { + args: { + overload, + argsLength: arguments.length, + }, + }) + } + } + function getMatcherOptions (): RouteMatcherOptions { if (isStringMatcher(matcher) && hasOnlyRouteMatcherKeys(handler)) { // url, mergeRouteMatcher, handler @@ -246,6 +262,8 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, return $errUtils.throwErrByPath('net_stubbing.intercept.handler_required') } + checkExtraArguments(['url', 'mergeRouteMatcher', 'handler']) + const opts = { url: matcher, ...handler as RouteMatcherOptions, @@ -262,6 +280,8 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, handler = arg2 + checkExtraArguments(['method', 'url', 'handler?']) + return { method: matcher, url, @@ -270,6 +290,8 @@ export function addCommand (Commands, Cypress: Cypress.Cypress, cy: Cypress.cy, if (isStringMatcher(matcher)) { // url, handler? + checkExtraArguments(['url', 'handler?']) + return { url: matcher, } diff --git a/packages/driver/src/cypress/error_messages.js b/packages/driver/src/cypress/error_messages.js index 1e2ea10048..25ea198ff5 100644 --- a/packages/driver/src/cypress/error_messages.js +++ b/packages/driver/src/cypress/error_messages.js @@ -931,23 +931,29 @@ module.exports = { You passed: ${format(staticResponse)}`, 8) }, intercept: { + extra_arguments: ({ argsLength, overload }) => { + return cyStripIndent(`\ + The ${cmd('intercept', overload.join(', '))} signature accepts a maximum of ${overload.length} arguments, but ${argsLength} arguments were passed. + + Please refer to the docs for all accepted signatures for ${cmd('intercept')}.`, 10) + }, invalid_handler: ({ handler }) => { - return stripIndent`\ + return cyStripIndent(`\ ${cmd('intercept')}'s \`handler\` argument must be a String, StaticResponse, or HttpController function. - You passed: ${format(handler)}` + You passed: ${format(handler)}`, 10) }, invalid_middleware_handler: ({ handler }) => { - return stripIndent`\ + return cyStripIndent(`\ ${cmd('intercept')}'s \`handler\` argument must be an HttpController function when \`middleware\` is set to \`true\`. - You passed: ${format(handler)}` + You passed: ${format(handler)}`, 10) }, invalid_route_matcher: ({ message, matcher }) => { - return stripIndent`\ + return cyStripIndent(`\ An invalid RouteMatcher was supplied to ${cmd('intercept')}. ${message} - You passed: ${format(matcher)}` + You passed: ${format(matcher)}`, 10) }, no_duplicate_url: `When invoking ${cmd('intercept')} with a \`RouteMatcher\` as the second parameter, \`url\` can only be specified as the first parameter.`, handler_required: `When invoking ${cmd('intercept')} with a \`RouteMatcher\` as the second parameter, a handler (function or \`StaticResponse\`) must be specified as the third parameter. If you intended to stub out a response body by passing an object as the 2nd parameter, pass an object with a \`body\` property containing the desired response body instead.`, diff --git a/yarn.lock b/yarn.lock index 398c359e99..65c06f8f5d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22873,6 +22873,13 @@ is-utf8@^0.2.0, is-utf8@^0.2.1: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= +is-valid-domain@0.0.19: + version "0.0.19" + resolved "https://registry.npmjs.org/is-valid-domain/-/is-valid-domain-0.0.19.tgz#50ce5ff3ab1cbe85bcb5b155b0fba61f4b9ea668" + integrity sha512-NxuZbJABXdGlFNEVphG9bT0YOQE0B75Bv+emGsEjmRnAs9aMUVbdKUafj//yTxApThjqQqRKBd9MJDlnqx8Pmg== + dependencies: + punycode "^1.4.1" + is-valid-glob@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe" @@ -31369,11 +31376,16 @@ pumpify@1.5.1, pumpify@^1.3.3, pumpify@^1.3.5: inherits "^2.0.3" pump "^2.0.0" -punycode@1.3.2, punycode@^1.2.4, punycode@^1.3.2: +punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= +punycode@^1.2.4, punycode@^1.3.2, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"