-
Notifications
You must be signed in to change notification settings - Fork 408
PhantomJS fails to execute tests when using websockets, introduced in #768 #824
Comments
I have to add that it is working when tests are running in Chrome |
this: var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true }; changed to: var desc = Object.getOwnPropertyDescriptor(obj, prop); and makes code not working. So it looks like in the end it doesn't patch the properties of websocket if I'm correct. |
@rokerkony, could you post the reproduce repo? or could you help to debug which |
I made my code working by changing it as: if (prop === 'onopen') {
var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true };
} else {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
} and this is working to connect. But I guess it should be done for all the methods I don't see a way to make a reproduce repo without really connecting to Sendbird and for that I cannot share appId and tokens... I will try to be as helpful as possible to fix it 👍 To add all information I have in
which looks like WebSocket from SendBird connect method, which after some prettify looks like this (spoiler alert: still not pretty): this.connect = function (_user_id, _access_token, _WSHost) {
DEBUG && console.log("WSClient connect called"), connectWSHost = _WSHost;
var _WS = null;
try {
_WS = "undefined" == typeof WebSocket ? require("websocket").w3cwebsocket : WebSocket
} catch (err) {
_WS = WebSocket
}
try {
var WS_URL_PARAM = "/?p=JS&pv=" + encodeURIComponent(OS_VERSION) + "&sv=" + encodeURIComponent("3.0.31") + "&ai=" + encodeURIComponent(appId);
if (
APIClient.getInstance().sessionKey ?
WS_URL_PARAM += "&key=" + encodeURIComponent(APIClient.getInstance().sessionKey) :
WS_URL_PARAM += "&user_id=" + encodeURIComponent(_user_id) + "&access_token=" + encodeURIComponent(_access_token),
!(ws = new _WS(connectWSHost + WS_URL_PARAM))
)
return void WSClientHandler.onError(e)
} catch (e) {
return void WSClientHandler.onError(e)
}
if (DEBUG)try {
window.ws = ws
} catch (e) {
}
ws.onopen = function (e) {
pinger && pinger.ping(), DEBUG && console.log("WSClient onopen called"), WSClientHandler.onOpen(e)
},
ws.onmessage = function (e) {
active();
var data = e.data.split("\n");
for (var i in data) {
var item = data[i];
if (item && "string" == typeof item) {
try {
if ("PONG" == item.substring(0, 4)) {
pinger && pinger.ping();
continue
}
} catch (e) {
DEBUG && console.log("ws.onmessage-command check error: ", e)
}
WSClientHandler.onMessage(item)
}
}
},
ws.onclose = function (e) {
DEBUG && console.log("WSClient ws.onclose called - e, explicitDisconnect: ", e, explicitDisconnect),
pinger && pinger.stop(),
explicitDisconnect ? WSClientHandler.onClose(e) : WSClientHandler.onError(e),
explicitDisconnect = !1
},
ws.onerror = function (e) {
DEBUG && console.log("WSClient ws.onerror called: ", e),
pinger && pinger.stop(),
WSClientHandler.onError(e)
}
} |
@rokerkony , thank you for the information, in your code, could you check. if (prop === 'onopen') {
var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true };
} else {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
} could you confirm that
when prop is |
So, first of all, I created the repository with the generated app via angular-cli which is simulating the problem:
but I cannot share my AppID (I put TODO in app.component.ts to find it) ... maybe it would be easy to create some trial on Sendbird and get ID plus create a channel... @JiaLiPassion I checked also what you have asked me and here is a result: var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true }; is obviously but this fallback to enumerable/configurable object was removed in 0.8.11 which could be a problem. Hard to copy a result from the debugger but should be ok: Object
addEventListener: function () {
close: function () {
get onopen: function () {
onclose: function (e) {
onerror: function (e) {
onmessage: function (e) {
removeEventListener: function () {
send: function () {
set onopen: function (newValue) {
__proto__: WebSocket keys are: Array[4]
0: "addEventListener"
1: "removeEventListener"
2: "send"
3: "close"
length: 4
__proto__: Array[0] prototype is: WebSocket
URL: "ws://localhost:4200/sockjs-node/236/4zynjfdu/websocket"
binaryType: "blob"
bufferedAmount: 0
constructor: WebSocketConstructor
extensions: ""
onclose: null
onerror: null
onmessage: null
onopen: null
protocol: ""
readyState: 1
url: "ws://localhost:4200/sockjs-node/236/4zynjfdu/websocket"
__proto__: WebSocketPrototype |
@rokerkony , could you try the attached zone.js work or not? |
Unfortunately not. prototype argument is now set to: function (a, b) {
var socket = arguments.length > 1 ? new WS(a, b) : new WS(a);
var proxySocket;
// Safari 7.0 has non-configurable own 'onmessage' and friends properties on the socket instance
var onmessageDesc = Object.getOwnPropertyDescriptor(socket, 'onmessage');
if (onmessageDesc && onmessageDesc.configurable === false) {
proxySocket = Object.create(socket);
['addEventListener', 'removeEventListener', 'send', 'close'].forEach(function (propName) {
proxySocket[propName] = function () {
return socket[propName].apply(socket, arguments);
};
});
}
else {
// we can patch the real socket
proxySocket = socket;
}
patchOnProperties(proxySocket, ['close', 'error', 'message', 'open'], _global.WebSocket);
return proxySocket;
}
target is Object {addEventListener: function, removeEventListener: function, send: function, close: function, readyState: 0…}
addEventListener: function () {
close: function () {
onclose: function (e) {DEBUG&&console.log("WSClient ws.onclose called - e, explicitDisconnect: ",e,explicitDisconnect),pinger&&pinger.stop(),explicitDisconnect?WSClientHandler.onClose(e):WSClientHandler.onError(e),explicitDisconnect=!1;}
onerror: function (e) {DEBUG&&console.log("WSClient ws.onerror called: ",e),pinger&&pinger.stop(),WSClientHandler.onError(e);}
onmessage: function (e) {active();var data=e.data.split("\n");for(var i in data){var item=data[i];if(item&&"string"==typeof item){try{if("PONG"==item.substring(0,4)){pinger&&pinger.ping();continue}}catch(e){DEBUG&&console.log("ws.onmessage-command check error: ",e)}WSClientHandler.onMessage(item)}}}
onopen: function (e) {pinger&&pinger.ping(),DEBUG&&console.log("WSClient onopen called"),WSClientHandler.onOpen(e);}
removeEventListener: function () {
send: function () {
__proto__: WebSocket keys are: ["addEventListener", "removeEventListener", "send", "close"] prototype is: WebSocket {readyState: 0, onclose: null, bufferedAmount: 0, extensions: "", onerror: null…}
URL: "wss://ws.sendbird.com/?p=JS&pv=Mozilla%2F5.0%20(Macintosh%3B%20Intel%20Mac%20OS%20X)%20AppleWebKit%2F538.1%20(KHTML.%20like%20Gecko)%20PhantomJS%2F2.1.1%20Safari%2F538.1&sv=3.0.31&ai=A85703AE-17FD-49A6-9298-89BCA43AD59C&user_id=95666b98-17d2-5a87-8062-7840f8d63599&access_token=4cc3001fbcd8d41e576813ef6a196781d453bd7f"
binaryType: "blob"
bufferedAmount: 0
constructor: WebSocketConstructor
extensions: ""
onclose: null
onerror: null
onmessage: null
onopen: null
protocol: ""
readyState: 1
url: "wss://ws.sendbird.com/?p=JS&pv=Mozilla%2F5.0%20(Macintosh%3B%20Intel%20Mac%20OS%20X)%20AppleWebKit%2F538.1%20(KHTML.%20like%20Gecko)%20PhantomJS%2F2.1.1%20Safari%2F538.1&sv=3.0.31&ai=A85703AE-17FD-49A6-9298-89BCA43AD59C&user_id=95666b98-17d2-5a87-8062-7840f8d63599&access_token=4cc3001fbcd8d41e576813ef6a196781d453bd7f"
__proto__: WebSocketPrototype |
@rokerkony , please try to modify
to
to try again. |
so no change... now the argument seems to be more correct, but I miss CLOSED: 3
CLOSING: 2
CONNECTING: 0
OPEN: 1
__zone_symbol__addEventListener: function addEventListener() {
__zone_symbol__removeEventListener: function removeEventListener() {
addEventListener: function (e, f, capture, secure) {
close: function close() {
dispatchEvent: function dispatchEvent() {
removeEventListener: function (e, f, capture, secure) {
send: function send() { so it means that |
@rokerkony , ok...,could you help me check where
|
@JiaLiPassion so after some time of investigation I can say that chrome has but PhantomJS looks like to have it only on the instance: WebSocket CLOSED: 3
CLOSING: 2
CONNECTING: 0
OPEN: 1
length: 1
prototype: WebSocketPrototype
__proto__: Object WebSocket.prototype CLOSED: 3
CLOSING: 2
CONNECTING: 0
OPEN: 1
__zone_symbol__addEventListener: function addEventListener() {
__zone_symbol__removeEventListener: function removeEventListener() {
addEventListener: function (e, f, capture, secure) {
close: function close() {
dispatchEvent: function dispatchEvent() {
removeEventListener: function (e, f, capture, secure) {
send: function send() {
__proto__: Object new WebSocket(...) URL: "ws://localhost:4200/sockjs-node/493/qgagpfbx/websocket"
binaryType: "blob"
bufferedAmount: 0
constructor: WebSocketConstructor
extensions: ""
onclose: null
onerror: null
onmessage: null
onopen: null
protocol: ""
readyState: 1
url: "ws://localhost:4200/sockjs-node/493/qgagpfbx/websocket"
__proto__: WebSocketPrototype |
@rokerkony , I just tried Phantomjs 2.1.14, and the Object.getOwnPropertyDescriptor(socket, 'onopen') return so the |
exactly, but socket is already an instance console.log('1:', Object.getOwnPropertyDescriptor(WS, 'onopen'));
var socket = arguments.length > 1 ? new WS(a, b) : new WS(a);
console.log('2:', Object.getOwnPropertyDescriptor(socket, 'onopen'));
console.log('3:', Object.getOwnPropertyDescriptor(_global.WebSocket, 'onopen'));
console.log('4:', Object.getOwnPropertyDescriptor(_global.WebSocket.prototype, 'onopen')); will output: 1: undefined
2: Object {value: null, writable: true, enumerable: true, configurable: false}
3: undefined
4: undefined Versions: which should be latest version for both packages... |
@rokerkony , yeah, that's why var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true }; because try to set |
Yeah I understand. But the modified code is not throwing an error for me (not in chrome nor phantom)... I returned this fallback for now and this is a result of var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true };
...
...
console.log('obj 1:', Object.assign({}, obj));
Object.defineProperty(obj, prop, desc);
console.log('obj 2:', Object.assign({}, obj)); Before patching: addEventListener: function () {
close: function () {
removeEventListener: function () {
send: function () {
__proto__: Object After patching: addEventListener: function () {
close: function () {
onclose: null
onerror: null
onmessage: null
onopen: null
removeEventListener: function () {
send: function () {
__proto__: Object but it is done in 4 steps for each method separately. |
could you print the |
actually it is not undefined... prop: onclose
desc: Object {enumerable: true, configurable: true, set: function, get: function}
obj1: Object {addEventListener: function, removeEventListener: function, send: function, close: function}
obj2: Object {addEventListener: function, removeEventListener: function, send: function, close: function, onclose: null}
prop: onerror
desc: Object {enumerable: true, configurable: true, set: function, get: function}
obj1: Object {addEventListener: function, removeEventListener: function, send: function, close: function, onclose: null}
obj2: Object {addEventListener: function, removeEventListener: function, send: function, close: function, onclose: null…}
prop: onmessage
desc: Object {enumerable: true, configurable: true, set: function, get: function}
obj1: Object {addEventListener: function, removeEventListener: function, send: function, close: function, onclose: null…}
obj2: Object {addEventListener: function, removeEventListener: function, send: function, close: function, onclose: null…}
prop: onopen
desc: Object {enumerable: true, configurable: true, set: function, get: function}
obj1: Object {addEventListener: function, removeEventListener: function, send: function, close: function, onclose: null…}
obj2: Object {addEventListener: function, removeEventListener: function, send: function, close: function, onclose: null…} if desc would be undefined it would not pass this condition: if (!desc || !desc.configurable) {
return;
} |
I think you print the information after this line var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true }; is that right? I think we should print the information before if (prop === 'onopen') {
console.log('obj', obj');
console.log('desc', Object.getOwnPropertyDescriptor(obj, prop));
}
var desc = Object.getOwnPropertyDescriptor(obj, prop) || { enumerable: true, configurable: true }; |
Ok, so this: function patchProperty(obj, prop, prototype) {
var desc = Object.getOwnPropertyDescriptor(obj, prop);
console.log('obj:', Object.assign({}, obj));
console.log('desc:', Object.getOwnPropertyDescriptor(obj, prop)); outputs to: obj:
Object {addEventListener: function, removeEventListener: function, send: function, close: function}
addEventListener: function () {
close: function () {
removeEventListener: function () {
send: function () {
__proto__: Object
desc: undefined in case I will add var desc = desc || { enumerable: true, configurable: true }; bellow console.log, it will add all |
@rokerkony , yeah, |
It looks like: I have an idea ... seems like console.log('naaah1', Object.getOwnPropertyDescriptor(socket, 'onopen'));
proxySocket = Object.create(socket);
console.log('naaah2', Object.getOwnPropertyDescriptor(proxySocket, 'onopen')); it outputs: naaah1: Object {value: null, writable: true, enumerable: true, configurable: false} vendor.bundle.js:4618
naaah2: undefined |
@rokerkony , I see. could you try the attached zone.js.zip? |
yes! that is working 👍 |
@rokerkony , ok, thank you for confirm it, I will make a PR to fix this one. |
thx for helping |
…ly in phantomjs
…ly in phantomjs
…ly in phantomjs
Hi,
changes introduced in #768 (specifically changes on function
patchProperty(...)
) are causing us problem with running e2e tests in angular (4.2.2) and we cannot upgrade Zone.js from 0.8.10 to higher version.When I drop changes manually on method
patchProperty(...)
, it works as before.Problem occurs when we run SendBird connect method which is connecting to WebSockets
this.sendbird.connect(userId, accessToken, (user: User, connectError: any) => {
Call stack from running tests:
The text was updated successfully, but these errors were encountered: