From c052f44ec8b3192efe804fe08ebca14337e55915 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 6 Jun 2019 16:04:29 -0400 Subject: [PATCH 01/18] use a parser that supports circular json --- packages/extension/app/background.coffee | 7 ++++++- packages/runner/src/lib/event-manager.js | 1 + packages/server/lib/socket.coffee | 1 + packages/server/test/integration/websockets_spec.coffee | 3 +++ packages/socket/lib/client.js | 4 ++++ packages/socket/lib/socket.js | 3 +++ packages/socket/package.json | 5 +++-- 7 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/extension/app/background.coffee b/packages/extension/app/background.coffee index 296bb6972c03..ac7e4f525e8a 100644 --- a/packages/extension/app/background.coffee +++ b/packages/extension/app/background.coffee @@ -2,6 +2,7 @@ map = require("lodash/map") pick = require("lodash/pick") once = require("lodash/once") Promise = require("bluebird") +{ circularParser } = require("@packages/socket") HOST = "CHANGE_ME_HOST" PATH = "CHANGE_ME_PATH" @@ -41,7 +42,11 @@ connect = (host, path, io) -> ## cannot use required socket here due ## to bug in socket io client with browserify - client = io.connect(host, {path: path, transports: ["websocket"]}) + client = io.connect(host, { + path: path, + transports: ["websocket"] + parser: circularParser + }) client.on "automation:request", (id, msg, data) -> switch msg diff --git a/packages/runner/src/lib/event-manager.js b/packages/runner/src/lib/event-manager.js index d449e67c037b..618d2408df51 100644 --- a/packages/runner/src/lib/event-manager.js +++ b/packages/runner/src/lib/event-manager.js @@ -12,6 +12,7 @@ import $Cypress, { $ } from '@packages/driver' const channel = io.connect({ path: '/__socket.io', transports: ['websocket'], + parser: io.circularParser, }) channel.on('connect', () => { diff --git a/packages/server/lib/socket.coffee b/packages/server/lib/socket.coffee index ee662ade0b78..af47a7df876d 100644 --- a/packages/server/lib/socket.coffee +++ b/packages/server/lib/socket.coffee @@ -124,6 +124,7 @@ class Socket destroyUpgrade: false serveClient: false cookie: cookie + parser: socketIo.circularParser }) startListening: (server, automation, config, options) -> diff --git a/packages/server/test/integration/websockets_spec.coffee b/packages/server/test/integration/websockets_spec.coffee index 7668c5df4dcf..fc933f3b7968 100644 --- a/packages/server/test/integration/websockets_spec.coffee +++ b/packages/server/test/integration/websockets_spec.coffee @@ -175,6 +175,7 @@ describe "Web Sockets", -> @wsClient = socketIo.client(@cfg.proxyUrl, { path: @cfg.socketIoRoute transports: ["websocket"] + parser: socketIo.circularParser }) @wsClient.on "connect", -> done() @@ -197,6 +198,7 @@ describe "Web Sockets", -> agent: agent path: @cfg.socketIoRoute transports: ["websocket"] + parser: socketIo.circularParser }) @wsClient.on "connect", -> done() @@ -220,6 +222,7 @@ describe "Web Sockets", -> @wsClient = socketIo.client("https://localhost:#{wssPort}", { agent: agent path: @cfg.socketIoRoute + parser: socketIo.circularParser }) @wsClient.on "connect", -> done() diff --git a/packages/socket/lib/client.js b/packages/socket/lib/client.js index e13ac9d1b45d..467bad9146f7 100644 --- a/packages/socket/lib/client.js +++ b/packages/socket/lib/client.js @@ -1 +1,5 @@ +const circularParser = require('socket.io-circular-parser') + module.exports = require('socket.io-client') + +module.exports.circularParser = circularParser diff --git a/packages/socket/lib/socket.js b/packages/socket/lib/socket.js index 7eff210b2d72..371e2c6c2375 100644 --- a/packages/socket/lib/socket.js +++ b/packages/socket/lib/socket.js @@ -4,12 +4,15 @@ const server = require('socket.io') const version = require('socket.io-client/package.json').version const clientPath = require.resolve('socket.io-client') const client = require('./client') +const circularParser = require('socket.io-circular-parser') module.exports = { server, client, + circularParser, + getPathToClientSource () { // clientPath returns the path to socket.io-client/lib/index.js // so walk up two levels to get to the root diff --git a/packages/socket/package.json b/packages/socket/package.json index a74615514b86..945020c05e0d 100644 --- a/packages/socket/package.json +++ b/packages/socket/package.json @@ -17,8 +17,9 @@ "lib" ], "dependencies": { - "socket.io": "1.7.4", - "socket.io-client": "1.7.4" + "socket.io": "2.2.0", + "socket.io-circular-parser": "3.1.2", + "socket.io-client": "2.2.0" }, "devDependencies": { "bin-up": "1.2.0", From ed0e3678541a53e5743608a08e95bbb58b7b544e Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 6 Jun 2019 16:35:38 -0400 Subject: [PATCH 02/18] update tests to work with new socketio version --- packages/network/test/support/servers.ts | 7 +++++-- packages/network/test/unit/agent_spec.ts | 10 ++++++---- .../server/test/integration/websockets_spec.coffee | 3 +++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/network/test/support/servers.ts b/packages/network/test/support/servers.ts index de12fdba407d..340cdc607c00 100644 --- a/packages/network/test/support/servers.ts +++ b/packages/network/test/support/servers.ts @@ -14,13 +14,16 @@ export interface AsyncServer { function addDestroy(server: http.Server | https.Server) { let connections = [] - server.on('connection', function(conn) { + function trackConn(conn) { connections.push(conn) conn.on('close', () => { connections = connections.filter(connection => connection !== conn) }) - }) + } + + server.on('connection', trackConn) + server.on('secureConnection', trackConn) // @ts-ignore Property 'destroy' does not exist on type 'Server'. server.destroy = function(cb) { diff --git a/packages/network/test/unit/agent_spec.ts b/packages/network/test/unit/agent_spec.ts index 687c53d1f398..99dd08cf92e5 100644 --- a/packages/network/test/unit/agent_spec.ts +++ b/packages/network/test/unit/agent_spec.ts @@ -1,6 +1,5 @@ import Bluebird from 'bluebird' import chai from 'chai' -import { EventEmitter } from 'events' import http from 'http' import https from 'https' import net from 'net' @@ -175,7 +174,8 @@ describe('lib/agent', function() { return new Bluebird((resolve) => { Io.client(`http://localhost:${HTTP_PORT}`, { agent: this.agent, - transports: ['websocket'] + transports: ['websocket'], + rejectUnauthorized: false }).on('message', resolve) }) .then(msg => { @@ -191,7 +191,8 @@ describe('lib/agent', function() { return new Bluebird((resolve) => { Io.client(`https://localhost:${HTTPS_PORT}`, { agent: this.agent, - transports: ['websocket'] + transports: ['websocket'], + rejectUnauthorized: false }).on('message', resolve) }) .then(msg => { @@ -357,7 +358,8 @@ describe('lib/agent', function() { Io.client(`${testCase.protocol}://foo.bar.baz.invalid`, { agent: testCase.agent, transports: ['websocket'], - timeout: 1 + timeout: 1, + rejectUnauthorized: false }) .on('message', reject) .on('connect_error', resolve) diff --git a/packages/server/test/integration/websockets_spec.coffee b/packages/server/test/integration/websockets_spec.coffee index fc933f3b7968..4af3f0431d7c 100644 --- a/packages/server/test/integration/websockets_spec.coffee +++ b/packages/server/test/integration/websockets_spec.coffee @@ -176,6 +176,7 @@ describe "Web Sockets", -> path: @cfg.socketIoRoute transports: ["websocket"] parser: socketIo.circularParser + rejectUnauthorized: false }) @wsClient.on "connect", -> done() @@ -199,6 +200,7 @@ describe "Web Sockets", -> path: @cfg.socketIoRoute transports: ["websocket"] parser: socketIo.circularParser + rejectUnauthorized: false }) @wsClient.on "connect", -> done() @@ -223,6 +225,7 @@ describe "Web Sockets", -> agent: agent path: @cfg.socketIoRoute parser: socketIo.circularParser + rejectUnauthorized: false }) @wsClient.on "connect", -> done() From 27b716cde4aaebffac10d30e0d265c92e23b34a0 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 6 Jun 2019 17:24:28 -0400 Subject: [PATCH 03/18] add error message when users supply circular body to visit/request --- packages/driver/package.json | 1 + .../driver/src/cy/commands/navigation.coffee | 4 +++ .../driver/src/cy/commands/request.coffee | 4 +++ .../driver/src/cypress/error_messages.coffee | 10 ++++++++ .../commands/navigation_spec.coffee | 25 +++++++++++++++++++ .../integration/commands/request_spec.coffee | 25 +++++++++++++++++++ 6 files changed, 69 insertions(+) diff --git a/packages/driver/package.json b/packages/driver/package.json index 70be2563029f..ca87d838864b 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -43,6 +43,7 @@ "jquery.scrollto": "2.1.2", "js-cookie": "2.2.0", "jsdom": "13.2.0", + "just-is-circular": "1.1.0", "lodash": "4.17.11", "lolex": "4.1.0", "methods": "1.1.2", diff --git a/packages/driver/src/cy/commands/navigation.coffee b/packages/driver/src/cy/commands/navigation.coffee index 3658b8453f89..7e9117e42bcd 100644 --- a/packages/driver/src/cy/commands/navigation.coffee +++ b/packages/driver/src/cy/commands/navigation.coffee @@ -1,4 +1,5 @@ _ = require("lodash") +isCircular = require("just-is-circular") moment = require("moment") UrlParse = require("url-parse") Promise = require("bluebird") @@ -522,6 +523,9 @@ module.exports = (Commands, Cypress, cy, state, config) -> if not _.isObject(options.headers) $utils.throwErrByPath("visit.invalid_headers") + if _.isObject(options.body) and isCircular(options.body) + $utils.throwErrByPath("visit.body_circular") + if options.log message = url diff --git a/packages/driver/src/cy/commands/request.coffee b/packages/driver/src/cy/commands/request.coffee index ea2db52d7db1..dc7a339cb25e 100644 --- a/packages/driver/src/cy/commands/request.coffee +++ b/packages/driver/src/cy/commands/request.coffee @@ -1,4 +1,5 @@ _ = require("lodash") +isCircular = require("just-is-circular") Promise = require("bluebird") $utils = require("../../cypress/utils") @@ -137,6 +138,9 @@ module.exports = (Commands, Cypress, cy, state, config) -> if needsFormSpecified(options) options.form = true + if _.isObject(options.body) and isCircular(options.body) + $utils.throwErrByPath("request.body_circular") + ## only set json to true if form isnt true ## and we have a valid object for body if options.form isnt true and isValidJsonObj(options.body) diff --git a/packages/driver/src/cypress/error_messages.coffee b/packages/driver/src/cypress/error_messages.coffee index 16d26dea288c..9f21f07a4ee4 100644 --- a/packages/driver/src/cypress/error_messages.coffee +++ b/packages/driver/src/cypress/error_messages.coffee @@ -593,6 +593,11 @@ module.exports = { invalid_arguments: "#{cmd('reload')} can only accept a boolean or options as its arguments." request: + body_circular: """ + The `body` parameter supplied to #{cmd('request')} contained a circular reference. + + `body` can only be a string or an object with no circular references. + """ status_code_flags_invalid: """ #{cmd('request')} was invoked with { failOnStatusCode: false, retryOnStatusCodeFailure: true }. @@ -931,6 +936,11 @@ module.exports = { missing_preset: "#{cmd('viewport')} could not find a preset for: '{{preset}}'. Available presets are: {{presets}}" visit: + body_circular: """ + The `body` parameter supplied to #{cmd('visit')} contained a circular reference. + + `body` can only be a string or an object with no circular references. + """ status_code_flags_invalid: """ #{cmd('visit')} was invoked with { failOnStatusCode: false, retryOnStatusCodeFailure: true }. diff --git a/packages/driver/test/cypress/integration/commands/navigation_spec.coffee b/packages/driver/test/cypress/integration/commands/navigation_spec.coffee index f1c9d0a08048..8326300bc0ee 100644 --- a/packages/driver/test/cypress/integration/commands/navigation_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/navigation_spec.coffee @@ -1455,6 +1455,31 @@ describe "src/cy/commands/navigation", -> cy.visit("https://google.com/foo") + it "displays body_circular when body is circular", (done) -> + c = {} + c.c = c + + cy.visit({ + method: "POST" + url: "http://foo.invalid/" + body: { + c + } + }) + + cy.on "fail", (err) => + lastLog = @lastLog + expect(@logs.length).to.eq(1) + expect(lastLog.get("error")).to.eq(err) + expect(lastLog.get("state")).to.eq("failed") + expect(err.message).to.eq """ + The `body` parameter supplied to cy.visit() contained a circular reference. + + `body` can only be a string or an object with no circular references. + """ + + done() + context "#page load", -> it "sets initial=true and then removes", -> Cookie.remove("__cypress.initial") diff --git a/packages/driver/test/cypress/integration/commands/request_spec.coffee b/packages/driver/test/cypress/integration/commands/request_spec.coffee index bcb79f7f51d7..2dffa5e8640b 100644 --- a/packages/driver/test/cypress/integration/commands/request_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/request_spec.coffee @@ -751,6 +751,31 @@ describe "src/cy/commands/request", -> } }) + it "displays body_circular when body is circular", (done) -> + c = {} + c.c = c + + cy.request({ + method: "POST" + url: "http://foo.invalid/" + body: { + c + } + }) + + cy.on "fail", (err) => + lastLog = @lastLog + expect(@logs.length).to.eq(1) + expect(lastLog.get("error")).to.eq(err) + expect(lastLog.get("state")).to.eq("failed") + expect(err.message).to.eq """ + The `body` parameter supplied to cy.request() contained a circular reference. + + `body` can only be a string or an object with no circular references. + """ + + done() + it "does not include redirects when there were no redirects", (done) -> backend = Cypress.backend .withArgs("http:request") From 05a4247cdc302a8a765d35dd5fdfb5eef03ea309 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Wed, 12 Jun 2019 13:43:07 -0400 Subject: [PATCH 04/18] show the path of the circular reference detected --- packages/driver/package.json | 2 +- packages/driver/src/cy/commands/navigation.coffee | 6 +++--- packages/driver/src/cy/commands/request.coffee | 6 +++--- packages/driver/src/cypress/error_messages.coffee | 8 ++++---- .../integration/commands/navigation_spec.coffee | 15 +++++++++------ .../integration/commands/request_spec.coffee | 15 +++++++++------ 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/packages/driver/package.json b/packages/driver/package.json index ca87d838864b..d46f872a1655 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -43,7 +43,6 @@ "jquery.scrollto": "2.1.2", "js-cookie": "2.2.0", "jsdom": "13.2.0", - "just-is-circular": "1.1.0", "lodash": "4.17.11", "lolex": "4.1.0", "methods": "1.1.2", @@ -63,6 +62,7 @@ "url-parse": "1.4.7", "vanilla-text-mask": "5.1.1", "wait-on": "3.2.0", + "what-is-circular": "1.0.0", "zone.js": "0.9.0" } } diff --git a/packages/driver/src/cy/commands/navigation.coffee b/packages/driver/src/cy/commands/navigation.coffee index 7e9117e42bcd..89ae27da30b5 100644 --- a/packages/driver/src/cy/commands/navigation.coffee +++ b/packages/driver/src/cy/commands/navigation.coffee @@ -1,5 +1,5 @@ _ = require("lodash") -isCircular = require("just-is-circular") +whatIsCircular = require("what-is-circular") moment = require("moment") UrlParse = require("url-parse") Promise = require("bluebird") @@ -523,8 +523,8 @@ module.exports = (Commands, Cypress, cy, state, config) -> if not _.isObject(options.headers) $utils.throwErrByPath("visit.invalid_headers") - if _.isObject(options.body) and isCircular(options.body) - $utils.throwErrByPath("visit.body_circular") + if _.isObject(options.body) and path = whatIsCircular(options.body) + $utils.throwErrByPath("visit.body_circular", { args: { path }}) if options.log message = url diff --git a/packages/driver/src/cy/commands/request.coffee b/packages/driver/src/cy/commands/request.coffee index dc7a339cb25e..45ad4fac9fa0 100644 --- a/packages/driver/src/cy/commands/request.coffee +++ b/packages/driver/src/cy/commands/request.coffee @@ -1,5 +1,5 @@ _ = require("lodash") -isCircular = require("just-is-circular") +whatIsCircular = require("what-is-circular") Promise = require("bluebird") $utils = require("../../cypress/utils") @@ -138,8 +138,8 @@ module.exports = (Commands, Cypress, cy, state, config) -> if needsFormSpecified(options) options.form = true - if _.isObject(options.body) and isCircular(options.body) - $utils.throwErrByPath("request.body_circular") + if _.isObject(options.body) and path = whatIsCircular(options.body) + $utils.throwErrByPath("request.body_circular", { args: { path }}) ## only set json to true if form isnt true ## and we have a valid object for body diff --git a/packages/driver/src/cypress/error_messages.coffee b/packages/driver/src/cypress/error_messages.coffee index 9f21f07a4ee4..be3165755d7a 100644 --- a/packages/driver/src/cypress/error_messages.coffee +++ b/packages/driver/src/cypress/error_messages.coffee @@ -593,8 +593,8 @@ module.exports = { invalid_arguments: "#{cmd('reload')} can only accept a boolean or options as its arguments." request: - body_circular: """ - The `body` parameter supplied to #{cmd('request')} contained a circular reference. + body_circular: ({ path }) -> """ + The `body` parameter supplied to #{cmd('request')} contained a circular reference at the path "#{path.join(".")}". `body` can only be a string or an object with no circular references. """ @@ -936,8 +936,8 @@ module.exports = { missing_preset: "#{cmd('viewport')} could not find a preset for: '{{preset}}'. Available presets are: {{presets}}" visit: - body_circular: """ - The `body` parameter supplied to #{cmd('visit')} contained a circular reference. + body_circular: ({ path }) -> """ + The `body` parameter supplied to #{cmd('visit')} contained a circular reference at the path "#{path.join(".")}". `body` can only be a string or an object with no circular references. """ diff --git a/packages/driver/test/cypress/integration/commands/navigation_spec.coffee b/packages/driver/test/cypress/integration/commands/navigation_spec.coffee index 8326300bc0ee..833b3728114d 100644 --- a/packages/driver/test/cypress/integration/commands/navigation_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/navigation_spec.coffee @@ -1456,15 +1456,18 @@ describe "src/cy/commands/navigation", -> cy.visit("https://google.com/foo") it "displays body_circular when body is circular", (done) -> - c = {} - c.c = c + foo = { + bar: { + baz: {} + } + } + + foo.bar.baz.quux = foo cy.visit({ method: "POST" url: "http://foo.invalid/" - body: { - c - } + body: foo }) cy.on "fail", (err) => @@ -1473,7 +1476,7 @@ describe "src/cy/commands/navigation", -> expect(lastLog.get("error")).to.eq(err) expect(lastLog.get("state")).to.eq("failed") expect(err.message).to.eq """ - The `body` parameter supplied to cy.visit() contained a circular reference. + The `body` parameter supplied to cy.visit() contained a circular reference at the path "bar.baz.quux". `body` can only be a string or an object with no circular references. """ diff --git a/packages/driver/test/cypress/integration/commands/request_spec.coffee b/packages/driver/test/cypress/integration/commands/request_spec.coffee index 2dffa5e8640b..c4aeecfbd029 100644 --- a/packages/driver/test/cypress/integration/commands/request_spec.coffee +++ b/packages/driver/test/cypress/integration/commands/request_spec.coffee @@ -752,15 +752,18 @@ describe "src/cy/commands/request", -> }) it "displays body_circular when body is circular", (done) -> - c = {} - c.c = c + foo = { + bar: { + baz: {} + } + } + + foo.bar.baz.quux = foo cy.request({ method: "POST" url: "http://foo.invalid/" - body: { - c - } + body: foo }) cy.on "fail", (err) => @@ -769,7 +772,7 @@ describe "src/cy/commands/request", -> expect(lastLog.get("error")).to.eq(err) expect(lastLog.get("state")).to.eq("failed") expect(err.message).to.eq """ - The `body` parameter supplied to cy.request() contained a circular reference. + The `body` parameter supplied to cy.request() contained a circular reference at the path "bar.baz.quux". `body` can only be a string or an object with no circular references. """ From 91c24aa628fc4afe65c166346d9051bcdec7c021 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Wed, 12 Jun 2019 14:05:33 -0400 Subject: [PATCH 05/18] Revert "use a parser that supports circular json" This reverts commit c052f44ec8b3192efe804fe08ebca14337e55915. --- packages/extension/app/background.coffee | 7 +------ packages/runner/src/lib/event-manager.js | 1 - packages/server/lib/socket.coffee | 1 - packages/server/test/integration/websockets_spec.coffee | 6 ------ packages/socket/lib/client.js | 4 ---- packages/socket/lib/socket.js | 3 --- packages/socket/package.json | 5 ++--- 7 files changed, 3 insertions(+), 24 deletions(-) diff --git a/packages/extension/app/background.coffee b/packages/extension/app/background.coffee index ac7e4f525e8a..296bb6972c03 100644 --- a/packages/extension/app/background.coffee +++ b/packages/extension/app/background.coffee @@ -2,7 +2,6 @@ map = require("lodash/map") pick = require("lodash/pick") once = require("lodash/once") Promise = require("bluebird") -{ circularParser } = require("@packages/socket") HOST = "CHANGE_ME_HOST" PATH = "CHANGE_ME_PATH" @@ -42,11 +41,7 @@ connect = (host, path, io) -> ## cannot use required socket here due ## to bug in socket io client with browserify - client = io.connect(host, { - path: path, - transports: ["websocket"] - parser: circularParser - }) + client = io.connect(host, {path: path, transports: ["websocket"]}) client.on "automation:request", (id, msg, data) -> switch msg diff --git a/packages/runner/src/lib/event-manager.js b/packages/runner/src/lib/event-manager.js index 618d2408df51..d449e67c037b 100644 --- a/packages/runner/src/lib/event-manager.js +++ b/packages/runner/src/lib/event-manager.js @@ -12,7 +12,6 @@ import $Cypress, { $ } from '@packages/driver' const channel = io.connect({ path: '/__socket.io', transports: ['websocket'], - parser: io.circularParser, }) channel.on('connect', () => { diff --git a/packages/server/lib/socket.coffee b/packages/server/lib/socket.coffee index af47a7df876d..ee662ade0b78 100644 --- a/packages/server/lib/socket.coffee +++ b/packages/server/lib/socket.coffee @@ -124,7 +124,6 @@ class Socket destroyUpgrade: false serveClient: false cookie: cookie - parser: socketIo.circularParser }) startListening: (server, automation, config, options) -> diff --git a/packages/server/test/integration/websockets_spec.coffee b/packages/server/test/integration/websockets_spec.coffee index 4af3f0431d7c..7668c5df4dcf 100644 --- a/packages/server/test/integration/websockets_spec.coffee +++ b/packages/server/test/integration/websockets_spec.coffee @@ -175,8 +175,6 @@ describe "Web Sockets", -> @wsClient = socketIo.client(@cfg.proxyUrl, { path: @cfg.socketIoRoute transports: ["websocket"] - parser: socketIo.circularParser - rejectUnauthorized: false }) @wsClient.on "connect", -> done() @@ -199,8 +197,6 @@ describe "Web Sockets", -> agent: agent path: @cfg.socketIoRoute transports: ["websocket"] - parser: socketIo.circularParser - rejectUnauthorized: false }) @wsClient.on "connect", -> done() @@ -224,8 +220,6 @@ describe "Web Sockets", -> @wsClient = socketIo.client("https://localhost:#{wssPort}", { agent: agent path: @cfg.socketIoRoute - parser: socketIo.circularParser - rejectUnauthorized: false }) @wsClient.on "connect", -> done() diff --git a/packages/socket/lib/client.js b/packages/socket/lib/client.js index 467bad9146f7..e13ac9d1b45d 100644 --- a/packages/socket/lib/client.js +++ b/packages/socket/lib/client.js @@ -1,5 +1 @@ -const circularParser = require('socket.io-circular-parser') - module.exports = require('socket.io-client') - -module.exports.circularParser = circularParser diff --git a/packages/socket/lib/socket.js b/packages/socket/lib/socket.js index 371e2c6c2375..7eff210b2d72 100644 --- a/packages/socket/lib/socket.js +++ b/packages/socket/lib/socket.js @@ -4,15 +4,12 @@ const server = require('socket.io') const version = require('socket.io-client/package.json').version const clientPath = require.resolve('socket.io-client') const client = require('./client') -const circularParser = require('socket.io-circular-parser') module.exports = { server, client, - circularParser, - getPathToClientSource () { // clientPath returns the path to socket.io-client/lib/index.js // so walk up two levels to get to the root diff --git a/packages/socket/package.json b/packages/socket/package.json index 945020c05e0d..a74615514b86 100644 --- a/packages/socket/package.json +++ b/packages/socket/package.json @@ -17,9 +17,8 @@ "lib" ], "dependencies": { - "socket.io": "2.2.0", - "socket.io-circular-parser": "3.1.2", - "socket.io-client": "2.2.0" + "socket.io": "1.7.4", + "socket.io-client": "1.7.4" }, "devDependencies": { "bin-up": "1.2.0", From 40912069b7ed42f031c2b81ce874724bdf8ab90c Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Wed, 12 Jun 2019 14:23:57 -0400 Subject: [PATCH 06/18] add failing driver and server tests for circular objs over websocket --- .../integration/cypress/cypress_spec.coffee | 14 +++++++++++++- packages/server/test/unit/socket_spec.coffee | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee b/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee index e69ef13af196..e4f41597cc4e 100644 --- a/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee +++ b/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee @@ -47,6 +47,18 @@ describe "driver/src/cypress/index", -> done() + ## https://github.com/cypress-io/cypress/issues/4346 + it "can complete if a circular reference is sent", -> + foo = { + bar: {} + } + + foo.bar.baz = foo + + Cypress.backend("foo", foo) + .catch (e) -> + expect(e.message).to.eq('You requested a backend event we cannot handle: foo') + context ".isCy", -> it "returns true on cy, cy chainable", -> expect(Cypress.isCy(cy)).to.be.true @@ -75,4 +87,4 @@ describe "driver/src/cypress/index", -> fn = -> Cypress.log({ message: 'My Log' }) - expect(fn).to.not.throw() \ No newline at end of file + expect(fn).to.not.throw() diff --git a/packages/server/test/unit/socket_spec.coffee b/packages/server/test/unit/socket_spec.coffee index cc07d6f713d6..53cbb9a0fbea 100644 --- a/packages/server/test/unit/socket_spec.coffee +++ b/packages/server/test/unit/socket_spec.coffee @@ -70,6 +70,22 @@ describe "lib/socket", -> afterEach -> @client.disconnect() + ## https://github.com/cypress-io/cypress/issues/4346 + it "can emit a circular object without crashing", (done) -> + foo = { + bar: {} + } + + foo.bar.baz = foo + + ## going to stub exec here just so we have something that we can + ## control the resolved value of + sinon.stub(exec, 'run').resolves(foo) + + @client.emit "backend:request", "exec", "quuz", (res) -> + expect(res).to.deep.eq(foo) + done() + context "on(automation:request)", -> describe "#onAutomation", -> before -> From 60c8e83550087023340b354466154a7bca3edcd3 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 6 Jun 2019 16:04:29 -0400 Subject: [PATCH 07/18] use a parser that supports circular json --- packages/extension/app/background.coffee | 7 ++++++- packages/runner/src/lib/event-manager.js | 1 + packages/server/lib/socket.coffee | 1 + packages/server/test/integration/websockets_spec.coffee | 3 +++ packages/socket/lib/client.js | 4 ++++ packages/socket/lib/socket.js | 3 +++ packages/socket/package.json | 5 +++-- 7 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/extension/app/background.coffee b/packages/extension/app/background.coffee index 296bb6972c03..ac7e4f525e8a 100644 --- a/packages/extension/app/background.coffee +++ b/packages/extension/app/background.coffee @@ -2,6 +2,7 @@ map = require("lodash/map") pick = require("lodash/pick") once = require("lodash/once") Promise = require("bluebird") +{ circularParser } = require("@packages/socket") HOST = "CHANGE_ME_HOST" PATH = "CHANGE_ME_PATH" @@ -41,7 +42,11 @@ connect = (host, path, io) -> ## cannot use required socket here due ## to bug in socket io client with browserify - client = io.connect(host, {path: path, transports: ["websocket"]}) + client = io.connect(host, { + path: path, + transports: ["websocket"] + parser: circularParser + }) client.on "automation:request", (id, msg, data) -> switch msg diff --git a/packages/runner/src/lib/event-manager.js b/packages/runner/src/lib/event-manager.js index d449e67c037b..618d2408df51 100644 --- a/packages/runner/src/lib/event-manager.js +++ b/packages/runner/src/lib/event-manager.js @@ -12,6 +12,7 @@ import $Cypress, { $ } from '@packages/driver' const channel = io.connect({ path: '/__socket.io', transports: ['websocket'], + parser: io.circularParser, }) channel.on('connect', () => { diff --git a/packages/server/lib/socket.coffee b/packages/server/lib/socket.coffee index ee662ade0b78..af47a7df876d 100644 --- a/packages/server/lib/socket.coffee +++ b/packages/server/lib/socket.coffee @@ -124,6 +124,7 @@ class Socket destroyUpgrade: false serveClient: false cookie: cookie + parser: socketIo.circularParser }) startListening: (server, automation, config, options) -> diff --git a/packages/server/test/integration/websockets_spec.coffee b/packages/server/test/integration/websockets_spec.coffee index 7668c5df4dcf..fc933f3b7968 100644 --- a/packages/server/test/integration/websockets_spec.coffee +++ b/packages/server/test/integration/websockets_spec.coffee @@ -175,6 +175,7 @@ describe "Web Sockets", -> @wsClient = socketIo.client(@cfg.proxyUrl, { path: @cfg.socketIoRoute transports: ["websocket"] + parser: socketIo.circularParser }) @wsClient.on "connect", -> done() @@ -197,6 +198,7 @@ describe "Web Sockets", -> agent: agent path: @cfg.socketIoRoute transports: ["websocket"] + parser: socketIo.circularParser }) @wsClient.on "connect", -> done() @@ -220,6 +222,7 @@ describe "Web Sockets", -> @wsClient = socketIo.client("https://localhost:#{wssPort}", { agent: agent path: @cfg.socketIoRoute + parser: socketIo.circularParser }) @wsClient.on "connect", -> done() diff --git a/packages/socket/lib/client.js b/packages/socket/lib/client.js index e13ac9d1b45d..467bad9146f7 100644 --- a/packages/socket/lib/client.js +++ b/packages/socket/lib/client.js @@ -1 +1,5 @@ +const circularParser = require('socket.io-circular-parser') + module.exports = require('socket.io-client') + +module.exports.circularParser = circularParser diff --git a/packages/socket/lib/socket.js b/packages/socket/lib/socket.js index 7eff210b2d72..371e2c6c2375 100644 --- a/packages/socket/lib/socket.js +++ b/packages/socket/lib/socket.js @@ -4,12 +4,15 @@ const server = require('socket.io') const version = require('socket.io-client/package.json').version const clientPath = require.resolve('socket.io-client') const client = require('./client') +const circularParser = require('socket.io-circular-parser') module.exports = { server, client, + circularParser, + getPathToClientSource () { // clientPath returns the path to socket.io-client/lib/index.js // so walk up two levels to get to the root diff --git a/packages/socket/package.json b/packages/socket/package.json index a74615514b86..945020c05e0d 100644 --- a/packages/socket/package.json +++ b/packages/socket/package.json @@ -17,8 +17,9 @@ "lib" ], "dependencies": { - "socket.io": "1.7.4", - "socket.io-client": "1.7.4" + "socket.io": "2.2.0", + "socket.io-circular-parser": "3.1.2", + "socket.io-client": "2.2.0" }, "devDependencies": { "bin-up": "1.2.0", From 38ba353e4527c9e55cb2ae305165e2a42dc9f999 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Wed, 12 Jun 2019 15:38:13 -0400 Subject: [PATCH 08/18] add has-binary2 patch that enables circular objects to be inspected --- packages/socket/package.json | 4 +- .../socket/patches/has-binary2+1.0.3.patch | 94 +++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 packages/socket/patches/has-binary2+1.0.3.patch diff --git a/packages/socket/package.json b/packages/socket/package.json index 945020c05e0d..c9b10153f4f7 100644 --- a/packages/socket/package.json +++ b/packages/socket/package.json @@ -5,6 +5,7 @@ "main": "index.js", "browser": "./lib/client.js", "scripts": { + "postinstall": "patch-package", "pretest": "npm run check-deps-pre", "test": "cross-env NODE_ENV=test bin-up mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json", "pretest-watch": "npm run check-deps-pre", @@ -24,6 +25,7 @@ "devDependencies": { "bin-up": "1.2.0", "chai": "3.5.0", - "cross-env": "5.2.0" + "cross-env": "5.2.0", + "patch-package": "6.1.2" } } diff --git a/packages/socket/patches/has-binary2+1.0.3.patch b/packages/socket/patches/has-binary2+1.0.3.patch new file mode 100644 index 000000000000..1da07225c972 --- /dev/null +++ b/packages/socket/patches/has-binary2+1.0.3.patch @@ -0,0 +1,94 @@ +diff --git a/node_modules/has-binary2/index.js b/node_modules/has-binary2/index.js +index cf756a3..277ed03 100644 +--- a/node_modules/has-binary2/index.js ++++ b/node_modules/has-binary2/index.js +@@ -4,19 +4,19 @@ + * Module requirements. + */ + +-var isArray = require('isarray'); ++let isArray = require('isarray') + +-var toString = Object.prototype.toString; +-var withNativeBlob = typeof Blob === 'function' || +- typeof Blob !== 'undefined' && toString.call(Blob) === '[object BlobConstructor]'; +-var withNativeFile = typeof File === 'function' || +- typeof File !== 'undefined' && toString.call(File) === '[object FileConstructor]'; ++let toString = Object.prototype.toString ++let withNativeBlob = typeof global.Blob === 'function' || toString.call(global.Blob) === '[object BlobConstructor]' ++let withNativeFile = typeof global.File === 'function' || toString.call(global.File) === '[object FileConstructor]' + + /** + * Module exports. + */ + +-module.exports = hasBinary; ++module.exports = function hasBinaryCircular (obj) { ++ return hasBinary(obj, []) ++} + + /** + * Checks for binary data. +@@ -27,38 +27,45 @@ module.exports = hasBinary; + * @api public + */ + +-function hasBinary (obj) { ++function hasBinary (obj, known) { + if (!obj || typeof obj !== 'object') { +- return false; ++ return false ++ } ++ ++ if (known.indexOf(obj) >= 0) { ++ return false + } + ++ known.push(obj) ++ + if (isArray(obj)) { +- for (var i = 0, l = obj.length; i < l; i++) { +- if (hasBinary(obj[i])) { +- return true; ++ for (let i = 0, l = obj.length; i < l; i++) { ++ if (hasBinary(obj[i], known)) { ++ return true + } + } +- return false; ++ ++ return false + } + +- if ((typeof Buffer === 'function' && Buffer.isBuffer && Buffer.isBuffer(obj)) || +- (typeof ArrayBuffer === 'function' && obj instanceof ArrayBuffer) || +- (withNativeBlob && obj instanceof Blob) || +- (withNativeFile && obj instanceof File) ++ if ((typeof global.Buffer === 'function' && global.Buffer.isBuffer && global.Buffer.isBuffer(obj)) || ++ (typeof global.ArrayBuffer === 'function' && obj instanceof ArrayBuffer) || ++ (withNativeBlob && obj instanceof Blob) || ++ (withNativeFile && obj instanceof File) + ) { +- return true; ++ return true + } + + // see: https://github.com/Automattic/has-binary/pull/4 +- if (obj.toJSON && typeof obj.toJSON === 'function' && arguments.length === 1) { +- return hasBinary(obj.toJSON(), true); ++ if (obj.toJSON && typeof obj.toJSON === 'function') { ++ return hasBinary(obj.toJSON(), known) + } + +- for (var key in obj) { +- if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key])) { +- return true; ++ for (let key in obj) { ++ if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key], known)) { ++ return true + } + } + +- return false; ++ return false + } From 4a99e303b8ea252904e1caa0ddd957eb71c7ec1f Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Wed, 12 Jun 2019 15:38:22 -0400 Subject: [PATCH 09/18] update socket spec --- packages/server/test/unit/socket_spec.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/server/test/unit/socket_spec.coffee b/packages/server/test/unit/socket_spec.coffee index 53cbb9a0fbea..fd1ebfebae83 100644 --- a/packages/server/test/unit/socket_spec.coffee +++ b/packages/server/test/unit/socket_spec.coffee @@ -64,6 +64,7 @@ describe "lib/socket", -> agent: agent path: socketIoRoute transports: ["websocket"] + parser: socketIo.circularParser }) return @@ -83,7 +84,7 @@ describe "lib/socket", -> sinon.stub(exec, 'run').resolves(foo) @client.emit "backend:request", "exec", "quuz", (res) -> - expect(res).to.deep.eq(foo) + expect(res.response).to.deep.eq(foo) done() context "on(automation:request)", -> From b7866a07f9ae652502aad13e75190354f6ed1571 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Wed, 12 Jun 2019 15:54:50 -0400 Subject: [PATCH 10/18] rejectUnauthorized: false --- packages/server/test/integration/websockets_spec.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/server/test/integration/websockets_spec.coffee b/packages/server/test/integration/websockets_spec.coffee index fc933f3b7968..a818f5983001 100644 --- a/packages/server/test/integration/websockets_spec.coffee +++ b/packages/server/test/integration/websockets_spec.coffee @@ -223,6 +223,7 @@ describe "Web Sockets", -> agent: agent path: @cfg.socketIoRoute parser: socketIo.circularParser + rejectUnauthorized: false }) @wsClient.on "connect", -> done() From c1616a81325a97abb66d8559c3a8d89edd53e148 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Wed, 12 Jun 2019 17:20:19 -0400 Subject: [PATCH 11/18] use @packages/socket instead of copying client source --- packages/extension/app/background.coffee | 13 ++++++------- packages/extension/app/manifest.json | 1 - packages/extension/gulpfile.coffee | 5 ----- .../test/integration/background_spec.coffee | 12 ++++++------ 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/packages/extension/app/background.coffee b/packages/extension/app/background.coffee index ac7e4f525e8a..6c60c3216b1e 100644 --- a/packages/extension/app/background.coffee +++ b/packages/extension/app/background.coffee @@ -2,7 +2,7 @@ map = require("lodash/map") pick = require("lodash/pick") once = require("lodash/once") Promise = require("bluebird") -{ circularParser } = require("@packages/socket") +io = require("@packages/socket") HOST = "CHANGE_ME_HOST" PATH = "CHANGE_ME_PATH" @@ -14,10 +14,9 @@ firstOrNull = (cookies) -> cookies[0] ? null connect = (host, path, io) -> - io ?= global.io - - ## bail if io isnt defined - return if not io + if not io.connect + ## running in node, return + return listenToCookieChanges = once -> chrome.cookies.onChanged.addListener (info) -> @@ -45,7 +44,7 @@ connect = (host, path, io) -> client = io.connect(host, { path: path, transports: ["websocket"] - parser: circularParser + parser: io.circularParser }) client.on "automation:request", (id, msg, data) -> @@ -77,7 +76,7 @@ connect = (host, path, io) -> return client ## initially connect -connect(HOST, PATH, global.io) +connect(HOST, PATH, io) automation = { connect: connect diff --git a/packages/extension/app/manifest.json b/packages/extension/app/manifest.json index 4248dddbc603..98c2a503dd2e 100644 --- a/packages/extension/app/manifest.json +++ b/packages/extension/app/manifest.json @@ -24,7 +24,6 @@ }, "background": { "scripts": [ - "socket.io.js", "background.js" ] }, diff --git a/packages/extension/gulpfile.coffee b/packages/extension/gulpfile.coffee index d417e11841c2..4e1b20441bd8 100644 --- a/packages/extension/gulpfile.coffee +++ b/packages/extension/gulpfile.coffee @@ -11,10 +11,6 @@ browserify = require("browserify") icons = require("@cypress/icons") ext = require("./") -gulp.task "copy:socket:client", -> - gulp.src(require("../socket").getPathToClientSource()) - .pipe(gulp.dest("dist")) - gulp.task "clean", -> gulp.src("dist") .pipe(clean()) @@ -71,7 +67,6 @@ gulp.task "watch", ["build"], -> gulp.task "build", -> runSeq "clean", [ - "copy:socket:client" "icons" "logos" "manifest" diff --git a/packages/extension/test/integration/background_spec.coffee b/packages/extension/test/integration/background_spec.coffee index c7f4d3c44444..65c383baa14a 100644 --- a/packages/extension/test/integration/background_spec.coffee +++ b/packages/extension/test/integration/background_spec.coffee @@ -114,10 +114,10 @@ describe "app/background", -> it "can connect", (done) -> @server.on "connection", -> done() - background.connect("http://localhost:#{PORT}", "/__socket.io") + background.connect("http://localhost:#{PORT}", "/__socket.io", io) it "emits 'automation:client:connected'", (done) -> - client = background.connect("http://localhost:#{PORT}", "/__socket.io") + client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) @sandbox.spy(client, "emit") @@ -127,7 +127,7 @@ describe "app/background", -> it "listens to cookie changes", (done) -> addListener = @sandbox.stub(chrome.cookies.onChanged, "addListener") - client = background.connect("http://localhost:#{PORT}", "/__socket.io") + client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) client.on "connect", _.once -> expect(addListener).to.be.calledOnce @@ -136,7 +136,7 @@ describe "app/background", -> context "onChanged", -> it "does not emit when cause is overwrite", (done) -> addListener = @sandbox.stub(chrome.cookies.onChanged, "addListener") - client = background.connect("http://localhost:#{PORT}", "/__socket.io") + client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) @sandbox.spy(client, "emit") @@ -152,7 +152,7 @@ describe "app/background", -> info = { cause: "explicit", cookie: {name: "foo", value: "bar"} } addListener = @sandbox.stub(chrome.cookies.onChanged, "addListener").yieldsAsync(info) - client = background.connect("http://localhost:#{PORT}", "/__socket.io") + client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) client.on "connect", -> client.emit = _.once (req, msg, data) -> @@ -266,7 +266,7 @@ describe "app/background", -> done = _.once(done) @server.on "connection", (@socket) => done() - @client = background.connect("http://localhost:#{PORT}", "/__socket.io") + @client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) describe "get:cookies", -> beforeEach -> From 8016e5d03aca9076a152624ab47f0919114cb124 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 13 Jun 2019 12:22:20 -0400 Subject: [PATCH 12/18] prevent false positive --- .../test/cypress/integration/cypress/cypress_spec.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee b/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee index e4f41597cc4e..183d16971dba 100644 --- a/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee +++ b/packages/driver/test/cypress/integration/cypress/cypress_spec.coffee @@ -56,8 +56,10 @@ describe "driver/src/cypress/index", -> foo.bar.baz = foo Cypress.backend("foo", foo) + .then -> + throw new Error("should not reach") .catch (e) -> - expect(e.message).to.eq('You requested a backend event we cannot handle: foo') + expect(e.message).to.eq("You requested a backend event we cannot handle: foo") context ".isCy", -> it "returns true on cy, cy chainable", -> From d5fee3ad4a92a391565a9bfab8e74896a9d9a4f6 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 13 Jun 2019 12:23:34 -0400 Subject: [PATCH 13/18] use commit hash for socket.io-circular-parser --- packages/socket/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/socket/package.json b/packages/socket/package.json index c9b10153f4f7..04d173d54ecc 100644 --- a/packages/socket/package.json +++ b/packages/socket/package.json @@ -19,7 +19,7 @@ ], "dependencies": { "socket.io": "2.2.0", - "socket.io-circular-parser": "3.1.2", + "socket.io-circular-parser": "cypress-io/socket.io-circular-parser#c5a895a0fef6d19d457a38a515dbb5c18feeb591", "socket.io-client": "2.2.0" }, "devDependencies": { From e2ea430fa74b83e8a36548bf867e4b0a5db11468 Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Thu, 13 Jun 2019 13:36:02 -0400 Subject: [PATCH 14/18] cleanup bundling of socket.io for node + browser - keep the interfaces identical - browser simply has less properties than the node variant --- packages/extension/app/background.coffee | 32 ++++++++----------- .../test/integration/background_spec.coffee | 19 ++++------- packages/extension/test/spec_helper.coffee | 6 +--- packages/socket/index.js | 2 +- packages/socket/lib/browser.js | 8 +++++ packages/socket/lib/client.js | 5 --- packages/socket/lib/socket.js | 6 ++-- packages/socket/package.json | 2 +- 8 files changed, 33 insertions(+), 47 deletions(-) create mode 100644 packages/socket/lib/browser.js delete mode 100644 packages/socket/lib/client.js diff --git a/packages/extension/app/background.coffee b/packages/extension/app/background.coffee index 6c60c3216b1e..026c8ba1a16d 100644 --- a/packages/extension/app/background.coffee +++ b/packages/extension/app/background.coffee @@ -2,7 +2,7 @@ map = require("lodash/map") pick = require("lodash/pick") once = require("lodash/once") Promise = require("bluebird") -io = require("@packages/socket") +{ client, circularParser } = require("@packages/socket") HOST = "CHANGE_ME_HOST" PATH = "CHANGE_ME_PATH" @@ -13,18 +13,14 @@ firstOrNull = (cookies) -> ## normalize into null when empty array cookies[0] ? null -connect = (host, path, io) -> - if not io.connect - ## running in node, return - return - +connect = (host, path) -> listenToCookieChanges = once -> chrome.cookies.onChanged.addListener (info) -> if info.cause isnt "overwrite" - client.emit("automation:push:request", "change:cookie", info) + ws.emit("automation:push:request", "change:cookie", info) fail = (id, err) -> - client.emit("automation:response", id, { + ws.emit("automation:response", id, { __error: err.message __stack: err.stack __name: err.name @@ -32,22 +28,20 @@ connect = (host, path, io) -> invoke = (method, id, args...) -> respond = (data) -> - client.emit("automation:response", id, {response: data}) + ws.emit("automation:response", id, {response: data}) Promise.try -> automation[method].apply(automation, args.concat(respond)) .catch (err) -> fail(id, err) - ## cannot use required socket here due - ## to bug in socket io client with browserify - client = io.connect(host, { + ws = client.connect(host, { path: path, transports: ["websocket"] - parser: io.circularParser + parser: circularParser }) - client.on "automation:request", (id, msg, data) -> + ws.on "automation:request", (id, msg, data) -> switch msg when "get:cookies" invoke("getCookies", id, data) @@ -68,18 +62,18 @@ connect = (host, path, io) -> else fail(id, {message: "No handler registered for: '#{msg}'"}) - client.on "connect", -> + ws.on "connect", -> listenToCookieChanges() - client.emit("automation:client:connected") + ws.emit("automation:client:connected") - return client + return ws ## initially connect -connect(HOST, PATH, io) +connect(HOST, PATH) automation = { - connect: connect + connect getUrl: (cookie = {}) -> prefix = if cookie.secure then "https://" else "http://" diff --git a/packages/extension/test/integration/background_spec.coffee b/packages/extension/test/integration/background_spec.coffee index 65c383baa14a..0a43b0ea25b2 100644 --- a/packages/extension/test/integration/background_spec.coffee +++ b/packages/extension/test/integration/background_spec.coffee @@ -94,10 +94,6 @@ tab3 = { } describe "app/background", -> - before -> - @io = global.io - global.io = socket.client - beforeEach (done) -> @httpSrv = http.createServer() @server = socket.server(@httpSrv, {path: "/__socket.io"}) @@ -107,17 +103,14 @@ describe "app/background", -> @server.close() @httpSrv.close -> done() - after -> - global.io = @io - context ".connect", -> it "can connect", (done) -> @server.on "connection", -> done() - background.connect("http://localhost:#{PORT}", "/__socket.io", io) + background.connect("http://localhost:#{PORT}", "/__socket.io") it "emits 'automation:client:connected'", (done) -> - client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) + client = background.connect("http://localhost:#{PORT}", "/__socket.io") @sandbox.spy(client, "emit") @@ -127,7 +120,7 @@ describe "app/background", -> it "listens to cookie changes", (done) -> addListener = @sandbox.stub(chrome.cookies.onChanged, "addListener") - client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) + client = background.connect("http://localhost:#{PORT}", "/__socket.io") client.on "connect", _.once -> expect(addListener).to.be.calledOnce @@ -136,7 +129,7 @@ describe "app/background", -> context "onChanged", -> it "does not emit when cause is overwrite", (done) -> addListener = @sandbox.stub(chrome.cookies.onChanged, "addListener") - client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) + client = background.connect("http://localhost:#{PORT}", "/__socket.io") @sandbox.spy(client, "emit") @@ -152,7 +145,7 @@ describe "app/background", -> info = { cause: "explicit", cookie: {name: "foo", value: "bar"} } addListener = @sandbox.stub(chrome.cookies.onChanged, "addListener").yieldsAsync(info) - client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) + client = background.connect("http://localhost:#{PORT}", "/__socket.io") client.on "connect", -> client.emit = _.once (req, msg, data) -> @@ -266,7 +259,7 @@ describe "app/background", -> done = _.once(done) @server.on "connection", (@socket) => done() - @client = background.connect("http://localhost:#{PORT}", "/__socket.io", io) + @client = background.connect("http://localhost:#{PORT}", "/__socket.io") describe "get:cookies", -> beforeEach -> diff --git a/packages/extension/test/spec_helper.coffee b/packages/extension/test/spec_helper.coffee index 5a4a28bde0dd..7be29a687d06 100644 --- a/packages/extension/test/spec_helper.coffee +++ b/packages/extension/test/spec_helper.coffee @@ -5,13 +5,9 @@ sinonChai = require("sinon-chai") chai.use(sinonChai) global.expect = chai.expect -global.io = { - connect: -> - return {on: ->} -} beforeEach -> @sandbox = sinon.sandbox.create() afterEach -> - @sandbox.restore() \ No newline at end of file + @sandbox.restore() diff --git a/packages/socket/index.js b/packages/socket/index.js index 77ca6ef899ed..c482fe1cee9d 100644 --- a/packages/socket/index.js +++ b/packages/socket/index.js @@ -1 +1 @@ -module.exports = require("./lib/socket") \ No newline at end of file +module.exports = require('./lib/socket') diff --git a/packages/socket/lib/browser.js b/packages/socket/lib/browser.js new file mode 100644 index 000000000000..36c1f83138bd --- /dev/null +++ b/packages/socket/lib/browser.js @@ -0,0 +1,8 @@ +const client = require('socket.io-client') +const circularParser = require('socket.io-circular-parser') + +module.exports = { + client, + + circularParser, +} diff --git a/packages/socket/lib/client.js b/packages/socket/lib/client.js deleted file mode 100644 index 467bad9146f7..000000000000 --- a/packages/socket/lib/client.js +++ /dev/null @@ -1,5 +0,0 @@ -const circularParser = require('socket.io-circular-parser') - -module.exports = require('socket.io-client') - -module.exports.circularParser = circularParser diff --git a/packages/socket/lib/socket.js b/packages/socket/lib/socket.js index 371e2c6c2375..3b90991616fe 100644 --- a/packages/socket/lib/socket.js +++ b/packages/socket/lib/socket.js @@ -1,10 +1,10 @@ const fs = require('fs') const path = require('path') const server = require('socket.io') -const version = require('socket.io-client/package.json').version +const { version } = require('socket.io-client/package.json') +const { client, circularParser } = require('./browser') + const clientPath = require.resolve('socket.io-client') -const client = require('./client') -const circularParser = require('socket.io-circular-parser') module.exports = { server, diff --git a/packages/socket/package.json b/packages/socket/package.json index 04d173d54ecc..f45473ff91f0 100644 --- a/packages/socket/package.json +++ b/packages/socket/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "main": "index.js", - "browser": "./lib/client.js", + "browser": "./lib/browser.js", "scripts": { "postinstall": "patch-package", "pretest": "npm run check-deps-pre", From 3f50c02a4f743437be47da964067c511c2ae270f Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Thu, 13 Jun 2019 14:19:47 -0400 Subject: [PATCH 15/18] properly import client + circularParser from socket package --- packages/runner/src/lib/event-manager.js | 44 ++++++++++++------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/runner/src/lib/event-manager.js b/packages/runner/src/lib/event-manager.js index 618d2408df51..796094697a8d 100644 --- a/packages/runner/src/lib/event-manager.js +++ b/packages/runner/src/lib/event-manager.js @@ -2,21 +2,21 @@ import _ from 'lodash' import { EventEmitter } from 'events' import Promise from 'bluebird' import { action } from 'mobx' -import io from '@packages/socket' +import { client, circularParser } from '@packages/socket' import automation from './automation' import logger from './logger' import $Cypress, { $ } from '@packages/driver' -const channel = io.connect({ +const ws = client.connect({ path: '/__socket.io', transports: ['websocket'], - parser: io.circularParser, + parser: circularParser, }) -channel.on('connect', () => { - channel.emit('runner:connected') +ws.on('connect', () => { + ws.emit('runner:connected') }) const driverToReporterEvents = 'paused'.split(' ') @@ -43,18 +43,18 @@ const eventManager = { return this._reRun(state) } - channel.emit('is:automation:client:connected', connectionInfo, action('automationEnsured', (isConnected) => { + ws.emit('is:automation:client:connected', connectionInfo, action('automationEnsured', (isConnected) => { state.automation = isConnected ? automation.CONNECTED : automation.MISSING - channel.on('automation:disconnected', action('automationDisconnected', () => { + ws.on('automation:disconnected', action('automationDisconnected', () => { state.automation = automation.DISCONNECTED })) })) - channel.on('change:to:url', (url) => { + ws.on('change:to:url', (url) => { window.location.href = url }) - channel.on('automation:push:message', (msg, data = {}) => { + ws.on('automation:push:message', (msg, data = {}) => { if (!Cypress) return switch (msg) { @@ -67,7 +67,7 @@ const eventManager = { }) _.each(socketRerunEvents, (event) => { - channel.on(event, rerun) + ws.on(event, rerun) }) reporterBus.on('runner:console:error', (testId) => { @@ -141,7 +141,7 @@ const eventManager = { }) reporterBus.on('external:open', (url) => { - channel.emit('external:open', url) + ws.emit('external:open', url) }) const $window = $(window) @@ -171,7 +171,7 @@ const eventManager = { start (config) { if (config.socketId) { - channel.emit('app:connect', config.socketId) + ws.emit('app:connect', config.socketId) } }, @@ -183,7 +183,7 @@ const eventManager = { this._addListeners() - channel.emit('watch:test:file', specPath) + ws.emit('watch:test:file', specPath) }, initialize ($autIframe, config) { @@ -191,7 +191,7 @@ const eventManager = { // get the current runnable in case we reran mid-test due to a visit // to a new domain - channel.emit('get:existing:run:state', (state = {}) => { + ws.emit('get:existing:run:state', (state = {}) => { const runnables = Cypress.normalizeAll(state.tests) const run = () => { this._runDriver(state) @@ -215,7 +215,7 @@ const eventManager = { } if (config.isTextTerminal && !state.currentId) { - channel.emit('set:runnables', runnables, run) + ws.emit('set:runnables', runnables, run) } else { run() } @@ -224,12 +224,12 @@ const eventManager = { _addListeners () { Cypress.on('message', (msg, data, cb) => { - channel.emit('client:request', msg, data, cb) + ws.emit('client:request', msg, data, cb) }) _.each(driverToSocketEvents, (event) => { Cypress.on(event, (...args) => { - return channel.emit(event, ...args) + return ws.emit(event, ...args) }) }) @@ -316,7 +316,7 @@ const eventManager = { stop () { localBus.removeAllListeners() - channel.off() + ws.off() }, _reRun (state) { @@ -356,11 +356,11 @@ const eventManager = { }, notifyRunningSpec (specFile) { - channel.emit('spec:changed', specFile) + ws.emit('spec:changed', specFile) }, focusTests () { - channel.emit('focus:tests') + ws.emit('focus:tests') }, snapshotUnpinned () { @@ -378,7 +378,7 @@ const eventManager = { }, launchBrowser (browser) { - channel.emit('reload:browser', window.location.toString(), browser && browser.name) + ws.emit('reload:browser', window.location.toString(), browser && browser.name) }, // clear all the cypress specific cookies @@ -397,7 +397,7 @@ const eventManager = { }, saveState (state) { - channel.emit('save:app:state', state) + ws.emit('save:app:state', state) }, } From 802a3a8a9943079968efe3fe042015e1967dfce4 Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Thu, 13 Jun 2019 14:30:56 -0400 Subject: [PATCH 16/18] @cypress/what-is-circular --- packages/driver/package.json | 2 +- packages/driver/src/cy/commands/navigation.coffee | 2 +- packages/driver/src/cy/commands/request.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/driver/package.json b/packages/driver/package.json index d46f872a1655..181c715018ba 100644 --- a/packages/driver/package.json +++ b/packages/driver/package.json @@ -62,7 +62,7 @@ "url-parse": "1.4.7", "vanilla-text-mask": "5.1.1", "wait-on": "3.2.0", - "what-is-circular": "1.0.0", + "@cypress/what-is-circular": "1.0.0", "zone.js": "0.9.0" } } diff --git a/packages/driver/src/cy/commands/navigation.coffee b/packages/driver/src/cy/commands/navigation.coffee index 89ae27da30b5..c300df70e1a8 100644 --- a/packages/driver/src/cy/commands/navigation.coffee +++ b/packages/driver/src/cy/commands/navigation.coffee @@ -1,5 +1,5 @@ _ = require("lodash") -whatIsCircular = require("what-is-circular") +whatIsCircular = require("@cypress/what-is-circular") moment = require("moment") UrlParse = require("url-parse") Promise = require("bluebird") diff --git a/packages/driver/src/cy/commands/request.coffee b/packages/driver/src/cy/commands/request.coffee index 45ad4fac9fa0..f7e95bfc8cd8 100644 --- a/packages/driver/src/cy/commands/request.coffee +++ b/packages/driver/src/cy/commands/request.coffee @@ -1,5 +1,5 @@ _ = require("lodash") -whatIsCircular = require("what-is-circular") +whatIsCircular = require("@cypress/what-is-circular") Promise = require("bluebird") $utils = require("../../cypress/utils") From 0d206281f2309488fb38446c5557df245cda9c25 Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Thu, 13 Jun 2019 14:36:08 -0400 Subject: [PATCH 17/18] dont require the extension, it causes gulp to hang --- packages/extension/gulpfile.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/extension/gulpfile.coffee b/packages/extension/gulpfile.coffee index 4e1b20441bd8..91fd9b08ad99 100644 --- a/packages/extension/gulpfile.coffee +++ b/packages/extension/gulpfile.coffee @@ -9,7 +9,6 @@ Promise = require("bluebird") coffeeify = require("coffeeify") browserify = require("browserify") icons = require("@cypress/icons") -ext = require("./") gulp.task "clean", -> gulp.src("dist") From 7b3b13ba792ca764ccc51158acb63ab58304014a Mon Sep 17 00:00:00 2001 From: Brian Mann Date: Thu, 13 Jun 2019 16:23:39 -0400 Subject: [PATCH 18/18] fix runner tests hanging --- packages/runner/lib/test-setup.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/runner/lib/test-setup.js b/packages/runner/lib/test-setup.js index b47aa416a4cf..c13891df3f64 100644 --- a/packages/runner/lib/test-setup.js +++ b/packages/runner/lib/test-setup.js @@ -2,7 +2,7 @@ const chai = require('chai') const JSDOM = require('jsdom').JSDOM const sinonChai = require('sinon-chai') const $Cypress = require('@packages/driver') -const io = require('@packages/socket') +const { client } = require('@packages/socket') // http://airbnb.io/enzyme/docs/guides/jsdom.html const jsdom = new JSDOM('') @@ -52,6 +52,6 @@ class Runner { global.Mocha = { Runnable, Runner } $Cypress.create = () => {} -io.connect = () => { +client.connect = () => { return { emit: () => {}, on: () => {} } }