mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-21 22:58:24 +00:00
fix web tests
This commit is contained in:
parent
0585e690c4
commit
3ad4949c0e
@ -1,4 +1,5 @@
|
||||
import uuid
|
||||
from typing import Literal, Union
|
||||
|
||||
from mitmproxy import connection
|
||||
from mitmproxy import controller
|
||||
@ -66,14 +67,8 @@ def twebsocketflow(messages=True, err=None, close_code=None, close_reason='') ->
|
||||
timestamp_start=946681202,
|
||||
timestamp_end=946681203,
|
||||
)
|
||||
flow.websocket = websocket.WebSocketData()
|
||||
|
||||
if messages is True:
|
||||
flow.websocket.messages = [
|
||||
websocket.WebSocketMessage(Opcode.BINARY, True, b"hello binary", 946681203),
|
||||
websocket.WebSocketMessage(Opcode.TEXT, True, b"hello text", 946681204),
|
||||
websocket.WebSocketMessage(Opcode.TEXT, False, b"it's me", 946681205),
|
||||
]
|
||||
flow.websocket = twebsocket()
|
||||
|
||||
flow.websocket.close_reason = close_reason
|
||||
|
||||
@ -91,15 +86,15 @@ def twebsocketflow(messages=True, err=None, close_code=None, close_reason='') ->
|
||||
return flow
|
||||
|
||||
|
||||
def tflow(client_conn=True, server_conn=True, req=True, resp=None, err=None) -> http.HTTPFlow:
|
||||
"""
|
||||
@type client_conn: bool | None | mitmproxy.proxy.connection.ClientConnection
|
||||
@type server_conn: bool | None | mitmproxy.proxy.connection.ServerConnection
|
||||
@type req: bool | None | mitmproxy.proxy.protocol.http.Request
|
||||
@type resp: bool | None | mitmproxy.proxy.protocol.http.Response
|
||||
@type err: bool | None | mitmproxy.proxy.protocol.primitives.Error
|
||||
@return: mitmproxy.proxy.protocol.http.HTTPFlow
|
||||
"""
|
||||
def tflow(
|
||||
client_conn: Union[Literal[True], None, connection.Client] = True,
|
||||
server_conn: Union[Literal[True], None, connection.Server] = True,
|
||||
req: Union[Literal[True], None, http.Request] = True,
|
||||
resp: Union[Literal[True], None, http.Response] = None,
|
||||
err: Union[Literal[True], None, flow.Error] = None,
|
||||
ws: Union[Literal[True], None, websocket.WebSocketData] = None,
|
||||
) -> http.HTTPFlow:
|
||||
"""Create a flow for testing."""
|
||||
if client_conn is True:
|
||||
client_conn = tclient_conn()
|
||||
if server_conn is True:
|
||||
@ -110,11 +105,14 @@ def tflow(client_conn=True, server_conn=True, req=True, resp=None, err=None) ->
|
||||
resp = tresp()
|
||||
if err is True:
|
||||
err = terr()
|
||||
if ws is True:
|
||||
ws = twebsocket()
|
||||
|
||||
f = http.HTTPFlow(client_conn, server_conn)
|
||||
f.request = req
|
||||
f.response = resp
|
||||
f.error = err
|
||||
f.websocket = ws
|
||||
f.reply = controller.DummyReply()
|
||||
return f
|
||||
|
||||
@ -197,3 +195,20 @@ def tserver_conn() -> connection.Server:
|
||||
def terr(content: str = "error") -> flow.Error:
|
||||
err = flow.Error(content, 946681207)
|
||||
return err
|
||||
|
||||
|
||||
def twebsocket(messages: bool = True) -> websocket.WebSocketData:
|
||||
ws = websocket.WebSocketData()
|
||||
|
||||
if messages:
|
||||
ws.messages = [
|
||||
websocket.WebSocketMessage(Opcode.BINARY, True, b"hello binary", 946681203),
|
||||
websocket.WebSocketMessage(Opcode.TEXT, True, b"hello text", 946681204),
|
||||
websocket.WebSocketMessage(Opcode.TEXT, False, b"it's me", 946681205),
|
||||
]
|
||||
ws.close_reason = "Close Reason"
|
||||
ws.close_code = 1000
|
||||
ws.closed_by_client = False
|
||||
ws.timestamp_end = 946681205
|
||||
|
||||
return ws
|
||||
|
2
mitmproxy/tools/web/static/app.css
vendored
2
mitmproxy/tools/web/static/app.css
vendored
File diff suppressed because one or more lines are too long
103
mitmproxy/tools/web/static/app.js
vendored
103
mitmproxy/tools/web/static/app.js
vendored
File diff suppressed because one or more lines are too long
6
mitmproxy/tools/web/static/vendor.css
vendored
6
mitmproxy/tools/web/static/vendor.css
vendored
File diff suppressed because one or more lines are too long
@ -324,7 +324,7 @@ class TestApp(tornado.testing.AsyncHTTPTestCase):
|
||||
ws_client2.close()
|
||||
|
||||
def test_generate_tflow_js(self):
|
||||
tf = tflow.tflow(resp=True, err=True)
|
||||
tf = tflow.tflow(resp=True, err=True, ws=True)
|
||||
tf.request.trailers = Headers(trailer="qvalue")
|
||||
tf.response.trailers = Headers(trailer="qvalue")
|
||||
|
||||
@ -342,9 +342,9 @@ class TestApp(tornado.testing.AsyncHTTPTestCase):
|
||||
).replace(": null", ": undefined")
|
||||
|
||||
content = (
|
||||
"/** Auto-generated by test_app.py:TestApp._test_generate_tflow_js */\n"
|
||||
"/** Auto-generated by test_app.py:TestApp.test_generate_tflow_js */\n"
|
||||
"import {HTTPFlow} from '../../flow';\n"
|
||||
"export default function(): HTTPFlow {\n"
|
||||
"export default function(): Required<HTTPFlow> {\n"
|
||||
f" return {tflow_json}\n"
|
||||
"}"
|
||||
)
|
||||
|
133
web/package-lock.json
generated
133
web/package-lock.json
generated
@ -2651,12 +2651,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.15.2",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.15.2.tgz",
|
||||
"integrity": "sha512-tKs41J7NJVuaya8DxIOCnl8QuPHx5/ZVbFo1oKgVl1qHFBBrDctzQGtuLjPpRdNTWmKPH6oEvgN/MUID+l485Q==",
|
||||
"dev": true
|
||||
},
|
||||
"core-js-pure": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.15.0.tgz",
|
||||
@ -2669,6 +2663,15 @@
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true
|
||||
},
|
||||
"cross-fetch": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz",
|
||||
"integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-fetch": "2.6.1"
|
||||
}
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
@ -3521,52 +3524,6 @@
|
||||
"bser": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"fetch-mock": {
|
||||
"version": "9.11.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-9.11.0.tgz",
|
||||
"integrity": "sha512-PG1XUv+x7iag5p/iNHD4/jdpxL9FtVSqRMUQhPab4hVDt80T1MH5ehzVrL2IdXO9Q2iBggArFvPqjUbHFuI58Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"core-js": "^3.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"glob-to-regexp": "^0.4.0",
|
||||
"is-subset": "^0.1.1",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"path-to-regexp": "^2.2.1",
|
||||
"querystring": "^0.2.0",
|
||||
"whatwg-url": "^6.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tr46": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
|
||||
"integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
|
||||
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
|
||||
"dev": true
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
|
||||
"integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash.sortby": "^4.7.0",
|
||||
"tr46": "^1.0.1",
|
||||
"webidl-conversions": "^4.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
|
||||
@ -3864,12 +3821,6 @@
|
||||
"unique-stream": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"glob-to-regexp": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
|
||||
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
|
||||
"dev": true
|
||||
},
|
||||
"glob-watcher": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz",
|
||||
@ -5191,12 +5142,6 @@
|
||||
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
|
||||
"dev": true
|
||||
},
|
||||
"is-subset": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz",
|
||||
"integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=",
|
||||
"dev": true
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
@ -5535,6 +5480,16 @@
|
||||
"jest-util": "^27.0.2"
|
||||
}
|
||||
},
|
||||
"jest-fetch-mock": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz",
|
||||
"integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cross-fetch": "^3.0.4",
|
||||
"promise-polyfill": "^8.1.3"
|
||||
}
|
||||
},
|
||||
"jest-get-type": {
|
||||
"version": "27.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.1.tgz",
|
||||
@ -6313,12 +6268,6 @@
|
||||
"integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.isequal": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
|
||||
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.isobject": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz",
|
||||
@ -6331,7 +6280,8 @@
|
||||
"lodash.isplainobject": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
|
||||
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.keys": {
|
||||
"version": "2.4.1",
|
||||
@ -6362,12 +6312,6 @@
|
||||
"integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.sortby": {
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
||||
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.template": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
|
||||
@ -6768,11 +6712,6 @@
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"mock-xmlhttprequest": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/mock-xmlhttprequest/-/mock-xmlhttprequest-1.2.0.tgz",
|
||||
"integrity": "sha512-iCP2jcd8WUrswkminVid7gL3PQ1hhD2UnfEV0dkQjdZmvLPS8mVhIooX1sooGF8/8RkVp4wwVI+wj7zo2S7seQ=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
@ -7294,12 +7233,6 @@
|
||||
"integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
|
||||
"dev": true
|
||||
},
|
||||
"path-to-regexp": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.4.0.tgz",
|
||||
"integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==",
|
||||
"dev": true
|
||||
},
|
||||
"path-type": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
|
||||
@ -7494,6 +7427,12 @@
|
||||
"asap": "~2.0.3"
|
||||
}
|
||||
},
|
||||
"promise-polyfill": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.0.tgz",
|
||||
"integrity": "sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g==",
|
||||
"dev": true
|
||||
},
|
||||
"prompts": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz",
|
||||
@ -7578,12 +7517,6 @@
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz",
|
||||
"integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==",
|
||||
"dev": true
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz",
|
||||
@ -7621,7 +7554,8 @@
|
||||
"react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
|
||||
"dev": true
|
||||
},
|
||||
"react-popper": {
|
||||
"version": "2.2.5",
|
||||
@ -7682,6 +7616,7 @@
|
||||
"version": "16.14.1",
|
||||
"resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz",
|
||||
"integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.12.0 || ^17.0.0"
|
||||
@ -7691,6 +7626,7 @@
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz",
|
||||
"integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^17.0.2",
|
||||
@ -7843,6 +7779,7 @@
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.4.tgz",
|
||||
"integrity": "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash.isplainobject": "^4.0.6"
|
||||
}
|
||||
@ -9212,6 +9149,12 @@
|
||||
"is-typedarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
|
||||
"integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "2.8.29",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
|
||||
|
@ -5,7 +5,7 @@
|
||||
"verbose": true
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest --coverage",
|
||||
"test": "tsc --noEmit && jest --coverage",
|
||||
"build": "gulp prod",
|
||||
"start": "gulp"
|
||||
},
|
||||
@ -15,15 +15,12 @@
|
||||
"classnames": "^2.3.1",
|
||||
"codemirror": "^5.62.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mock-xmlhttprequest": "^1.1.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-popper": "^2.2.5",
|
||||
"react-redux": "^7.2.4",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"redux": "^4.1.0",
|
||||
"redux-mock-store": "^1.5.4",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"shallowequal": "^1.1.0",
|
||||
"stable": "^0.1.8"
|
||||
@ -34,7 +31,6 @@
|
||||
"@types/redux-mock-store": "^1.0.2",
|
||||
"esbuild": "^0.12.9",
|
||||
"esbuild-jest": "^0.5.0",
|
||||
"fetch-mock": "^9.11.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-clean-css": "^4.3.0",
|
||||
"gulp-esbuild": "^0.8.2",
|
||||
@ -46,7 +42,10 @@
|
||||
"gulp-replace": "^1.1.3",
|
||||
"gulp-sourcemaps": "^3.0.0",
|
||||
"jest": "^27.0.4",
|
||||
"node-fetch": "^2.6.1",
|
||||
"through2": "^4.0.2"
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"react-test-renderer": "^17.0.2",
|
||||
"redux-mock-store": "^1.5.4",
|
||||
"through2": "^4.0.2",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
import * as React from "react"
|
||||
import CommandBar from '../../../components/CommandBar'
|
||||
import { render } from "../../test-utils"
|
||||
import fetchMock from 'fetch-mock';
|
||||
import { act, waitFor } from '@testing-library/react'
|
||||
import {render} from "../../test-utils"
|
||||
import fetchMock, {enableFetchMocks} from "jest-fetch-mock";
|
||||
import {waitFor} from '@testing-library/react'
|
||||
|
||||
enableFetchMocks()
|
||||
|
||||
|
||||
test('CommandBar Component', async () => {
|
||||
fetchMock.get('./commands.json', {status: 200, body: {"commands": "foo"}})
|
||||
fetchMock.mockResponseOnce(JSON.stringify({"commands": "foo"}));
|
||||
|
||||
const {asFragment, store} = render(
|
||||
<CommandBar/>
|
||||
|
26
web/src/js/__tests__/components/CommandBarSpec.tsx
Normal file
26
web/src/js/__tests__/components/CommandBarSpec.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import * as React from "react"
|
||||
import {render, waitFor, screen} from "../test-utils";
|
||||
import CommandBar from "../../components/CommandBar";
|
||||
import fetchMock, {enableFetchMocks} from "jest-fetch-mock";
|
||||
|
||||
enableFetchMocks();
|
||||
|
||||
test("CommandBar", async () => {
|
||||
fetchMock.mockResponseOnce(JSON.stringify({
|
||||
"flow.decode": {"help": "Decode flows.",
|
||||
"parameters": [{"name": "flows", "type": "flow[]", "kind": "POSITIONAL_OR_KEYWORD"}, {
|
||||
"name": "part",
|
||||
"type": "str",
|
||||
"kind": "POSITIONAL_OR_KEYWORD"
|
||||
}],
|
||||
"return_type": null,
|
||||
"signature_help": "flow.decode flows part"
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
const {asFragment} = render(<CommandBar/>);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
await waitFor(() => screen.getByText('["flow.decode"]'))
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
@ -1,14 +0,0 @@
|
||||
jest.mock("../../../contrib/CodeMirror")
|
||||
import * as React from 'react';
|
||||
import CodeEditor from '../../../components/ContentView/CodeEditor'
|
||||
import {render} from '@testing-library/react'
|
||||
|
||||
|
||||
test("CodeEditor", async () => {
|
||||
|
||||
const changeFn = jest.fn(),
|
||||
{asFragment} = render(
|
||||
<CodeEditor content="foo" onChange={changeFn}/>
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot()
|
||||
});
|
@ -1,74 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import withContentLoader from '../../../components/contentviews/useContent'
|
||||
import { TFlow } from '../../ducks/tutils'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import mockXMLHttpRequest from 'mock-xmlhttprequest'
|
||||
|
||||
global.XMLHttpRequest = mockXMLHttpRequest
|
||||
class tComponent extends React.Component {
|
||||
constructor(props, context){
|
||||
super(props, context)
|
||||
}
|
||||
render() {
|
||||
return (<p>foo</p>)
|
||||
}
|
||||
}
|
||||
|
||||
let tflow = new TFlow(),
|
||||
ContentLoader = withContentLoader(tComponent)
|
||||
|
||||
describe('ContentLoader Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let contentLoader = renderer.create(<ContentLoader flow={tflow} message={tflow.response}/>),
|
||||
tree = contentLoader.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let contentLoader = TestUtils.renderIntoDocument(<ContentLoader flow={tflow} message={tflow.response}/>)
|
||||
|
||||
it('should handle updateContent', () => {
|
||||
tflow.response.content = 'foo'
|
||||
contentLoader.updateContent({flow: tflow, message: tflow.response})
|
||||
expect(contentLoader.state.request).toEqual(undefined)
|
||||
expect(contentLoader.state.content).toEqual('foo')
|
||||
// when content length is 0 or null
|
||||
tflow.response.contentLength = 0
|
||||
tflow.response.content = undefined
|
||||
contentLoader.updateContent({flow: tflow, message: tflow.response})
|
||||
expect(contentLoader.state.request).toEqual(undefined)
|
||||
expect(contentLoader.state.content).toEqual('')
|
||||
})
|
||||
|
||||
it('should handle componentWillReceiveProps', () => {
|
||||
contentLoader.updateContent = jest.fn()
|
||||
contentLoader.UNSAFE_componentWillReceiveProps({flow: tflow, message: tflow.request})
|
||||
expect(contentLoader.updateContent).toBeCalled()
|
||||
})
|
||||
|
||||
it('should handle requestComplete', () => {
|
||||
expect(contentLoader.requestComplete(tflow.request, {})).toEqual(undefined)
|
||||
// request == this.state.request
|
||||
contentLoader.state.request = tflow.request
|
||||
contentLoader.requestComplete(tflow.request, {})
|
||||
expect(contentLoader.state.content).toEqual(tflow.request.responseText)
|
||||
expect(contentLoader.state.request).toEqual(undefined)
|
||||
})
|
||||
|
||||
it('should handle requestFailed', () => {
|
||||
console.error = jest.fn()
|
||||
expect(contentLoader.requestFailed(tflow.request, {})).toEqual(undefined)
|
||||
//request == this.state.request
|
||||
contentLoader.state.request = tflow.request
|
||||
contentLoader.requestFailed(tflow.request, 'foo error')
|
||||
expect(contentLoader.state.content).toEqual('Error getting content.')
|
||||
expect(contentLoader.state.request).toEqual(undefined)
|
||||
expect(console.error).toBeCalledWith('foo error')
|
||||
})
|
||||
|
||||
it('should handle componentWillUnmount', () => {
|
||||
contentLoader.state.request = { abort : jest.fn() }
|
||||
contentLoader.componentWillUnmount()
|
||||
expect(contentLoader.state.request.abort).toBeCalled()
|
||||
})
|
||||
})
|
@ -1,20 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import ContentViewOptions from '../../../components/ContentView/ContentViewOptions'
|
||||
import { Provider } from 'react-redux'
|
||||
import { TFlow, TStore } from '../../ducks/tutils'
|
||||
import { uploadContent } from '../../../ducks/flows'
|
||||
|
||||
let tflow = new TFlow()
|
||||
|
||||
describe('ContentViewOptions Component', () => {
|
||||
let store = TStore()
|
||||
it('should render correctly', () => {
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<ContentViewOptions flow={tflow} message={tflow.response} uploadContent={uploadContent}/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,60 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import { Provider } from 'react-redux'
|
||||
import { ViewServer, ViewImage, PureViewServer, Edit } from '../../../components/ContentView/ContentViews'
|
||||
import { TFlow, TStore } from '../../ducks/tutils'
|
||||
import mockXMLHttpRequest from 'mock-xmlhttprequest'
|
||||
|
||||
window.XMLHttpRequest = mockXMLHttpRequest
|
||||
let tflow = new TFlow()
|
||||
|
||||
describe('ViewImage Component', () => {
|
||||
let viewImage = renderer.create(<ViewImage flow={tflow} message={tflow.response}/>),
|
||||
tree = viewImage.toJSON()
|
||||
|
||||
it('should render correctly', () => {
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('ViewServer Component', () => {
|
||||
let store = TStore()
|
||||
|
||||
it('should render correctly and connect to state', () => {
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<ViewServer
|
||||
flow={tflow}
|
||||
message={tflow.response}
|
||||
/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
|
||||
let viewServer = renderer.create(
|
||||
<Provider store={store}>
|
||||
<PureViewServer
|
||||
flow={tflow}
|
||||
message={tflow.response}
|
||||
content={JSON.stringify({lines: [['k1', 'v1']]})}
|
||||
/>
|
||||
</Provider>
|
||||
)
|
||||
tree = viewServer.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edit Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let edit = renderer.create(<Edit
|
||||
content="foo"
|
||||
onChange={jest.fn}
|
||||
flow={tflow}
|
||||
message={tflow.response}
|
||||
/>),
|
||||
tree = edit.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,15 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import DownloadContentButton from '../../../components/ContentView/DownloadContentButton'
|
||||
import { TFlow } from '../../ducks/tutils'
|
||||
|
||||
let tflow = new TFlow()
|
||||
describe('DownloadContentButton Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let downloadContentButton = renderer.create(
|
||||
<DownloadContentButton flow={tflow} message={tflow.response}/>
|
||||
),
|
||||
tree = downloadContentButton.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,37 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import { ContentEmpty, ContentMissing, ContentTooLarge } from '../../../components/ContentView/MetaViews'
|
||||
import { TFlow } from '../../ducks/tutils'
|
||||
|
||||
let tflow = new TFlow()
|
||||
|
||||
describe('ContentEmpty Components', () => {
|
||||
it('should render correctly', () => {
|
||||
let contentEmpty = renderer.create(<ContentEmpty flow={tflow} message={tflow.response}/>),
|
||||
tree = contentEmpty.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('ContentMissing Components', () => {
|
||||
it('should render correctly', () => {
|
||||
let contentMissing = renderer.create(<ContentMissing flow={tflow} message={tflow.response}/>),
|
||||
tree = contentMissing.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('ContentTooLarge Components', () => {
|
||||
it('should render correctly', () => {
|
||||
let clickFn = jest.fn(),
|
||||
uploadContentFn = jest.fn(),
|
||||
contentTooLarge = renderer.create(<ContentTooLarge
|
||||
flow={tflow}
|
||||
message={tflow.response}
|
||||
onClick={clickFn}
|
||||
uploadContent={uploadContentFn}
|
||||
/>),
|
||||
tree = contentTooLarge.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,22 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import { Provider } from 'react-redux'
|
||||
import ShowFullContentButton from '../../../components/ContentView/ShowFullContentButton'
|
||||
import { TStore } from '../../ducks/tutils'
|
||||
|
||||
|
||||
describe('ShowFullContentButton Component', () => {
|
||||
let store = TStore()
|
||||
|
||||
let setShowFullContentFn = jest.fn(),
|
||||
showFullContentButton = renderer.create(
|
||||
<Provider store={store}>
|
||||
<ShowFullContentButton />
|
||||
</Provider>
|
||||
),
|
||||
tree = showFullContentButton.toJSON()
|
||||
|
||||
it('should render correctly', () => {
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,12 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import UploadContentButton from '../../../components/ContentView/UploadContentButton'
|
||||
|
||||
describe('UpdateContentButton Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let uploadContentFn = jest.fn(),
|
||||
uploadContentButton = renderer.create(<UploadContentButton uploadContent={uploadContentFn}/>),
|
||||
tree = uploadContentButton.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,20 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import ViewSelector from '../../../components/ContentView/ViewSelector'
|
||||
import { Provider } from 'react-redux'
|
||||
import { TStore } from '../../ducks/tutils'
|
||||
|
||||
|
||||
describe('ViewSelector Component', () => {
|
||||
let store = TStore(),
|
||||
viewSelector = renderer.create(
|
||||
<Provider store={store}>
|
||||
<ViewSelector/>
|
||||
</Provider>
|
||||
),
|
||||
tree = viewSelector.toJSON()
|
||||
|
||||
it('should render correctly', () => {
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,11 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ContentLoader Component should render correctly 1`] = `
|
||||
<div
|
||||
className="text-center"
|
||||
>
|
||||
<i
|
||||
className="fa fa-spinner fa-spin"
|
||||
/>
|
||||
</div>
|
||||
`;
|
@ -1,41 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ContentViewOptions Component should render correctly 1`] = `
|
||||
<div
|
||||
className="view-options"
|
||||
>
|
||||
<span>
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
edit
|
||||
</span>
|
||||
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content.data"
|
||||
title="Download the content of the flow."
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-upload"
|
||||
/>
|
||||
<input
|
||||
className="hidden"
|
||||
onChange={[Function]}
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
`;
|
@ -1,39 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Edit Component should render correctly 1`] = `
|
||||
<div
|
||||
className="text-center"
|
||||
>
|
||||
<i
|
||||
className="fa fa-spinner fa-spin"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ViewImage Component should render correctly 1`] = `
|
||||
<div
|
||||
className="flowview-image"
|
||||
>
|
||||
<img
|
||||
alt="preview"
|
||||
className="img-thumbnail"
|
||||
src="./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content.data"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ViewServer Component should render correctly and connect to state 1`] = `
|
||||
<div
|
||||
className="text-center"
|
||||
>
|
||||
<i
|
||||
className="fa fa-spinner fa-spin"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ViewServer Component should render correctly and connect to state 2`] = `
|
||||
<div>
|
||||
<pre />
|
||||
</div>
|
||||
`;
|
@ -1,13 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`DownloadContentButton Component should render correctly 1`] = `
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content.data"
|
||||
title="Download the content of the flow."
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
/>
|
||||
</a>
|
||||
`;
|
@ -1,66 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ContentEmpty Components should render correctly 1`] = `
|
||||
<div
|
||||
className="alert alert-info"
|
||||
>
|
||||
No
|
||||
response
|
||||
content.
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ContentMissing Components should render correctly 1`] = `
|
||||
<div
|
||||
className="alert alert-info"
|
||||
>
|
||||
Response
|
||||
content missing.
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ContentTooLarge Components should render correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="alert alert-warning"
|
||||
>
|
||||
<button
|
||||
className="btn btn-xs btn-warning pull-right"
|
||||
onClick={[MockFunction]}
|
||||
>
|
||||
Display anyway
|
||||
</button>
|
||||
7b
|
||||
content size.
|
||||
</div>
|
||||
<div
|
||||
className="view-options text-center"
|
||||
>
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-upload"
|
||||
/>
|
||||
<input
|
||||
className="hidden"
|
||||
onChange={[Function]}
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content.data"
|
||||
title="Download the content of the flow."
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -1,3 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ShowFullContentButton Component should render correctly 1`] = `null`;
|
@ -1,19 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`UpdateContentButton Component should render correctly 1`] = `
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-upload"
|
||||
/>
|
||||
<input
|
||||
className="hidden"
|
||||
onChange={[Function]}
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
`;
|
@ -1,21 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ViewSelector Component should render correctly 1`] = `
|
||||
<a
|
||||
className="btn btn-default btn-xs pull-left"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<span>
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
|
||||
auto
|
||||
|
||||
<span
|
||||
className="caret"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
`;
|
@ -1,62 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import ContentView from '../../components/ContentView'
|
||||
import { TStore, TFlow } from '../ducks/tutils'
|
||||
import { Provider } from 'react-redux'
|
||||
import mockXMLHttpRequest from 'mock-xmlhttprequest'
|
||||
|
||||
window.XMLHttpRequest = mockXMLHttpRequest
|
||||
|
||||
describe('ContentView Component', () => {
|
||||
let store = TStore()
|
||||
|
||||
it('should render correctly', () => {
|
||||
store.getState().ui.flow.contentView = 'Edit'
|
||||
let tflow = TFlow(),
|
||||
provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<ContentView flow={tflow} message={tflow.request}/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render correctly with empty content', () => {
|
||||
let tflow = TFlow()
|
||||
tflow.response.contentLength = 0
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<ContentView flow={tflow} message={tflow.response} readonly={true}/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render correctly with missing content', () => {
|
||||
let tflow = TFlow()
|
||||
tflow.response.contentLength = null
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<ContentView flow={tflow} message={tflow.response} readonly={true}/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render correctly with content too large', () => {
|
||||
let tflow = TFlow()
|
||||
tflow.response.contentLength = 1024 * 1024 * 100
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<ContentView
|
||||
flow={tflow}
|
||||
message={tflow.response}
|
||||
readonly={true}
|
||||
uploadContent={jest.fn()}
|
||||
onOpenFile={jest.fn()}
|
||||
/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,137 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import {
|
||||
icon,
|
||||
method,
|
||||
path,
|
||||
quickactions,
|
||||
size,
|
||||
status,
|
||||
time,
|
||||
timestamp,
|
||||
tls
|
||||
} from '../../../components/FlowTable/FlowColumns'
|
||||
import {TFlow, TStore} from '../../ducks/tutils'
|
||||
import {Provider} from 'react-redux'
|
||||
|
||||
describe('Flowcolumns Components', () => {
|
||||
|
||||
let tflow = TFlow()
|
||||
it('should render TLSColumn', () => {
|
||||
let tlsColumn = renderer.create(<tls flow={tflow}/>),
|
||||
tree = tlsColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render IconColumn', () => {
|
||||
let tflow = TFlow(),
|
||||
iconColumn = renderer.create(<icon flow={tflow}/>),
|
||||
tree = iconColumn.toJSON()
|
||||
// plain
|
||||
expect(tree).toMatchSnapshot()
|
||||
// not modified
|
||||
tflow.response.status_code = 304
|
||||
iconColumn = renderer.create(<icon flow={tflow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// redirect
|
||||
tflow.response.status_code = 302
|
||||
iconColumn = renderer.create(<icon flow={tflow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// image
|
||||
let imageFlow = TFlow()
|
||||
imageFlow.response.headers = [['Content-Type', 'image/jpeg']]
|
||||
iconColumn = renderer.create(<icon flow={imageFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// javascript
|
||||
let jsFlow = TFlow()
|
||||
jsFlow.response.headers = [['Content-Type', 'application/x-javascript']]
|
||||
iconColumn = renderer.create(<icon flow={jsFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// css
|
||||
let cssFlow = TFlow()
|
||||
cssFlow.response.headers = [['Content-Type', 'text/css']]
|
||||
iconColumn = renderer.create(<icon flow={cssFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// html
|
||||
let htmlFlow = TFlow()
|
||||
htmlFlow.response.headers = [['Content-Type', 'text/html']]
|
||||
iconColumn = renderer.create(<icon flow={htmlFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// default
|
||||
let fooFlow = TFlow()
|
||||
fooFlow.response.headers = [['Content-Type', 'foo']]
|
||||
iconColumn = renderer.create(<icon flow={fooFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// no response
|
||||
tflow.response = null
|
||||
iconColumn = renderer.create(<icon flow={tflow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render pathColumn', () => {
|
||||
let tflow = TFlow(),
|
||||
pathColumn = renderer.create(<path flow={tflow}/>),
|
||||
tree = pathColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
|
||||
tflow.error.msg = 'Connection killed.'
|
||||
tflow.intercepted = true
|
||||
pathColumn = renderer.create(<path flow={tflow}/>)
|
||||
tree = pathColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render MethodColumn', () => {
|
||||
let methodColumn = renderer.create(<method flow={tflow}/>),
|
||||
tree = methodColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render StatusColumn', () => {
|
||||
let statusColumn = renderer.create(<status flow={tflow}/>),
|
||||
tree = statusColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render SizeColumn', () => {
|
||||
let sizeColumn = renderer.create(<size flow={tflow}/>),
|
||||
tree = sizeColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render TimeColumn', () => {
|
||||
let tflow = TFlow(),
|
||||
timeColumn = renderer.create(<time flow={tflow}/>),
|
||||
tree = timeColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
|
||||
tflow.response = null
|
||||
timeColumn = renderer.create(<time flow={tflow}/>)
|
||||
tree = timeColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render TimeStampColumn', () => {
|
||||
let timeStampColumn = renderer.create(<timestamp flow={tflow}/>),
|
||||
tree = timeStampColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render QuickActionsColumn', () => {
|
||||
let store = TStore(),
|
||||
provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<quickactions flow={tflow}/>
|
||||
</Provider>),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -0,0 +1,98 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import FlowColumns from '../../../components/FlowTable/FlowColumns'
|
||||
import {TFlow} from '../../ducks/tutils'
|
||||
import {render} from "../../test-utils";
|
||||
|
||||
test("should render columns", async () => {
|
||||
const tflow = TFlow();
|
||||
Object.entries(FlowColumns).forEach(([name, Col]) => {
|
||||
const {asFragment} = render(<table>
|
||||
<tbody>
|
||||
<tr><Col flow={tflow}/></tr>
|
||||
</tbody>
|
||||
</table>)
|
||||
expect(asFragment()).toMatchSnapshot(name);
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
describe('Flowcolumns Components', () => {
|
||||
it('should render IconColumn', () => {
|
||||
let tflow = {...TFlow(), websocket: undefined},
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={tflow}/>),
|
||||
tree = iconColumn.toJSON()
|
||||
// plain
|
||||
expect(tree).toMatchSnapshot()
|
||||
// not modified
|
||||
tflow.response.status_code = 304
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={tflow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// redirect
|
||||
tflow.response.status_code = 302
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={tflow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// image
|
||||
let imageFlow = {...TFlow(), websocket: undefined}
|
||||
imageFlow.response.headers = [['Content-Type', 'image/jpeg']]
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={imageFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// javascript
|
||||
let jsFlow = {...TFlow(), websocket: undefined}
|
||||
jsFlow.response.headers = [['Content-Type', 'application/x-javascript']]
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={jsFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// css
|
||||
let cssFlow = {...TFlow(), websocket: undefined}
|
||||
cssFlow.response.headers = [['Content-Type', 'text/css']]
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={cssFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// html
|
||||
let htmlFlow = {...TFlow(), websocket: undefined}
|
||||
htmlFlow.response.headers = [['Content-Type', 'text/html']]
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={htmlFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// default
|
||||
let fooFlow = {...TFlow(), websocket: undefined}
|
||||
fooFlow.response.headers = [['Content-Type', 'foo']]
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={fooFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// no response
|
||||
let noResponseFlow = {...TFlow(), response: undefined}
|
||||
iconColumn = renderer.create(<FlowColumns.icon flow={noResponseFlow}/>)
|
||||
tree = iconColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render pathColumn', () => {
|
||||
let tflow = TFlow(),
|
||||
pathColumn = renderer.create(<FlowColumns.path flow={tflow}/>),
|
||||
tree = pathColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
|
||||
tflow.error.msg = 'Connection killed.'
|
||||
tflow.intercepted = true
|
||||
pathColumn = renderer.create(<FlowColumns.path flow={tflow}/>)
|
||||
tree = pathColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render TimeColumn', () => {
|
||||
let tflow = TFlow(),
|
||||
timeColumn = renderer.create(<FlowColumns.time flow={tflow}/>),
|
||||
tree = timeColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
|
||||
let noResponseFlow = {...tflow, response: undefined}
|
||||
timeColumn = renderer.create(<FlowColumns.time flow={noResponseFlow}/>)
|
||||
tree = timeColumn.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -7,15 +7,15 @@ import {createAppStore} from "../../../ducks";
|
||||
|
||||
test("FlowRow", async () => {
|
||||
const store = createAppStore(testState),
|
||||
tflow2 = store.getState().flows.view[1],
|
||||
tflow2 = store.getState().flows.list[0],
|
||||
{asFragment} = render(<table>
|
||||
<tbody>
|
||||
<FlowRow flow={tflow2} selected highlighted/>
|
||||
</tbody>
|
||||
</table>, {store})
|
||||
expect(asFragment()).toMatchSnapshot()
|
||||
expect(store.getState().flows.selected[0]).toBe(store.getState().flows.view[0].id)
|
||||
|
||||
fireEvent.click(screen.getByText("http://address:22/second"))
|
||||
expect(store.getState().flows.selected[0]).toBe(store.getState().flows.view[1].id)
|
||||
expect(store.getState().flows.selected[0]).not.toBe(store.getState().flows.list[0].id)
|
||||
fireEvent.click(screen.getByText("http://address:22/path"))
|
||||
expect(store.getState().flows.selected[0]).toBe(store.getState().flows.list[0].id)
|
||||
})
|
||||
|
@ -1,203 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 1`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-plain"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 2`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-not-modified"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 3`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-redirect"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 4`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-image"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 5`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-js"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 6`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-css"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 7`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-document"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 8`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-plain"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 9`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-plain"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render MethodColumn 1`] = `
|
||||
<td
|
||||
className="col-method"
|
||||
>
|
||||
GET
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render QuickActionsColumn 1`] = `
|
||||
<td
|
||||
className="col-quickactions"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<div>
|
||||
<a
|
||||
className="quickaction"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-repeat text-primary"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
className="quickaction"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-ellipsis-h text-muted"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render SizeColumn 1`] = `
|
||||
<td
|
||||
className="col-size"
|
||||
>
|
||||
14b
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render StatusColumn 1`] = `
|
||||
<td
|
||||
className="col-status"
|
||||
style={
|
||||
Object {
|
||||
"color": "darkgreen",
|
||||
}
|
||||
}
|
||||
>
|
||||
200
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render TLSColumn 1`] = `
|
||||
<td
|
||||
className="col-tls col-tls-https"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render TimeColumn 1`] = `
|
||||
<td
|
||||
className="col-time"
|
||||
>
|
||||
3s
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render TimeColumn 2`] = `
|
||||
<td
|
||||
className="col-time"
|
||||
>
|
||||
...
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render TimeStampColumn 1`] = `
|
||||
<td
|
||||
className="col-start"
|
||||
>
|
||||
1999-12-31 23:00:00.000
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render pathColumn 1`] = `
|
||||
<td
|
||||
className="col-path"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-exclamation pull-right"
|
||||
/>
|
||||
http://address:22/path
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render pathColumn 2`] = `
|
||||
<td
|
||||
className="col-path"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-pause pull-right"
|
||||
/>
|
||||
<i
|
||||
className="fa fa-fw fa-times pull-right"
|
||||
/>
|
||||
http://address:22/path
|
||||
</td>
|
||||
`;
|
@ -0,0 +1,310 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 1`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-plain"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 2`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-not-modified"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 3`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-redirect"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 4`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-image"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 5`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-js"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 6`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-css"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 7`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-document"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 8`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-plain"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render IconColumn 9`] = `
|
||||
<td
|
||||
className="col-icon"
|
||||
>
|
||||
<div
|
||||
className="resource-icon resource-icon-plain"
|
||||
/>
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render TimeColumn 1`] = `
|
||||
<td
|
||||
className="col-time"
|
||||
>
|
||||
5s
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render TimeColumn 2`] = `
|
||||
<td
|
||||
className="col-time"
|
||||
>
|
||||
5s
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render pathColumn 1`] = `
|
||||
<td
|
||||
className="col-path"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-exclamation pull-right"
|
||||
/>
|
||||
<span
|
||||
className="marker pull-right"
|
||||
>
|
||||
|
||||
</span>
|
||||
http://address:22/path
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`Flowcolumns Components should render pathColumn 2`] = `
|
||||
<td
|
||||
className="col-path"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-pause pull-right"
|
||||
/>
|
||||
<i
|
||||
className="fa fa-fw fa-times pull-right"
|
||||
/>
|
||||
<span
|
||||
className="marker pull-right"
|
||||
>
|
||||
|
||||
</span>
|
||||
http://address:22/path
|
||||
</td>
|
||||
`;
|
||||
|
||||
exports[`should render columns: icon 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-icon"
|
||||
>
|
||||
<div
|
||||
class="resource-icon resource-icon-websocket"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`should render columns: method 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-method"
|
||||
>
|
||||
GET
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`should render columns: path 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-path"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-exclamation pull-right"
|
||||
/>
|
||||
<span
|
||||
class="marker pull-right"
|
||||
/>
|
||||
http://address:22/path
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`should render columns: quickactions 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-quickactions"
|
||||
>
|
||||
<div>
|
||||
<a
|
||||
class="quickaction"
|
||||
href="#"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-repeat text-primary"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
class="quickaction"
|
||||
href="#"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-ellipsis-h text-muted"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`should render columns: size 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-size"
|
||||
>
|
||||
14b
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`should render columns: status 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-status"
|
||||
style="color: darkgreen;"
|
||||
>
|
||||
200
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`should render columns: time 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-time"
|
||||
>
|
||||
5s
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`should render columns: timestamp 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-start"
|
||||
>
|
||||
1999-12-31 23:00:00.000
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`should render columns: tls 1`] = `
|
||||
<DocumentFragment>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
class="col-tls col-tls-https"
|
||||
/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -5,7 +5,7 @@ exports[`FlowRow 1`] = `
|
||||
<table>
|
||||
<tbody>
|
||||
<tr
|
||||
class="selected highlighted has-request has-response"
|
||||
class="selected highlighted intercepted has-request has-response"
|
||||
>
|
||||
<td
|
||||
class="col-tls col-tls-https"
|
||||
@ -14,16 +14,22 @@ exports[`FlowRow 1`] = `
|
||||
class="col-icon"
|
||||
>
|
||||
<div
|
||||
class="resource-icon resource-icon-plain"
|
||||
class="resource-icon resource-icon-websocket"
|
||||
/>
|
||||
</td>
|
||||
<td
|
||||
class="col-path"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-pause pull-right"
|
||||
/>
|
||||
<i
|
||||
class="fa fa-fw fa-exclamation pull-right"
|
||||
/>
|
||||
http://address:22/second
|
||||
<span
|
||||
class="marker pull-right"
|
||||
/>
|
||||
http://address:22/path
|
||||
</td>
|
||||
<td
|
||||
class="col-method"
|
||||
@ -44,7 +50,7 @@ exports[`FlowRow 1`] = `
|
||||
<td
|
||||
class="col-time"
|
||||
>
|
||||
3s
|
||||
5s
|
||||
</td>
|
||||
<td
|
||||
class="col-quickactions"
|
||||
@ -55,7 +61,7 @@ exports[`FlowRow 1`] = `
|
||||
href="#"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-repeat text-primary"
|
||||
class="fa fa-fw fa-play text-success"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
|
@ -1,69 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import Connection, { TimeStamp, ConnectionInfo, CertificateInfo, Timing } from '../../../components/FlowView/Connection'
|
||||
import { TFlow } from '../../ducks/tutils'
|
||||
|
||||
let tflow = TFlow()
|
||||
|
||||
describe('TimeStamp Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let timestamp = renderer.create(<TimeStamp t={1483228800} deltaTo={1483228700} title="foo"/>),
|
||||
tree = timestamp.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
// without timestamp
|
||||
timestamp = renderer.create(<TimeStamp/>)
|
||||
tree = timestamp.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('ConnectionInfo Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let connectionInfo = renderer.create(<ConnectionInfo conn={tflow.client_conn}/>),
|
||||
tree = connectionInfo.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('CertificateInfo Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let certificateInfo = renderer.create(<CertificateInfo flow={tflow}/>),
|
||||
tree = certificateInfo.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Timing Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let timing = renderer.create(<Timing flow={tflow}/>),
|
||||
tree = timing.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Details Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let details = renderer.create(<Connection flow={tflow}/>),
|
||||
tree = details.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should render correctly when server address is missing', () => {
|
||||
let tflowServerAddressNull = tflow
|
||||
|
||||
tflowServerAddressNull.server_conn.address = null
|
||||
tflowServerAddressNull.server_conn.ip_address = null
|
||||
tflowServerAddressNull.server_conn.sni = null
|
||||
tflowServerAddressNull.server_conn.ssl_established = false
|
||||
tflowServerAddressNull.server_conn.tls_version = null
|
||||
tflowServerAddressNull.server_conn.timestamp_tcp_setup = null
|
||||
tflowServerAddressNull.server_conn.timestamp_ssl_setup = null
|
||||
tflowServerAddressNull.server_conn.timestamp_start = null
|
||||
tflowServerAddressNull.server_conn.timestamp_end = null
|
||||
|
||||
let details = renderer.create(<Connection flow={tflowServerAddressNull}/>),
|
||||
tree = details.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
})
|
@ -1,132 +0,0 @@
|
||||
import * as React from "react"
|
||||
import ReactDOM from 'react-dom'
|
||||
import renderer from 'react-test-renderer'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import KeyValueListEditor, { HeaderEditor } from '../../../components/editors/KeyValueListEditor'
|
||||
import { Key } from '../../../utils'
|
||||
|
||||
describe('HeaderEditor Component', () => {
|
||||
|
||||
it('should render correctly', () => {
|
||||
let headerEditor = renderer.create(
|
||||
<HeaderEditor content="foo" onDone={jest.fn()}/>),
|
||||
tree = headerEditor.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let doneFn = jest.fn(),
|
||||
removeFn = jest.fn(),
|
||||
tabFn = jest.fn(),
|
||||
headerEditor = TestUtils.renderIntoDocument(
|
||||
<HeaderEditor content="foo" onDone={doneFn} onRemove={removeFn} onTab={tabFn}/>)
|
||||
|
||||
it('should handle focus', () => {
|
||||
let focusFn = jest.fn()
|
||||
ReactDOM.findDOMNode = jest.fn( node => {
|
||||
return {focus: focusFn}
|
||||
})
|
||||
headerEditor.focus()
|
||||
expect(ReactDOM.findDOMNode).toBeCalledWith(headerEditor)
|
||||
expect(focusFn).toBeCalled()
|
||||
})
|
||||
|
||||
it('should handle keyDown', () => {
|
||||
let mockEvent = { keyCode: Key.BACKSPACE },
|
||||
getRangeAt = jest.fn( s => {
|
||||
return { startOffset: 0, endOffset: 0 }
|
||||
})
|
||||
window.getSelection = jest.fn(selection => {
|
||||
return { getRangeAt }
|
||||
})
|
||||
// Backspace
|
||||
headerEditor.onKeyDown(mockEvent)
|
||||
expect(window.getSelection).toBeCalled()
|
||||
expect(getRangeAt).toBeCalledWith(0)
|
||||
expect(headerEditor.props.onRemove).toBeCalledWith(mockEvent)
|
||||
// Enter & Tab
|
||||
mockEvent.keyCode = Key.ENTER
|
||||
headerEditor.onKeyDown(mockEvent)
|
||||
expect(headerEditor.props.onTab).toBeCalledWith(mockEvent)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Headers Component', () => {
|
||||
let changeFn = jest.fn(),
|
||||
mockMessage = { headers: [['k1', 'v1'], ['k2', '']] }
|
||||
it('should handle correctly', () => {
|
||||
let headers = renderer.create(<KeyValueListEditor onChange={changeFn} message={mockMessage}/>),
|
||||
tree = headers.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let headers = TestUtils.renderIntoDocument(<KeyValueListEditor onChange={changeFn} message={mockMessage}/>),
|
||||
headerEditors = TestUtils.scryRenderedComponentsWithType(headers, HeaderEditor),
|
||||
key1Editor = headerEditors[0],
|
||||
value1Editor = headerEditors[1],
|
||||
key2Editor = headerEditors[2],
|
||||
value2Editor = headerEditors[3]
|
||||
|
||||
it('should handle change on header name', () => {
|
||||
key2Editor.props.onDone('')
|
||||
expect(changeFn).toBeCalled()
|
||||
expect(headers._nextSel).toEqual('0-value')
|
||||
changeFn.mockClear()
|
||||
})
|
||||
|
||||
it('should handle change on header value', () => {
|
||||
value2Editor.props.onDone('')
|
||||
expect(changeFn).toBeCalled()
|
||||
expect(headers._nextSel).toEqual('0-value')
|
||||
changeFn.mockClear()
|
||||
})
|
||||
|
||||
let mockEvent = { preventDefault: jest.fn() }
|
||||
it('should handle remove on header name', () => {
|
||||
key2Editor.props.onRemove(mockEvent)
|
||||
expect(mockEvent.preventDefault).toBeCalled()
|
||||
mockEvent.preventDefault.mockClear()
|
||||
})
|
||||
|
||||
it('should handle remove on header value', () => {
|
||||
value2Editor.props.onRemove(mockEvent)
|
||||
expect(mockEvent.preventDefault).toBeCalled()
|
||||
mockEvent.preventDefault.mockClear()
|
||||
})
|
||||
|
||||
it('should handle tab on header name', () => {
|
||||
key1Editor.props.onTab(mockEvent)
|
||||
expect(headers._nextSel).toEqual('0-value')
|
||||
})
|
||||
|
||||
it('should handle tab on header value', () => {
|
||||
value1Editor.props.onTab(mockEvent)
|
||||
expect(headers._nextSel).toEqual('1-key')
|
||||
|
||||
value2Editor.props.onTab(mockEvent)
|
||||
expect(mockEvent.preventDefault).toBeCalled()
|
||||
expect(headers._nextSel).toEqual('2-key')
|
||||
})
|
||||
|
||||
it('should handle componentDidUpdate', () => {
|
||||
headers._nextSel = '1-value'
|
||||
headers.refs['1-value'] = { focus: jest.fn() }
|
||||
headers.componentDidUpdate()
|
||||
expect(headers.refs['1-value'].focus).toBeCalled()
|
||||
expect(headers._nextSel).toEqual(undefined)
|
||||
})
|
||||
|
||||
it('should handle edit', () => {
|
||||
headers.refs['0-key'] = { focus: jest.fn() }
|
||||
headers.edit()
|
||||
expect(headers.refs['0-key'].focus).toBeCalled()
|
||||
})
|
||||
|
||||
it('should not delete last row when handle remove', () => {
|
||||
mockMessage = { headers: [['', '']] }
|
||||
headers = TestUtils.renderIntoDocument(<KeyValueListEditor onChange={changeFn} message={mockMessage}/>)
|
||||
headers.onChange(0, 0, '')
|
||||
expect(changeFn).toBeCalledWith([['Name', 'Value']])
|
||||
|
||||
})
|
||||
|
||||
})
|
@ -1,146 +0,0 @@
|
||||
jest.mock('../../../components/ContentView', () => () => null)
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import {ErrorView, Request, Response} from '../../../components/FlowView/HttpMessages'
|
||||
import {Provider} from 'react-redux'
|
||||
import {TFlow, TStore} from '../../ducks/tutils'
|
||||
import {updateEdit} from '../../../ducks/ui/flow'
|
||||
import {parseUrl} from '../../../flow/utils'
|
||||
import ContentView from '../../../components/ContentView'
|
||||
import ContentViewOptions from '../../../components/ContentView/ContentViewOptions'
|
||||
import KeyValueListEditor from '../../../components/editors/KeyValueListEditor'
|
||||
import ValueEditor from '../../../components/editors/ValueEditor'
|
||||
|
||||
global.fetch = jest.fn()
|
||||
|
||||
let tflow = new TFlow(),
|
||||
store = TStore()
|
||||
store.getState().ui.flow.modifiedFlow = false
|
||||
|
||||
describe('Request Component', () => {
|
||||
|
||||
afterEach(() => {
|
||||
store.clearActions()
|
||||
})
|
||||
|
||||
it('should render correctly', () => {
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<Request/>
|
||||
</Provider>
|
||||
),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<Request/>
|
||||
</Provider>),
|
||||
valueEditors = provider.root.findAllByType(ValueEditor)
|
||||
|
||||
it('should handle done on flow request method', () => {
|
||||
let valueEditor = valueEditors[0]
|
||||
valueEditor.props.onDone('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {method: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle done on flow request url', () => {
|
||||
let valueEditor = valueEditors[1],
|
||||
url = 'http://foo/bar'
|
||||
valueEditor.props.onDone(url)
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {path: '', ...parseUrl(url)}})])
|
||||
})
|
||||
|
||||
it('should handle done on flow request http version', () => {
|
||||
let valueEditor = valueEditors[2]
|
||||
valueEditor.props.onDone('HTTP/9.9')
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {http_version: 'HTTP/9.9'}})])
|
||||
})
|
||||
|
||||
it('should handle change on flow request header', () => {
|
||||
let headers = provider.root.findAllByType(KeyValueListEditor).filter(headers => headers.props.type === 'headers')[0]
|
||||
headers.props.onChange('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {headers: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle change on flow request contentView', () => {
|
||||
let contentView = provider.root.findByType(ContentView)
|
||||
contentView.props.onContentChange('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({request: {content: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle uploadContent on flow request ContentViewOptions', () => {
|
||||
let contentViewOptions = provider.root.findByType(ContentViewOptions)
|
||||
contentViewOptions.props.uploadContent('foo')
|
||||
expect(fetch).toBeCalled()
|
||||
fetch.mockClear()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Response Component', () => {
|
||||
afterEach(() => {
|
||||
store.clearActions()
|
||||
})
|
||||
|
||||
it('should render correctly', () => {
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<Response/>
|
||||
</Provider>
|
||||
),
|
||||
tree = provider.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let provider = renderer.create(
|
||||
<Provider store={store}>
|
||||
<Response/>
|
||||
</Provider>),
|
||||
valueEditors = provider.root.findAllByType(ValueEditor)
|
||||
|
||||
it('should handle done on flow response http version', () => {
|
||||
let valueEditor = valueEditors[0]
|
||||
valueEditor.props.onDone('HTTP/9.9')
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {http_version: 'HTTP/9.9'}})])
|
||||
})
|
||||
|
||||
it('should handle done on flow response status code', () => {
|
||||
let valueEditor = valueEditors[1]
|
||||
valueEditor.props.onDone('404')
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {code: parseInt('404')}})])
|
||||
})
|
||||
|
||||
it('should handle done on flow response reason', () => {
|
||||
let valueEdiotr = valueEditors[2]
|
||||
valueEdiotr.props.onDone('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {msg: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle change on flow response headers', () => {
|
||||
let headers = provider.root.findAllByType(KeyValueListEditor).filter(headers => headers.props.type === 'headers')[0]
|
||||
headers.props.onChange('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {headers: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle change on flow response ContentView', () => {
|
||||
let contentView = provider.root.findByType(ContentView)
|
||||
contentView.props.onContentChange('foo')
|
||||
expect(store.getActions()).toEqual([updateEdit({response: {content: 'foo'}})])
|
||||
})
|
||||
|
||||
it('should handle updateContent on flow response ContentViewOptions', () => {
|
||||
let contentViewOptions = provider.root.findByType(ContentViewOptions)
|
||||
contentViewOptions.props.uploadContent('foo')
|
||||
expect(fetch).toBeCalled()
|
||||
fetch.mockClear()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Error Component', () => {
|
||||
it('should render correctly', () => {
|
||||
let errorView = renderer.create(<ErrorView flow={tflow}/>),
|
||||
tree = errorView.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
})
|
@ -1,38 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import Nav, { NavAction } from '../../../components/FlowView/Nav'
|
||||
|
||||
describe('Nav Component', () => {
|
||||
let tabs = ['foo', 'bar'],
|
||||
onSelectTab = jest.fn(),
|
||||
nav = renderer.create(<Nav active='foo' tabs={tabs} onSelectTab={onSelectTab}/>),
|
||||
tree = nav.toJSON()
|
||||
|
||||
it('should render correctly', () => {
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should handle click', () => {
|
||||
let mockEvent = { preventDefault: jest.fn() }
|
||||
tree.children[0].props.onClick(mockEvent)
|
||||
expect(mockEvent.preventDefault).toBeCalled()
|
||||
expect(onSelectTab).toBeCalledWith('foo')
|
||||
})
|
||||
})
|
||||
|
||||
describe('NavAction Component', () => {
|
||||
let clickFn = jest.fn(),
|
||||
navAction = renderer.create(<NavAction icon="foo" title="bar" onClick={clickFn}/>),
|
||||
tree = navAction.toJSON()
|
||||
|
||||
it('should render correctly', () => {
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('should handle click', () => {
|
||||
let mockEvent = { preventDefault: jest.fn() }
|
||||
tree.props.onClick(mockEvent)
|
||||
expect(mockEvent.preventDefault).toBeCalled()
|
||||
expect(clickFn).toBeCalledWith(mockEvent)
|
||||
})
|
||||
})
|
@ -1,21 +0,0 @@
|
||||
import * as React from "react"
|
||||
import ToggleEdit from '../../../components/FlowView/ToggleEdit'
|
||||
import {TFlow} from '../../ducks/tutils'
|
||||
import {render} from "../../test-utils"
|
||||
import {fireEvent, screen} from "@testing-library/react";
|
||||
|
||||
let tflow = TFlow();
|
||||
|
||||
test("ToggleEdit", async () => {
|
||||
const {asFragment, store} = render(
|
||||
<ToggleEdit/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByTitle("Edit Flow"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
expect(store.getState().ui.flow.modifiedFlow).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByTitle("Finish Edit"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
expect(store.getState().ui.flow.modifiedFlow).toBeFalsy();
|
||||
});
|
@ -1,591 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CertificateInfo Component should render correctly 1`] = `<div />`;
|
||||
|
||||
exports[`ConnectionInfo Component should render correctly 1`] = `
|
||||
<table
|
||||
className="connection-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Address:
|
||||
</td>
|
||||
<td>
|
||||
127.0.0.1:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="TLS Server Name Indication"
|
||||
>
|
||||
TLS SNI:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
address
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TLS version:
|
||||
</td>
|
||||
<td>
|
||||
TLSv1.2
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
cipher name:
|
||||
</td>
|
||||
<td>
|
||||
cipher
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="ALPN protocol negotiated"
|
||||
>
|
||||
ALPN:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
http/1.1
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
exports[`Details Component should render correctly 1`] = `
|
||||
<section
|
||||
className="detail"
|
||||
>
|
||||
<h4>
|
||||
Client Connection
|
||||
</h4>
|
||||
<table
|
||||
className="connection-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Address:
|
||||
</td>
|
||||
<td>
|
||||
127.0.0.1:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="TLS Server Name Indication"
|
||||
>
|
||||
TLS SNI:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
address
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TLS version:
|
||||
</td>
|
||||
<td>
|
||||
TLSv1.2
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
cipher name:
|
||||
</td>
|
||||
<td>
|
||||
cipher
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="ALPN protocol negotiated"
|
||||
>
|
||||
ALPN:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
http/1.1
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h4>
|
||||
Server Connection
|
||||
</h4>
|
||||
<table
|
||||
className="connection-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Address:
|
||||
</td>
|
||||
<td>
|
||||
address:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="TLS Server Name Indication"
|
||||
>
|
||||
TLS SNI:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
address
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TLS version:
|
||||
</td>
|
||||
<td>
|
||||
TLSv1.2
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Resolved address:
|
||||
</td>
|
||||
<td>
|
||||
192.168.0.1:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Source address:
|
||||
</td>
|
||||
<td>
|
||||
address:22
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div />
|
||||
<div>
|
||||
<h4>
|
||||
Timing
|
||||
</h4>
|
||||
<table
|
||||
className="timing-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Server conn. initiated
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:02.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
2s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Server conn. TCP handshake
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:03.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
3s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr />
|
||||
<tr>
|
||||
<td>
|
||||
Client conn. established
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:00.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
0ms
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr />
|
||||
<tr>
|
||||
<td>
|
||||
First request byte
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:00.000
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Request complete
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:01.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
1s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
First response byte
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:02.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
2s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Response complete
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:03.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
3s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
|
||||
exports[`Details Component should render correctly when server address is missing 1`] = `
|
||||
<section
|
||||
className="detail"
|
||||
>
|
||||
<h4>
|
||||
Client Connection
|
||||
</h4>
|
||||
<table
|
||||
className="connection-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Address:
|
||||
</td>
|
||||
<td>
|
||||
127.0.0.1:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="TLS Server Name Indication"
|
||||
>
|
||||
TLS SNI:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
address
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TLS version:
|
||||
</td>
|
||||
<td>
|
||||
TLSv1.2
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
cipher name:
|
||||
</td>
|
||||
<td>
|
||||
cipher
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="ALPN protocol negotiated"
|
||||
>
|
||||
ALPN:
|
||||
</abbr>
|
||||
</td>
|
||||
<td>
|
||||
http/1.1
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div />
|
||||
<div>
|
||||
<h4>
|
||||
Timing
|
||||
</h4>
|
||||
<table
|
||||
className="timing-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr />
|
||||
<tr />
|
||||
<tr />
|
||||
<tr>
|
||||
<td>
|
||||
Client conn. established
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:00.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
0ms
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr />
|
||||
<tr>
|
||||
<td>
|
||||
First request byte
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:00.000
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Request complete
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:01.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
1s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
First response byte
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:02.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
2s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Response complete
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:03.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
3s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
|
||||
exports[`TimeStamp Component should render correctly 1`] = `
|
||||
<tr>
|
||||
<td>
|
||||
foo
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
2017-01-01 00:00:00.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
2min
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
|
||||
exports[`TimeStamp Component should render correctly 2`] = `<tr />`;
|
||||
|
||||
exports[`Timing Component should render correctly 1`] = `
|
||||
<div>
|
||||
<h4>
|
||||
Timing
|
||||
</h4>
|
||||
<table
|
||||
className="timing-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Server conn. initiated
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:02.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
2s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Server conn. TCP handshake
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:03.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
3s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr />
|
||||
<tr>
|
||||
<td>
|
||||
Client conn. established
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:00.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
0ms
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr />
|
||||
<tr>
|
||||
<td>
|
||||
First request byte
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:00.000
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Request complete
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:01.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
1s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
First response byte
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:02.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
2s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Response complete
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:03.000
|
||||
<span
|
||||
className="text-muted"
|
||||
>
|
||||
(
|
||||
3s
|
||||
)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
@ -1,123 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`HeaderEditor Component should render correctly 1`] = `
|
||||
<div
|
||||
className="inline-input editable"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "foo",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={0}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`KeyValueListEditor Component should handle correctly 1`] = `
|
||||
<table
|
||||
className="header-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
className="header-name"
|
||||
>
|
||||
<div
|
||||
className="inline-input editable"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "k1",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
className="header-value"
|
||||
>
|
||||
<div
|
||||
className="inline-input editable"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "v1",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={0}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
className="header-name"
|
||||
>
|
||||
<div
|
||||
className="inline-input editable"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "k2",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={0}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
className="header-value"
|
||||
>
|
||||
<div
|
||||
className="inline-input editable"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={0}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
@ -1,496 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Error Component should render correctly 1`] = `
|
||||
<section
|
||||
className="error"
|
||||
>
|
||||
<div
|
||||
className="alert alert-warning"
|
||||
>
|
||||
error
|
||||
<div>
|
||||
<small>
|
||||
1999-12-31 23:00:07.000
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
`;
|
||||
|
||||
exports[`Request Component should render correctly 1`] = `
|
||||
<section
|
||||
className="request"
|
||||
>
|
||||
<article>
|
||||
<div
|
||||
className="edit-flow-container"
|
||||
>
|
||||
<a
|
||||
className="edit-flow"
|
||||
onClick={[Function]}
|
||||
title="Edit Flow"
|
||||
>
|
||||
<i
|
||||
className="fa fa-pencil"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
className="first-line request-line"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "GET",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="inline-input readonly has-success"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "http://address:22/path",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="inline-input readonly has-success"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "HTTP/1.1",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<table
|
||||
className="header-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
className="header-name"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "header",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
className="header-value"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "qvalue",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
className="header-name"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "content-length",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
className="header-value"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "7",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<hr />
|
||||
<table
|
||||
className="header-table"
|
||||
>
|
||||
<tbody />
|
||||
</table>
|
||||
</article>
|
||||
<footer>
|
||||
<div
|
||||
className="view-options"
|
||||
>
|
||||
<span>
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
edit
|
||||
</span>
|
||||
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/request/content.data"
|
||||
title="Download the content of the flow."
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-upload"
|
||||
/>
|
||||
<input
|
||||
className="hidden"
|
||||
onChange={[Function]}
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
`;
|
||||
|
||||
exports[`Response Component should render correctly 1`] = `
|
||||
<section
|
||||
className="response"
|
||||
>
|
||||
<article>
|
||||
<div
|
||||
className="edit-flow-container"
|
||||
>
|
||||
<a
|
||||
className="edit-flow"
|
||||
onClick={[Function]}
|
||||
title="Edit Flow"
|
||||
>
|
||||
<i
|
||||
className="fa fa-pencil"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
className="first-line response-line"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly has-success"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "HTTP/1.1",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="inline-input readonly has-success"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "200",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "OK",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
</div>
|
||||
<table
|
||||
className="header-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
className="header-name"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "header-response",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
className="header-value"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "svalue",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
className="header-name"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "content-length",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
className="header-value"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "7",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<hr />
|
||||
<table
|
||||
className="header-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
className="header-name"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "trailer",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
<span
|
||||
className="header-colon"
|
||||
>
|
||||
:
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
className="header-value"
|
||||
>
|
||||
<div
|
||||
className="inline-input readonly"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "qvalue",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</article>
|
||||
<footer>
|
||||
<div
|
||||
className="view-options"
|
||||
>
|
||||
<span>
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
edit
|
||||
</span>
|
||||
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content.data"
|
||||
title="Download the content of the flow."
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-upload"
|
||||
/>
|
||||
<input
|
||||
className="hidden"
|
||||
onChange={[Function]}
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
`;
|
@ -1,35 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Nav Component should render correctly 1`] = `
|
||||
<nav
|
||||
className="nav-tabs nav-tabs-sm"
|
||||
>
|
||||
<a
|
||||
className="active"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Foo
|
||||
</a>
|
||||
<a
|
||||
className=""
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Bar
|
||||
</a>
|
||||
</nav>
|
||||
`;
|
||||
|
||||
exports[`NavAction Component should render correctly 1`] = `
|
||||
<a
|
||||
className="nav-action"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
title="bar"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw foo"
|
||||
/>
|
||||
</a>
|
||||
`;
|
@ -1,35 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ToggleEdit 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="edit-flow-container"
|
||||
>
|
||||
<a
|
||||
class="edit-flow"
|
||||
title="Finish Edit"
|
||||
>
|
||||
<i
|
||||
class="fa fa-check"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`ToggleEdit 2`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="edit-flow-container"
|
||||
>
|
||||
<a
|
||||
class="edit-flow"
|
||||
title="Edit Flow"
|
||||
>
|
||||
<i
|
||||
class="fa fa-pencil"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
29
web/src/js/__tests__/components/FlowViewSpec.tsx
Normal file
29
web/src/js/__tests__/components/FlowViewSpec.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import * as React from "react"
|
||||
import {render, screen, waitFor} from "../test-utils";
|
||||
import FlowView from "../../components/FlowView";
|
||||
import fetchMock, {enableFetchMocks} from "jest-fetch-mock";
|
||||
import {fireEvent} from "@testing-library/react";
|
||||
|
||||
enableFetchMocks();
|
||||
|
||||
test("FlowView", async () => {
|
||||
fetchMock.mockReject(new Error("backend missing"));
|
||||
|
||||
const {asFragment} = render(<FlowView/>);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(screen.getByText("Response"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(screen.getByText("WebSocket"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(screen.getByText("Connection"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(screen.getByText("Timing"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(screen.getByText("Error"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
@ -1,35 +0,0 @@
|
||||
jest.mock('../../../flow/utils')
|
||||
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import FlowMenu from '../../../components/Header/FlowMenu'
|
||||
import { TFlow, TStore }from '../../ducks/tutils'
|
||||
import { MessageUtils } from "../../../flow/utils"
|
||||
import { Provider } from 'react-redux'
|
||||
|
||||
describe('FlowMenu Component', () => {
|
||||
let tflow = new TFlow(),
|
||||
store = new TStore()
|
||||
tflow.modified = true
|
||||
tflow.intercepted = true
|
||||
global.fetch = jest.fn()
|
||||
|
||||
let flowMenu = renderer.create(
|
||||
<Provider store={store}>
|
||||
<FlowMenu />
|
||||
</Provider>
|
||||
),
|
||||
tree = flowMenu.toJSON()
|
||||
|
||||
it('should render correctly with flow', () => {
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let menu_content_2 = tree.children[1].children[0]
|
||||
it('should handle download', () => {
|
||||
let button = menu_content_2.children[0]
|
||||
button.props.onClick()
|
||||
expect(MessageUtils.getContentURL).toBeCalledWith(tflow, tflow.response)
|
||||
})
|
||||
|
||||
})
|
8
web/src/js/__tests__/components/Header/FlowMenuSpec.tsx
Normal file
8
web/src/js/__tests__/components/Header/FlowMenuSpec.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
import * as React from "react"
|
||||
import FlowMenu from '../../../components/Header/FlowMenu'
|
||||
import {render} from "../../test-utils"
|
||||
|
||||
test("FlowMenu", async () => {
|
||||
const {asFragment} = render(<FlowMenu/>);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
@ -6,6 +6,6 @@ exports[`FileMenu Component should render correctly 1`] = `
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
>
|
||||
mitmproxy
|
||||
File
|
||||
</a>
|
||||
`;
|
||||
|
@ -1,120 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FlowMenu Component should render correctly with flow 1`] = `
|
||||
<div
|
||||
className="flow-menu"
|
||||
>
|
||||
<div
|
||||
className="menu-group"
|
||||
>
|
||||
<div
|
||||
className="menu-content"
|
||||
>
|
||||
<button
|
||||
className="btn btn-default"
|
||||
onClick={[Function]}
|
||||
title="[r]eplay flow"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-repeat text-primary"
|
||||
/>
|
||||
Replay
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-default"
|
||||
onClick={[Function]}
|
||||
title="[D]uplicate flow"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-copy text-info"
|
||||
/>
|
||||
Duplicate
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-default"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
title="revert changes to flow [V]"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-history text-warning"
|
||||
/>
|
||||
Revert
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-default"
|
||||
onClick={[Function]}
|
||||
title="[d]elete flow"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-trash text-danger"
|
||||
/>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="menu-legend"
|
||||
>
|
||||
Flow Modification
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="menu-group"
|
||||
>
|
||||
<div
|
||||
className="menu-content"
|
||||
>
|
||||
<button
|
||||
className="btn btn-default"
|
||||
onClick={[Function]}
|
||||
title="download"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-download"
|
||||
/>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="menu-legend"
|
||||
>
|
||||
Export
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="menu-group"
|
||||
>
|
||||
<div
|
||||
className="menu-content"
|
||||
>
|
||||
<button
|
||||
className="btn btn-default"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
title="[a]ccept intercepted flow"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-play text-success"
|
||||
/>
|
||||
Resume
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-default"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
title="kill intercepted flow [x]"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-times text-danger"
|
||||
/>
|
||||
Abort
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="menu-legend"
|
||||
>
|
||||
Interception
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -0,0 +1,134 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FlowMenu 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="flow-menu"
|
||||
>
|
||||
<div
|
||||
class="menu-group"
|
||||
>
|
||||
<div
|
||||
class="menu-content"
|
||||
>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
disabled=""
|
||||
title="[r]eplay flow"
|
||||
>
|
||||
<i
|
||||
class="fa fa-repeat text-primary"
|
||||
/>
|
||||
Replay
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
title="[D]uplicate flow"
|
||||
>
|
||||
<i
|
||||
class="fa fa-copy text-info"
|
||||
/>
|
||||
Duplicate
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
disabled=""
|
||||
title="revert changes to flow [V]"
|
||||
>
|
||||
<i
|
||||
class="fa fa-history text-warning"
|
||||
/>
|
||||
Revert
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
title="[d]elete flow"
|
||||
>
|
||||
<i
|
||||
class="fa fa-trash text-danger"
|
||||
/>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="menu-legend"
|
||||
>
|
||||
Flow Modification
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="menu-group"
|
||||
>
|
||||
<div
|
||||
class="menu-content"
|
||||
>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
>
|
||||
<i
|
||||
class="fa fa-download"
|
||||
/>
|
||||
Download▾
|
||||
</button>
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
title="Export flow."
|
||||
>
|
||||
<i
|
||||
class="fa fa-clone"
|
||||
/>
|
||||
Export▾
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
class="menu-legend"
|
||||
>
|
||||
Export
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="menu-group"
|
||||
>
|
||||
<div
|
||||
class="menu-content"
|
||||
>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
disabled=""
|
||||
title="[a]ccept intercepted flow"
|
||||
>
|
||||
<i
|
||||
class="fa fa-play text-success"
|
||||
/>
|
||||
Resume
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
disabled=""
|
||||
title="kill intercepted flow [x]"
|
||||
>
|
||||
<i
|
||||
class="fa fa-times text-danger"
|
||||
/>
|
||||
Abort
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="menu-legend"
|
||||
>
|
||||
Interception
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -26,7 +26,7 @@ exports[`MainMenu 1`] = `
|
||||
class="form-control"
|
||||
placeholder="Search"
|
||||
type="text"
|
||||
value="~d address"
|
||||
value="~u /second"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
@ -97,101 +97,3 @@ exports[`MainMenu 1`] = `
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`StartMenu 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="main-menu"
|
||||
>
|
||||
<div
|
||||
class="menu-group"
|
||||
>
|
||||
<div
|
||||
class="menu-content"
|
||||
>
|
||||
<div
|
||||
class="filter-input input-group"
|
||||
>
|
||||
<span
|
||||
class="input-group-addon"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-search"
|
||||
style="color: black;"
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
class="form-control"
|
||||
placeholder="Search"
|
||||
type="text"
|
||||
value="~d address"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="filter-input input-group"
|
||||
>
|
||||
<span
|
||||
class="input-group-addon"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-tag"
|
||||
style="color: rgb(0, 0, 0);"
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
class="form-control"
|
||||
placeholder="Highlight"
|
||||
type="text"
|
||||
value="~u /path"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="menu-legend"
|
||||
>
|
||||
Find
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="menu-group"
|
||||
>
|
||||
<div
|
||||
class="menu-content"
|
||||
>
|
||||
<div
|
||||
class="filter-input input-group"
|
||||
>
|
||||
<span
|
||||
class="input-group-addon"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-pause"
|
||||
style="color: rgb(68, 68, 68);"
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
class="form-control"
|
||||
placeholder="Intercept"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
class="btn-sm btn btn-default"
|
||||
title="[a]ccept all"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-forward text-success"
|
||||
/>
|
||||
Resume All
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="menu-legend"
|
||||
>
|
||||
Intercept
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
@ -14,8 +14,9 @@ exports[`OptionMenu Component should render correctly 1`] = `
|
||||
title="Open Options"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-cogs text-primary"
|
||||
className="fa fa-cogs text-primary"
|
||||
/>
|
||||
|
||||
Edit Options
|
||||
<sup>
|
||||
alpha
|
||||
@ -103,6 +104,18 @@ exports[`OptionMenu Component should render correctly 1`] = `
|
||||
Display Event Log
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
className="menu-entry"
|
||||
>
|
||||
<label>
|
||||
<input
|
||||
checked={true}
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
/>
|
||||
Display Command Bar
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="menu-legend"
|
||||
|
@ -1,47 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import ValidateEditor from '../../../components/editors/ValidateEditor'
|
||||
|
||||
describe('ValidateEditor Component', () => {
|
||||
let validateFn = jest.fn( content => content.length == 3),
|
||||
doneFn = jest.fn()
|
||||
|
||||
it('should render correctly', () => {
|
||||
let validateEditor = renderer.create(
|
||||
<ValidateEditor content="foo" onEditDone={doneFn} isValid={validateFn}/>
|
||||
),
|
||||
tree = validateEditor.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let validateEditor = TestUtils.renderIntoDocument(
|
||||
<ValidateEditor content="foo" onEditDone={doneFn} isValid={validateFn}/>
|
||||
)
|
||||
it('should handle componentWillReceiveProps', () => {
|
||||
let mockProps = {
|
||||
isValid: s => s.length == 3,
|
||||
content: "bar"
|
||||
}
|
||||
validateEditor.UNSAFE_componentWillReceiveProps(mockProps)
|
||||
expect(validateEditor.state.valid).toBeTruthy()
|
||||
validateEditor.UNSAFE_componentWillReceiveProps({...mockProps, content: "bars"})
|
||||
expect(validateEditor.state.valid).toBeFalsy()
|
||||
|
||||
})
|
||||
|
||||
it('should handle input', () => {
|
||||
validateEditor.onInput("foo bar")
|
||||
expect(validateFn).toBeCalledWith("foo bar")
|
||||
})
|
||||
|
||||
it('should handle done', () => {
|
||||
// invalid
|
||||
validateEditor.editor.reset = jest.fn()
|
||||
validateEditor.onDone("foo bar")
|
||||
expect(validateEditor.editor.reset).toBeCalled()
|
||||
// valid
|
||||
validateEditor.onDone("bar")
|
||||
expect(doneFn).toBeCalledWith("bar")
|
||||
})
|
||||
})
|
@ -1,155 +0,0 @@
|
||||
import * as React from "react"
|
||||
import renderer from 'react-test-renderer'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import ValueEditor from '../../../components/editors/ValueEditor'
|
||||
import { Key } from '../../../utils'
|
||||
|
||||
describe('ValueEditor Component', () => {
|
||||
|
||||
let mockFn = jest.fn()
|
||||
it ('should render correctly', () => {
|
||||
let valueEditor = renderer.create(
|
||||
<ValueEditor content="foo" onEditDone={mockFn}/>
|
||||
),
|
||||
tree = valueEditor.toJSON()
|
||||
expect(tree).toMatchSnapshot()
|
||||
})
|
||||
|
||||
let valueEditor = TestUtils.renderIntoDocument(
|
||||
<ValueEditor content="<script>foo</script>" onEditDone={mockFn}/>
|
||||
)
|
||||
it('should handle this.blur', () => {
|
||||
valueEditor.input.blur = jest.fn()
|
||||
valueEditor.blur()
|
||||
expect(valueEditor.input.blur).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should handle reset', () => {
|
||||
valueEditor.reset()
|
||||
expect(valueEditor.input.innerHTML).toEqual(
|
||||
"<script>foo</script>"
|
||||
)
|
||||
})
|
||||
|
||||
it('should handle paste', () => {
|
||||
let mockEvent = {
|
||||
preventDefault: jest.fn(),
|
||||
clipboardData: { getData: (t) => "foo content"}
|
||||
}
|
||||
document.execCommand = jest.fn()
|
||||
valueEditor.onPaste(mockEvent)
|
||||
expect(document.execCommand).toBeCalledWith('insertHTML', false, "foo content")
|
||||
})
|
||||
|
||||
it('should handle mouseDown', () => {
|
||||
window.addEventListener = jest.fn()
|
||||
valueEditor.onMouseDown({})
|
||||
expect(valueEditor._mouseDown).toBeTruthy()
|
||||
expect(window.addEventListener).toBeCalledWith('mouseup', valueEditor.onMouseUp)
|
||||
})
|
||||
|
||||
it('should handle mouseUp', () => {
|
||||
window.removeEventListener = jest.fn()
|
||||
valueEditor.onMouseUp()
|
||||
expect(window.removeEventListener).toBeCalledWith('mouseup', valueEditor.onMouseUp)
|
||||
})
|
||||
|
||||
it('should handle focus', () => {
|
||||
let mockEvent = { clientX: 1, clientY: 2 },
|
||||
mockSelection = {
|
||||
rangeCount: 1,
|
||||
getRangeAt: jest.fn( (index) => {return { selectNodeContents: jest.fn() }}),
|
||||
removeAllRanges: jest.fn(),
|
||||
addRange: jest.fn()
|
||||
},
|
||||
clearState = (v) => {
|
||||
v._mouseDown = false
|
||||
v._ignore_events = false
|
||||
v.state.editable = false
|
||||
}
|
||||
window.getSelection = () => mockSelection
|
||||
|
||||
// return undefined when mouse down
|
||||
valueEditor.onMouseDown()
|
||||
expect(valueEditor.onFocus(mockEvent)).toEqual(undefined)
|
||||
valueEditor.onMouseUp()
|
||||
|
||||
// sel.rangeCount > 0
|
||||
valueEditor.onFocus(mockEvent)
|
||||
expect(mockSelection.getRangeAt).toBeCalledWith(0)
|
||||
expect(valueEditor.state.editable).toBeTruthy()
|
||||
expect(mockSelection.removeAllRanges).toBeCalled()
|
||||
expect(mockSelection.addRange).toBeCalled()
|
||||
clearState(valueEditor)
|
||||
|
||||
// document.caretPositionFromPoint
|
||||
mockSelection.rangeCount = 0
|
||||
let mockRange = { setStart: jest.fn(), selectNodeContents: jest.fn() }
|
||||
|
||||
document.caretPositionFromPoint = jest.fn((x, y) => {
|
||||
return { offsetNode: 0, offset: x + y}
|
||||
})
|
||||
document.createRange = jest.fn(() => mockRange)
|
||||
valueEditor.onFocus(mockEvent)
|
||||
expect(mockRange.setStart).toBeCalledWith(0, 3)
|
||||
clearState(valueEditor)
|
||||
document.caretPositionFromPoint = null
|
||||
|
||||
//document.caretRangeFromPoint
|
||||
document.caretRangeFromPoint = jest.fn(() => mockRange)
|
||||
valueEditor.onFocus(mockEvent)
|
||||
expect(document.caretRangeFromPoint).toBeCalledWith(1, 2)
|
||||
clearState(valueEditor)
|
||||
document.caretRangeFromPoint = null
|
||||
|
||||
//else
|
||||
valueEditor.onFocus(mockEvent)
|
||||
expect(mockRange.selectNodeContents).toBeCalledWith(valueEditor.input)
|
||||
clearState(valueEditor)
|
||||
})
|
||||
|
||||
it('should handle click', () => {
|
||||
valueEditor.onMouseUp = jest.fn()
|
||||
valueEditor.onFocus = jest.fn()
|
||||
valueEditor.onClick('foo')
|
||||
expect(valueEditor.onMouseUp).toBeCalled()
|
||||
expect(valueEditor.onFocus).toBeCalledWith('foo')
|
||||
})
|
||||
|
||||
it('should handle blur', () => {
|
||||
// return undefined
|
||||
valueEditor._ignore_events = true
|
||||
expect(valueEditor.onBlur({})).toEqual(undefined)
|
||||
// else
|
||||
valueEditor._ignore_events = false
|
||||
valueEditor.onBlur({})
|
||||
expect(valueEditor.state.editable).toBeFalsy()
|
||||
expect(valueEditor.props.onDone).toBeCalledWith(valueEditor.input.textContent)
|
||||
})
|
||||
|
||||
it('should handle key down', () => {
|
||||
let mockKeyEvent = (keyCode, shiftKey=false) => {
|
||||
return {
|
||||
keyCode: keyCode,
|
||||
shiftKey: shiftKey,
|
||||
stopPropagation: jest.fn(),
|
||||
preventDefault: jest.fn()
|
||||
}
|
||||
}
|
||||
valueEditor.reset = jest.fn()
|
||||
valueEditor.blur = jest.fn()
|
||||
valueEditor.onKeyDown(mockKeyEvent(Key.ESC))
|
||||
expect(valueEditor.reset).toBeCalled()
|
||||
expect(valueEditor.blur).toBeCalled()
|
||||
valueEditor.blur.mockReset()
|
||||
|
||||
valueEditor.onKeyDown(mockKeyEvent(Key.ENTER))
|
||||
expect(valueEditor.blur).toBeCalled()
|
||||
|
||||
valueEditor.onKeyDown(mockKeyEvent(Key.SPACE))
|
||||
})
|
||||
|
||||
it('should handle input', () => {
|
||||
valueEditor.onInput()
|
||||
})
|
||||
})
|
@ -1,20 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ValidateEditor Component should render correctly 1`] = `
|
||||
<div
|
||||
className="inline-input editable has-success"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "foo",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={0}
|
||||
/>
|
||||
`;
|
@ -1,20 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ValueEditor Component should render correctly 1`] = `
|
||||
<div
|
||||
className="inline-input editable"
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "foo",
|
||||
}
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onFocus={[Function]}
|
||||
onInput={[Function]}
|
||||
onKeyDown={[Function]}
|
||||
onMouseDown={[Function]}
|
||||
onPaste={[Function]}
|
||||
tabIndex={0}
|
||||
/>
|
||||
`;
|
@ -0,0 +1,111 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CommandBar 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="command"
|
||||
>
|
||||
<div
|
||||
class="command-title"
|
||||
>
|
||||
Command Result
|
||||
</div>
|
||||
<div
|
||||
class="command-result"
|
||||
/>
|
||||
<div
|
||||
class="argument-suggestion popover top"
|
||||
>
|
||||
<div
|
||||
class="arrow"
|
||||
/>
|
||||
<div
|
||||
class="popover-content"
|
||||
>
|
||||
<div>
|
||||
<strong>
|
||||
Available Commands:
|
||||
</strong>
|
||||
<p
|
||||
class="available-commands"
|
||||
>
|
||||
[]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="command-input input-group"
|
||||
>
|
||||
<span
|
||||
class="input-group-addon"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-terminal"
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
class="form-control"
|
||||
placeholder="Enter command"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`CommandBar 2`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="command"
|
||||
>
|
||||
<div
|
||||
class="command-title"
|
||||
>
|
||||
Command Result
|
||||
</div>
|
||||
<div
|
||||
class="command-result"
|
||||
/>
|
||||
<div
|
||||
class="argument-suggestion popover top"
|
||||
>
|
||||
<div
|
||||
class="arrow"
|
||||
/>
|
||||
<div
|
||||
class="popover-content"
|
||||
>
|
||||
<div>
|
||||
<strong>
|
||||
Available Commands:
|
||||
</strong>
|
||||
<p
|
||||
class="available-commands"
|
||||
>
|
||||
["flow.decode"]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="command-input input-group"
|
||||
>
|
||||
<span
|
||||
class="input-group-addon"
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-terminal"
|
||||
/>
|
||||
</span>
|
||||
<input
|
||||
class="form-control"
|
||||
placeholder="Enter command"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -1,80 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ContentView Component should render correctly 1`] = `
|
||||
<div
|
||||
className="contentview"
|
||||
>
|
||||
<div
|
||||
className="text-center"
|
||||
>
|
||||
<i
|
||||
className="fa fa-spinner fa-spin"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ContentView Component should render correctly with content too large 1`] = `
|
||||
<div>
|
||||
<div
|
||||
className="alert alert-warning"
|
||||
>
|
||||
<button
|
||||
className="btn btn-xs btn-warning pull-right"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Display anyway
|
||||
</button>
|
||||
100mb
|
||||
content size.
|
||||
</div>
|
||||
<div
|
||||
className="view-options text-center"
|
||||
>
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="#"
|
||||
onClick={[Function]}
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw fa-upload"
|
||||
/>
|
||||
<input
|
||||
className="hidden"
|
||||
onChange={[Function]}
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
className="btn btn-default btn-xs"
|
||||
href="./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/response/content.data"
|
||||
title="Download the content of the flow."
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ContentView Component should render correctly with empty content 1`] = `
|
||||
<div
|
||||
className="alert alert-info"
|
||||
>
|
||||
No
|
||||
response
|
||||
content.
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ContentView Component should render correctly with missing content 1`] = `
|
||||
<div
|
||||
className="alert alert-info"
|
||||
>
|
||||
Response
|
||||
content missing.
|
||||
</div>
|
||||
`;
|
@ -0,0 +1,854 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FlowView 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="flow-detail"
|
||||
>
|
||||
<nav
|
||||
class="nav-tabs nav-tabs-sm"
|
||||
>
|
||||
<a
|
||||
class="active"
|
||||
href="#"
|
||||
>
|
||||
Request
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Response
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
WebSocket
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Error
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Connection
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Timing
|
||||
</a>
|
||||
</nav>
|
||||
<section
|
||||
class="request"
|
||||
>
|
||||
<div
|
||||
class="first-line request-line"
|
||||
>
|
||||
<div>
|
||||
<span
|
||||
class="inline-input has-success"
|
||||
tabindex="0"
|
||||
>
|
||||
GET
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="inline-input has-success"
|
||||
tabindex="0"
|
||||
>
|
||||
http://address:22/second
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="inline-input has-success"
|
||||
tabindex="0"
|
||||
>
|
||||
HTTP/1.1
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="kv-editor headers"
|
||||
>
|
||||
<div
|
||||
class="kv-row"
|
||||
>
|
||||
<span
|
||||
class="inline-input kv-key"
|
||||
tabindex="0"
|
||||
>
|
||||
header
|
||||
</span>
|
||||
:
|
||||
<span
|
||||
class="inline-input kv-value"
|
||||
placeholder="empty"
|
||||
tabindex="0"
|
||||
>
|
||||
qvalue
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="kv-row"
|
||||
>
|
||||
<span
|
||||
class="inline-input kv-key"
|
||||
tabindex="0"
|
||||
>
|
||||
content-length
|
||||
</span>
|
||||
:
|
||||
<span
|
||||
class="inline-input kv-value"
|
||||
placeholder="empty"
|
||||
tabindex="0"
|
||||
>
|
||||
7
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Add"
|
||||
class="kv-add-row fa fa-plus-square-o"
|
||||
role="button"
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div
|
||||
class="contentview"
|
||||
>
|
||||
<div
|
||||
class="controls"
|
||||
>
|
||||
<h5>
|
||||
Loading...
|
||||
</h5>
|
||||
<button
|
||||
class="btn-xs btn btn-default"
|
||||
>
|
||||
<i
|
||||
class="fa fa-edit"
|
||||
/>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-upload"
|
||||
/>
|
||||
Replace
|
||||
<input
|
||||
class="hidden"
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="fa fa-fw fa-files-o"
|
||||
/>
|
||||
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
auto
|
||||
<span
|
||||
class="caret"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`FlowView 2`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="flow-detail"
|
||||
>
|
||||
<nav
|
||||
class="nav-tabs nav-tabs-sm"
|
||||
>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Request
|
||||
</a>
|
||||
<a
|
||||
class="active"
|
||||
href="#"
|
||||
>
|
||||
Response
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
WebSocket
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Error
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Connection
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Timing
|
||||
</a>
|
||||
</nav>
|
||||
<section
|
||||
class="response"
|
||||
>
|
||||
<div
|
||||
class="first-line response-line"
|
||||
>
|
||||
<span
|
||||
class="inline-input has-success"
|
||||
tabindex="0"
|
||||
>
|
||||
HTTP/1.1
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="inline-input has-success"
|
||||
tabindex="0"
|
||||
>
|
||||
200
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="inline-input"
|
||||
tabindex="0"
|
||||
>
|
||||
OK
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="kv-editor headers"
|
||||
>
|
||||
<div
|
||||
class="kv-row"
|
||||
>
|
||||
<span
|
||||
class="inline-input kv-key"
|
||||
tabindex="0"
|
||||
>
|
||||
header-response
|
||||
</span>
|
||||
:
|
||||
<span
|
||||
class="inline-input kv-value"
|
||||
placeholder="empty"
|
||||
tabindex="0"
|
||||
>
|
||||
svalue
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="kv-row"
|
||||
>
|
||||
<span
|
||||
class="inline-input kv-key"
|
||||
tabindex="0"
|
||||
>
|
||||
content-length
|
||||
</span>
|
||||
:
|
||||
<span
|
||||
class="inline-input kv-value"
|
||||
placeholder="empty"
|
||||
tabindex="0"
|
||||
>
|
||||
7
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
aria-label="Add"
|
||||
class="kv-add-row fa fa-plus-square-o"
|
||||
role="button"
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div
|
||||
class="contentview"
|
||||
>
|
||||
<div
|
||||
class="controls"
|
||||
>
|
||||
<h5>
|
||||
Loading...
|
||||
</h5>
|
||||
<button
|
||||
class="btn-xs btn btn-default"
|
||||
>
|
||||
<i
|
||||
class="fa fa-edit"
|
||||
/>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-upload"
|
||||
/>
|
||||
Replace
|
||||
<input
|
||||
class="hidden"
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="fa fa-fw fa-files-o"
|
||||
/>
|
||||
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
auto
|
||||
<span
|
||||
class="caret"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`FlowView 3`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="flow-detail"
|
||||
>
|
||||
<nav
|
||||
class="nav-tabs nav-tabs-sm"
|
||||
>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Request
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Response
|
||||
</a>
|
||||
<a
|
||||
class="active"
|
||||
href="#"
|
||||
>
|
||||
WebSocket
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Error
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Connection
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Timing
|
||||
</a>
|
||||
</nav>
|
||||
<section
|
||||
class="websocket"
|
||||
>
|
||||
<h4>
|
||||
WebSocket
|
||||
</h4>
|
||||
<div
|
||||
class="contentview"
|
||||
>
|
||||
<div
|
||||
class="controls"
|
||||
>
|
||||
<h5>
|
||||
3 Messages
|
||||
</h5>
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="fa fa-fw fa-files-o"
|
||||
/>
|
||||
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
auto
|
||||
<span
|
||||
class="caret"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<i
|
||||
class="fa fa-fw fa-window-close text-muted"
|
||||
/>
|
||||
Closed by server with code 1000 (Close Reason).
|
||||
<small
|
||||
class="pull-right"
|
||||
>
|
||||
1999-12-31 23:00:05.000
|
||||
</small>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`FlowView 4`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="flow-detail"
|
||||
>
|
||||
<nav
|
||||
class="nav-tabs nav-tabs-sm"
|
||||
>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Request
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Response
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
WebSocket
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Error
|
||||
</a>
|
||||
<a
|
||||
class="active"
|
||||
href="#"
|
||||
>
|
||||
Connection
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Timing
|
||||
</a>
|
||||
</nav>
|
||||
<section
|
||||
class="detail"
|
||||
>
|
||||
<h4>
|
||||
Client Connection
|
||||
</h4>
|
||||
<table
|
||||
class="connection-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Address:
|
||||
</td>
|
||||
<td>
|
||||
127.0.0.1:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="TLS Server Name Indication"
|
||||
>
|
||||
SNI
|
||||
</abbr>
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
address
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="ALPN protocol negotiated"
|
||||
>
|
||||
ALPN
|
||||
</abbr>
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
http/1.1
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TLS Version:
|
||||
</td>
|
||||
<td>
|
||||
TLSv1.2
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TLS Cipher:
|
||||
</td>
|
||||
<td>
|
||||
cipher
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h4>
|
||||
Server Connection
|
||||
</h4>
|
||||
<table
|
||||
class="connection-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Address:
|
||||
</td>
|
||||
<td>
|
||||
address:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Resolved address:
|
||||
</td>
|
||||
<td>
|
||||
192.168.0.1:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Source address:
|
||||
</td>
|
||||
<td>
|
||||
address:22
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<abbr
|
||||
title="TLS Server Name Indication"
|
||||
>
|
||||
SNI
|
||||
</abbr>
|
||||
:
|
||||
</td>
|
||||
<td>
|
||||
address
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TLS Version:
|
||||
</td>
|
||||
<td>
|
||||
TLSv1.2
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`FlowView 5`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="flow-detail"
|
||||
>
|
||||
<nav
|
||||
class="nav-tabs nav-tabs-sm"
|
||||
>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Request
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Response
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
WebSocket
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Error
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Connection
|
||||
</a>
|
||||
<a
|
||||
class="active"
|
||||
href="#"
|
||||
>
|
||||
Timing
|
||||
</a>
|
||||
</nav>
|
||||
<section
|
||||
class="timing"
|
||||
>
|
||||
<h4>
|
||||
Timing
|
||||
</h4>
|
||||
<table
|
||||
class="timing-table"
|
||||
>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Client conn. established:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:00.000
|
||||
<span
|
||||
class="text-muted"
|
||||
>
|
||||
(0ms)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
First request byte:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:00.000
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Client conn. TLS handshake:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:01.000
|
||||
<span
|
||||
class="text-muted"
|
||||
>
|
||||
(1s)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Request complete:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:01.000
|
||||
<span
|
||||
class="text-muted"
|
||||
>
|
||||
(1s)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Server conn. initiated:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:02.000
|
||||
<span
|
||||
class="text-muted"
|
||||
>
|
||||
(2s)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
First response byte:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:02.000
|
||||
<span
|
||||
class="text-muted"
|
||||
>
|
||||
(2s)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Server conn. TCP handshake:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:03.000
|
||||
<span
|
||||
class="text-muted"
|
||||
>
|
||||
(3s)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Response complete:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:03.000
|
||||
<span
|
||||
class="text-muted"
|
||||
>
|
||||
(3s)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Server conn. TLS handshake:
|
||||
</td>
|
||||
<td>
|
||||
1999-12-31 23:00:04.000
|
||||
<span
|
||||
class="text-muted"
|
||||
>
|
||||
(4s)
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`FlowView 6`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="flow-detail"
|
||||
>
|
||||
<nav
|
||||
class="nav-tabs nav-tabs-sm"
|
||||
>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Request
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Response
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
WebSocket
|
||||
</a>
|
||||
<a
|
||||
class="active"
|
||||
href="#"
|
||||
>
|
||||
Error
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Connection
|
||||
</a>
|
||||
<a
|
||||
class=""
|
||||
href="#"
|
||||
>
|
||||
Timing
|
||||
</a>
|
||||
</nav>
|
||||
<section
|
||||
class="error"
|
||||
>
|
||||
<div
|
||||
class="alert alert-warning"
|
||||
>
|
||||
error
|
||||
<div>
|
||||
<small>
|
||||
1999-12-31 23:00:07.000
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -1,6 +1,6 @@
|
||||
import * as React from "react";
|
||||
import Dropdown, {Divider, MenuItem, SubMenu} from '../../../components/common/Dropdown'
|
||||
import {fireEvent, render, screen, waitFor} from '@testing-library/react'
|
||||
import {fireEvent, render, screen, waitFor} from "../../test-utils";
|
||||
|
||||
|
||||
test('Dropdown', async () => {
|
||||
@ -18,11 +18,9 @@ test('Dropdown', async () => {
|
||||
await waitFor(() => expect(onOpen).toBeCalledWith(true))
|
||||
expect(asFragment()).toMatchSnapshot()
|
||||
|
||||
/*
|
||||
onOpen.mockClear()
|
||||
fireEvent.click(document.body)
|
||||
await waitFor(() => expect(onOpen).toBeCalledWith(false))
|
||||
*/
|
||||
await waitFor(() => expect(onOpen).toBeCalledWith(false));
|
||||
})
|
||||
|
||||
test('SubMenu', async () => {
|
||||
@ -45,9 +43,9 @@ test('SubMenu', async () => {
|
||||
test('MenuItem', async () => {
|
||||
let click = jest.fn();
|
||||
const {asFragment} = render(
|
||||
<MenuItem onClick={click}>click me</MenuItem>
|
||||
<MenuItem onClick={click}>wtf</MenuItem>
|
||||
)
|
||||
expect(asFragment()).toMatchSnapshot()
|
||||
fireEvent.click(screen.getByText("click me"))
|
||||
expect(click).toBeCalled()
|
||||
fireEvent.click(screen.getByText("wtf"))
|
||||
await waitFor(() => expect(click).toBeCalled());
|
||||
})
|
||||
|
@ -18,8 +18,9 @@ exports[`Button Component should render correctly 1`] = `
|
||||
title="title"
|
||||
>
|
||||
<i
|
||||
className="fa fa-fw icon"
|
||||
className="fa icon"
|
||||
/>
|
||||
|
||||
<a>
|
||||
foo
|
||||
</a>
|
||||
|
@ -54,7 +54,7 @@ exports[`MenuItem 1`] = `
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
click me
|
||||
wtf
|
||||
</a>
|
||||
</li>
|
||||
</DocumentFragment>
|
||||
|
@ -0,0 +1,10 @@
|
||||
jest.mock("../../../contrib/CodeMirror")
|
||||
import * as React from 'react';
|
||||
import CodeEditor from '../../../components/contentviews/CodeEditor'
|
||||
import {render} from "../../test-utils"
|
||||
|
||||
|
||||
test("CodeEditor", async () => {
|
||||
const {asFragment} = render(<CodeEditor initialContent="foo"/>);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
@ -0,0 +1,60 @@
|
||||
import {TFlow} from "../../ducks/tutils";
|
||||
import * as React from 'react';
|
||||
import HttpMessage, {ViewImage} from '../../../components/contentviews/HttpMessage'
|
||||
import {fireEvent, render, screen, waitFor} from "../../test-utils"
|
||||
import fetchMock, {enableFetchMocks} from "jest-fetch-mock";
|
||||
import {SHOW_MAX_LINES} from "../../../components/contentviews/useContent";
|
||||
|
||||
jest.mock("../../../contrib/CodeMirror")
|
||||
|
||||
enableFetchMocks();
|
||||
|
||||
test("HttpMessage", async () => {
|
||||
const lines = Array(SHOW_MAX_LINES).fill([["text", "data"]]).concat(
|
||||
Array(SHOW_MAX_LINES).fill([["text", "additional"]])
|
||||
);
|
||||
|
||||
fetchMock.mockResponses(
|
||||
JSON.stringify({
|
||||
lines: lines.slice(0, SHOW_MAX_LINES + 1),
|
||||
description: "Auto"
|
||||
}), JSON.stringify({
|
||||
lines,
|
||||
description: "Auto"
|
||||
}), JSON.stringify({
|
||||
lines: Array(5).fill([["text", "rawdata"]]),
|
||||
description: "Raw",
|
||||
}),
|
||||
"raw content",
|
||||
JSON.stringify({
|
||||
lines: Array(5).fill([["text", "rawdata"]]),
|
||||
description: "Raw",
|
||||
})
|
||||
);
|
||||
|
||||
const tflow = TFlow();
|
||||
const {asFragment} = render(<HttpMessage flow={tflow} message={tflow.request}/>);
|
||||
await waitFor(() => screen.getAllByText("data"));
|
||||
expect(screen.queryByText('additional')).toBeNull();
|
||||
|
||||
fireEvent.click(screen.getByText("Show more"));
|
||||
await waitFor(() => screen.getAllByText("additional"));
|
||||
|
||||
fireEvent.click(screen.getByText("auto"));
|
||||
fireEvent.click(screen.getByText("raw"));
|
||||
await waitFor(() => screen.getAllByText("rawdata"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
fireEvent.click(screen.getByText("Edit"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
fireEvent.click(screen.getByText("Cancel"));
|
||||
|
||||
await waitFor(() => screen.getAllByText("rawdata"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("ViewImage", async () => {
|
||||
const flow = TFlow();
|
||||
const {asFragment} = render(<ViewImage flow={flow} message={flow.request}/>)
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
@ -0,0 +1,28 @@
|
||||
import * as React from 'react';
|
||||
import LineRenderer from '../../../components/contentviews/LineRenderer'
|
||||
import {fireEvent, render, screen} from "../../test-utils"
|
||||
|
||||
|
||||
test("LineRenderer", async () => {
|
||||
const lines: [style: string, text: string][][] = [
|
||||
[
|
||||
["header", "foo: "],
|
||||
["text", "42"]
|
||||
],
|
||||
[
|
||||
["header", "bar: "],
|
||||
["text", "43"]
|
||||
],
|
||||
]
|
||||
|
||||
const showMore = jest.fn();
|
||||
const {asFragment} = render(<LineRenderer lines={lines} maxLines={1} showMore={showMore}/>);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
fireEvent.click(screen.getByText("Show more"));
|
||||
expect(showMore).toBeCalled();
|
||||
});
|
||||
|
||||
test("No lines", async () => {
|
||||
const {asFragment} = render(<LineRenderer lines={[]} maxLines={1} showMore={() => 0}/>);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
})
|
@ -0,0 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import ViewSelector from '../../../components/contentviews/ViewSelector'
|
||||
import {fireEvent, render, screen} from "../../test-utils"
|
||||
|
||||
|
||||
test("ViewSelector", async () => {
|
||||
|
||||
const onChange = jest.fn();
|
||||
const {asFragment} = render(<ViewSelector value="Auto" onChange={onChange}/>);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
fireEvent.click(screen.getByText("auto"));
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
fireEvent.click(screen.getByText("raw"));
|
||||
expect(onChange).toBeCalledWith("Raw");
|
||||
});
|
@ -0,0 +1,241 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`HttpMessage 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="contentview"
|
||||
>
|
||||
<div
|
||||
class="controls"
|
||||
>
|
||||
<h5>
|
||||
Raw
|
||||
</h5>
|
||||
<button
|
||||
class="btn-xs btn btn-default"
|
||||
>
|
||||
<i
|
||||
class="fa fa-edit"
|
||||
/>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-upload"
|
||||
/>
|
||||
Replace
|
||||
<input
|
||||
class="hidden"
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="fa fa-fw fa-files-o"
|
||||
/>
|
||||
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
raw
|
||||
<span
|
||||
class="caret"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<pre>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
</pre>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`HttpMessage 2`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="contentview"
|
||||
>
|
||||
<div
|
||||
class="controls"
|
||||
>
|
||||
<h5>
|
||||
[Editing]
|
||||
</h5>
|
||||
<button
|
||||
class="btn-xs btn btn-default"
|
||||
>
|
||||
<i
|
||||
class="fa fa-check text-success"
|
||||
/>
|
||||
Done
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn-xs btn btn-default"
|
||||
>
|
||||
<i
|
||||
class="fa fa-times text-danger"
|
||||
/>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="codeeditor"
|
||||
/>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`HttpMessage 3`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="contentview"
|
||||
>
|
||||
<div
|
||||
class="controls"
|
||||
>
|
||||
<h5>
|
||||
Raw
|
||||
</h5>
|
||||
<button
|
||||
class="btn-xs btn btn-default"
|
||||
>
|
||||
<i
|
||||
class="fa fa-edit"
|
||||
/>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
title="Upload a file to replace the content."
|
||||
>
|
||||
<i
|
||||
class="fa fa-fw fa-upload"
|
||||
/>
|
||||
Replace
|
||||
<input
|
||||
class="hidden"
|
||||
type="file"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="fa fa-fw fa-files-o"
|
||||
/>
|
||||
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
raw
|
||||
<span
|
||||
class="caret"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<pre>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
rawdata
|
||||
</span>
|
||||
</div>
|
||||
</pre>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`ViewImage 1`] = `
|
||||
<DocumentFragment>
|
||||
<div
|
||||
class="flowview-image"
|
||||
>
|
||||
<img
|
||||
alt="preview"
|
||||
class="img-thumbnail"
|
||||
src="./flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/request/content.data"
|
||||
/>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -0,0 +1,31 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LineRenderer 1`] = `
|
||||
<DocumentFragment>
|
||||
<pre>
|
||||
<div>
|
||||
<span
|
||||
class="header"
|
||||
>
|
||||
foo:
|
||||
</span>
|
||||
<span
|
||||
class="text"
|
||||
>
|
||||
42
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-xs btn-info"
|
||||
>
|
||||
<i
|
||||
aria-hidden="true"
|
||||
class="fa fa-angle-double-down"
|
||||
/>
|
||||
Show more
|
||||
</button>
|
||||
</pre>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`No lines 1`] = `<DocumentFragment />`;
|
@ -0,0 +1,66 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ViewSelector 1`] = `
|
||||
<DocumentFragment>
|
||||
<a
|
||||
class="btn btn-default btn-xs"
|
||||
href="#"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="fa fa-fw fa-files-o"
|
||||
/>
|
||||
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
auto
|
||||
<span
|
||||
class="caret"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`ViewSelector 2`] = `
|
||||
<DocumentFragment>
|
||||
<a
|
||||
class="btn btn-default btn-xs open"
|
||||
href="#"
|
||||
>
|
||||
<span>
|
||||
<i
|
||||
class="fa fa-fw fa-files-o"
|
||||
/>
|
||||
|
||||
<b>
|
||||
View:
|
||||
</b>
|
||||
auto
|
||||
<span
|
||||
class="caret"
|
||||
/>
|
||||
</span>
|
||||
</a>
|
||||
<ul
|
||||
class="dropdown-menu show"
|
||||
style="position: absolute; left: 0px; top: 0px;"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
auto
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="#"
|
||||
>
|
||||
raw
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -0,0 +1,31 @@
|
||||
import * as React from 'react';
|
||||
import {render, screen, waitFor} from "../../test-utils"
|
||||
import {useContent} from "../../../components/contentviews/useContent";
|
||||
import fetchMock, {enableFetchMocks} from 'jest-fetch-mock'
|
||||
|
||||
enableFetchMocks()
|
||||
|
||||
|
||||
function TComp({url, hash}: { url: string, hash: string }) {
|
||||
const content = useContent(url, hash);
|
||||
return <div>{content}</div>;
|
||||
}
|
||||
|
||||
test("caching", async () => {
|
||||
fetchMock.mockResponses("hello", "world");
|
||||
const {rerender} = render(<TComp url="/content" hash="hash"/>);
|
||||
|
||||
await waitFor(() => screen.getByText("hello"));
|
||||
rerender(<TComp url="/content" hash="hash"/>);
|
||||
expect(fetchMock.mock.calls).toHaveLength(1);
|
||||
|
||||
rerender(<TComp url="/content" hash="newhash"/>);
|
||||
await waitFor(() => screen.getByText("world"));
|
||||
expect(fetchMock.mock.calls).toHaveLength(2);
|
||||
});
|
||||
|
||||
test("network error", async () => {
|
||||
fetchMock.mockRejectOnce(new Error("I/O error"));
|
||||
render(<TComp url="/content" hash="hash"/>);
|
||||
await waitFor(() => screen.getByText("Error getting content: Error: I/O error."));
|
||||
});
|
@ -0,0 +1,27 @@
|
||||
import * as React from "react"
|
||||
import ValidateEditor from '../../../components/editors/ValidateEditor'
|
||||
import {fireEvent, render, screen, waitFor} from "../../test-utils";
|
||||
|
||||
test("ValidateEditor", async () => {
|
||||
const onEditDone = jest.fn();
|
||||
const {asFragment} = render(
|
||||
<ValidateEditor content="ok" isValid={x => x.includes("ok")} onEditDone={onEditDone}/>
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
fireEvent.mouseDown(screen.getByText("ok"));
|
||||
fireEvent.mouseUp(screen.getByText("ok"));
|
||||
|
||||
screen.getByText("ok").innerHTML = "this is ok";
|
||||
|
||||
fireEvent.blur(screen.getByText("this is ok"));
|
||||
|
||||
await waitFor(() => expect(onEditDone).toBeCalledWith("this is ok"));
|
||||
onEditDone.mockClear();
|
||||
|
||||
fireEvent.mouseDown(screen.getByText("this is ok"));
|
||||
fireEvent.mouseUp(screen.getByText("this is ok"));
|
||||
screen.getByText("this is ok").innerHTML = "wat";
|
||||
fireEvent.blur(screen.getByText("wat"));
|
||||
expect(screen.getByText("ok")).toBeDefined();
|
||||
});
|
21
web/src/js/__tests__/components/editors/ValueEditorSpec.tsx
Normal file
21
web/src/js/__tests__/components/editors/ValueEditorSpec.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import * as React from "react"
|
||||
import ValueEditor from '../../../components/editors/ValueEditor'
|
||||
import {render, waitFor} from "../../test-utils";
|
||||
|
||||
test("ValueEditor", async () => {
|
||||
const onEditDone = jest.fn();
|
||||
let editor: { current?: ValueEditor | null } = {}
|
||||
const {asFragment} = render(
|
||||
<ValueEditor ref={x => editor.current = x} content="hello world" onEditDone={onEditDone}/>
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
|
||||
if (!editor.current)
|
||||
throw "err";
|
||||
|
||||
editor.current.startEditing();
|
||||
await waitFor(() => expect(editor.current?.isEditing()).toBeTruthy());
|
||||
|
||||
editor.current.finishEditing();
|
||||
await waitFor(() => expect(onEditDone).toBeCalledWith("hello world"));
|
||||
});
|
@ -0,0 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ValidateEditor 1`] = `
|
||||
<DocumentFragment>
|
||||
<span
|
||||
class="inline-input has-success"
|
||||
tabindex="0"
|
||||
>
|
||||
ok
|
||||
</span>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -0,0 +1,12 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ValueEditor 1`] = `
|
||||
<DocumentFragment>
|
||||
<span
|
||||
class="inline-input"
|
||||
tabindex="0"
|
||||
>
|
||||
hello world
|
||||
</span>
|
||||
</DocumentFragment>
|
||||
`;
|
@ -1,18 +1,11 @@
|
||||
/** Auto-generated by test_app.py:TestApp._test_generate_tflow_js */
|
||||
/** Auto-generated by test_app.py:TestApp.test_generate_tflow_js */
|
||||
import {HTTPFlow} from '../../flow';
|
||||
export default function(): HTTPFlow {
|
||||
export default function(): Required<HTTPFlow> {
|
||||
return {
|
||||
"client_conn": {
|
||||
//@ts-ignore
|
||||
"address": [
|
||||
"127.0.0.1",
|
||||
22
|
||||
],
|
||||
"alpn": "http/1.1",
|
||||
//@ts-ignore
|
||||
"alpn_proto_negotiated": "http/1.1",
|
||||
"cert": undefined,
|
||||
"cipher": "cipher",
|
||||
"cipher_name": "cipher",
|
||||
"id": "4a18d1a0-50a1-48dd-9aa6-d45d74282939",
|
||||
"peername": [
|
||||
"127.0.0.1",
|
||||
@ -97,14 +90,9 @@ export default function(): HTTPFlow {
|
||||
22
|
||||
],
|
||||
"alpn": undefined,
|
||||
//@ts-ignore
|
||||
"alpn_proto_negotiated": undefined,
|
||||
"cert": undefined,
|
||||
"cipher": undefined,
|
||||
"id": "f087e7b2-6d0a-41a8-a8f0-e1a4761395f8",
|
||||
"ip_address": [
|
||||
"192.168.0.1",
|
||||
22
|
||||
],
|
||||
"peername": [
|
||||
"192.168.0.1",
|
||||
22
|
||||
@ -114,10 +102,6 @@ export default function(): HTTPFlow {
|
||||
"address",
|
||||
22
|
||||
],
|
||||
"source_address": [
|
||||
"address",
|
||||
22
|
||||
],
|
||||
"timestamp_end": 946681205,
|
||||
"timestamp_start": 946681202,
|
||||
"timestamp_tcp_setup": 946681203,
|
||||
@ -125,6 +109,16 @@ export default function(): HTTPFlow {
|
||||
"tls_established": true,
|
||||
"tls_version": "TLSv1.2"
|
||||
},
|
||||
"type": "http"
|
||||
"type": "http",
|
||||
"websocket": {
|
||||
"close_code": 1000,
|
||||
"close_reason": "Close Reason",
|
||||
"closed_by_client": false,
|
||||
"messages_meta": {
|
||||
"count": 3,
|
||||
"timestamp_last": 946681205
|
||||
},
|
||||
"timestamp_end": 946681205
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import reduceEventLog, * as eventLogActions from '../../ducks/eventLog'
|
||||
import reduce from '../../ducks/utils/store'
|
||||
import {reduce} from '../../ducks/utils/store'
|
||||
|
||||
describe('event log reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
|
@ -1,226 +0,0 @@
|
||||
jest.mock('../../utils')
|
||||
|
||||
import reduceFlows from "../../ducks/flows"
|
||||
import * as flowActions from "../../ducks/flows"
|
||||
import reduce from "../../ducks/utils/store"
|
||||
import { fetchApi } from "../../utils"
|
||||
import { createStore } from "./tutils"
|
||||
|
||||
describe('flow reducer', () => {
|
||||
let state = undefined
|
||||
for (let i of [1, 2, 3, 4]) {
|
||||
state = reduceFlows(state, { type: flowActions.ADD, data: { id: i }, cmd: 'add' })
|
||||
}
|
||||
|
||||
it('should return initial state', () => {
|
||||
expect(reduceFlows(undefined, {})).toEqual({
|
||||
highlight: null,
|
||||
filter: null,
|
||||
sort: { column: null, desc: false },
|
||||
selected: [],
|
||||
...reduce(undefined, {})
|
||||
})
|
||||
})
|
||||
|
||||
describe('selections', () => {
|
||||
it('should be possible to select a single flow', () => {
|
||||
expect(reduceFlows(state, flowActions.select(2))).toEqual(
|
||||
{
|
||||
...state,
|
||||
selected: [2],
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should be possible to deselect a flow', () => {
|
||||
expect(reduceFlows({ ...state, selected: [1] }, flowActions.select())).toEqual(
|
||||
{
|
||||
...state,
|
||||
selected: [],
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should be possible to select relative', () => {
|
||||
// haven't selected any flow
|
||||
expect(
|
||||
flowActions.selectRelative(state, 1)
|
||||
).toEqual(
|
||||
flowActions.select(4)
|
||||
)
|
||||
|
||||
// already selected some flows
|
||||
expect(
|
||||
flowActions.selectRelative({ ...state, selected: [2] }, 1)
|
||||
).toEqual(
|
||||
flowActions.select(3)
|
||||
)
|
||||
})
|
||||
|
||||
it('should update state.selected on remove', () => {
|
||||
let next
|
||||
next = reduceFlows({ ...state, selected: [2] }, {
|
||||
type: flowActions.REMOVE,
|
||||
data: 2,
|
||||
cmd: 'remove'
|
||||
})
|
||||
expect(next.selected).toEqual([3])
|
||||
|
||||
//last row
|
||||
next = reduceFlows({ ...state, selected: [4] }, {
|
||||
type: flowActions.REMOVE,
|
||||
data: 4,
|
||||
cmd: 'remove'
|
||||
})
|
||||
expect(next.selected).toEqual([3])
|
||||
|
||||
//multiple selection
|
||||
next = reduceFlows({ ...state, selected: [2, 3, 4] }, {
|
||||
type: flowActions.REMOVE,
|
||||
data: 3,
|
||||
cmd: 'remove'
|
||||
})
|
||||
expect(next.selected).toEqual([2, 4])
|
||||
})
|
||||
})
|
||||
|
||||
it('should be possible to set filter', () => {
|
||||
let filt = "~u 123"
|
||||
expect(reduceFlows(undefined, flowActions.setFilter(filt)).filter).toEqual(filt)
|
||||
})
|
||||
|
||||
it('should be possible to set highlight', () => {
|
||||
let key = "foo"
|
||||
expect(reduceFlows(undefined, flowActions.setHighlight(key)).highlight).toEqual(key)
|
||||
})
|
||||
|
||||
it('should be possible to set sort', () => {
|
||||
let sort = { column: "TLSColumn", desc: 1 }
|
||||
expect(reduceFlows(undefined, flowActions.setSort(sort.column, sort.desc)).sort).toEqual(sort)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('flows actions', () => {
|
||||
|
||||
let store = createStore({ reduceFlows })
|
||||
|
||||
let tflow = { id: 1 }
|
||||
it('should handle resume action', () => {
|
||||
store.dispatch(flowActions.resume(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/1/resume', { method: 'POST' })
|
||||
})
|
||||
|
||||
it('should handle resumeAll action', () => {
|
||||
store.dispatch(flowActions.resumeAll())
|
||||
expect(fetchApi).toBeCalledWith('/flows/resume', { method: 'POST' })
|
||||
})
|
||||
|
||||
it('should handle kill action', () => {
|
||||
store.dispatch(flowActions.kill(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/1/kill', { method: 'POST' })
|
||||
|
||||
})
|
||||
|
||||
it('should handle killAll action', () => {
|
||||
store.dispatch(flowActions.killAll())
|
||||
expect(fetchApi).toBeCalledWith('/flows/kill', { method: 'POST' })
|
||||
})
|
||||
|
||||
it('should handle remove action', () => {
|
||||
store.dispatch(flowActions.remove(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/1', { method: 'DELETE' })
|
||||
})
|
||||
|
||||
it('should handle duplicate action', () => {
|
||||
store.dispatch(flowActions.duplicate(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/1/duplicate', { method: 'POST' })
|
||||
})
|
||||
|
||||
it('should handle replay action', () => {
|
||||
store.dispatch(flowActions.replay(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/1/replay', { method: 'POST' })
|
||||
})
|
||||
|
||||
it('should handle revert action', () => {
|
||||
store.dispatch(flowActions.revert(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/1/revert', { method: 'POST' })
|
||||
})
|
||||
|
||||
it('should handle update action', () => {
|
||||
store.dispatch(flowActions.update(tflow, 'foo'))
|
||||
expect(fetchApi.put).toBeCalledWith('/flows/1', 'foo')
|
||||
})
|
||||
|
||||
it('should handle uploadContent action', () => {
|
||||
let body = new FormData(),
|
||||
file = new window.Blob(['foo'], { type: 'plain/text' })
|
||||
body.append('file', file)
|
||||
store.dispatch(flowActions.uploadContent(tflow, 'foo', 'foo'))
|
||||
// window.Blob's lastModified is always the current time,
|
||||
// which causes flaky tests on comparison.
|
||||
expect(fetchApi).toBeCalledWith('/flows/1/foo/content.data', { method: 'POST', body: expect.anything()})
|
||||
})
|
||||
|
||||
it('should handle clear action', () => {
|
||||
store.dispatch(flowActions.clear())
|
||||
expect(fetchApi).toBeCalledWith('/clear', { method: 'POST'} )
|
||||
})
|
||||
|
||||
it('should handle download action', () => {
|
||||
let state = reduceFlows(undefined, {})
|
||||
expect(reduceFlows(state, flowActions.download())).toEqual(state)
|
||||
})
|
||||
|
||||
it('should handle upload action', () => {
|
||||
let body = new FormData()
|
||||
body.append('file', 'foo')
|
||||
store.dispatch(flowActions.upload('foo'))
|
||||
expect(fetchApi).toBeCalledWith('/flows/dump', { method: 'POST', body })
|
||||
})
|
||||
})
|
||||
|
||||
describe('makeSort', () => {
|
||||
it('should be possible to sort by TLSColumn', () => {
|
||||
let sort = flowActions.makeSort({ column: 'TLSColumn', desc: true }),
|
||||
a = { request: { scheme: 'http' } },
|
||||
b = { request: { scheme: 'https' } }
|
||||
expect(sort(a, b)).toEqual(1)
|
||||
})
|
||||
|
||||
it('should be possible to sort by PathColumn', () => {
|
||||
let sort = flowActions.makeSort({ column: 'PathColumn', desc: true }),
|
||||
a = { request: {} },
|
||||
b = { request: {} }
|
||||
expect(sort(a, b)).toEqual(0)
|
||||
|
||||
})
|
||||
|
||||
it('should be possible to sort by MethodColumn', () => {
|
||||
let sort = flowActions.makeSort({ column: 'MethodColumn', desc: true }),
|
||||
a = { request: { method: 'GET' } },
|
||||
b = { request: { method: 'POST' } }
|
||||
expect(sort(b, a)).toEqual(-1)
|
||||
})
|
||||
|
||||
it('should be possible to sort by StatusColumn', () => {
|
||||
let sort = flowActions.makeSort({ column: 'StatusColumn', desc: false }),
|
||||
a = { response: { status_code: 200 } },
|
||||
b = { response: { status_code: 404 } }
|
||||
expect(sort(a, b)).toEqual(-1)
|
||||
})
|
||||
|
||||
it('should be possible to sort by TimeColumn', () => {
|
||||
let sort = flowActions.makeSort({ column: 'TimeColumn', desc: false }),
|
||||
a = { response: { timestamp_end: 9 }, request: { timestamp_start: 8 } },
|
||||
b = { response: { timestamp_end: 10 }, request: { timestamp_start: 8 } }
|
||||
expect(sort(b, a)).toEqual(1)
|
||||
})
|
||||
|
||||
it('should be possible to sort by SizeColumn', () => {
|
||||
let sort = flowActions.makeSort({ column: 'SizeColumn', desc: true }),
|
||||
a = { request: { contentLength: 1 }, response: { contentLength: 1 } },
|
||||
b = { request: { contentLength: 1 } }
|
||||
expect(sort(a, b)).toEqual(-1)
|
||||
})
|
||||
})
|
197
web/src/js/__tests__/ducks/flowsSpec.tsx
Normal file
197
web/src/js/__tests__/ducks/flowsSpec.tsx
Normal file
@ -0,0 +1,197 @@
|
||||
import reduceFlows, * as flowActions from "../../ducks/flows";
|
||||
import {reduce} from "../../ducks/utils/store"
|
||||
import {fetchApi} from "../../utils"
|
||||
import {TFlow, TStore} from "./tutils"
|
||||
import FlowColumns from "../../components/FlowTable/FlowColumns"
|
||||
|
||||
jest.mock('../../utils')
|
||||
|
||||
describe('flow reducer', () => {
|
||||
|
||||
let s;
|
||||
for (let i of ["1", "2", "3", "4"]) {
|
||||
s = reduceFlows(s, {type: flowActions.ADD, data: {id: i}, cmd: 'add'})
|
||||
}
|
||||
let state = s;
|
||||
|
||||
it('should return initial state', () => {
|
||||
expect(reduceFlows(undefined, {})).toEqual({
|
||||
highlight: undefined,
|
||||
filter: undefined,
|
||||
sort: {column: undefined, desc: false},
|
||||
selected: [],
|
||||
...reduce(undefined, {})
|
||||
})
|
||||
})
|
||||
|
||||
describe('selections', () => {
|
||||
it('should be possible to select a single flow', () => {
|
||||
expect(reduceFlows(state, flowActions.select("2"))).toEqual(
|
||||
{
|
||||
...state,
|
||||
selected: ["2"],
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should be possible to deselect a flow', () => {
|
||||
expect(reduceFlows({...state, selected: ["1"]}, flowActions.select())).toEqual(
|
||||
{
|
||||
...state,
|
||||
selected: [],
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it('should be possible to select relative', () => {
|
||||
// haven't selected any flow
|
||||
expect(
|
||||
flowActions.selectRelative(state, 1)
|
||||
).toEqual(
|
||||
flowActions.select("4")
|
||||
)
|
||||
|
||||
// already selected some flows
|
||||
expect(
|
||||
flowActions.selectRelative({...state, selected: [2]}, 1)
|
||||
).toEqual(
|
||||
flowActions.select("3")
|
||||
)
|
||||
})
|
||||
|
||||
it('should update state.selected on remove', () => {
|
||||
let next
|
||||
next = reduceFlows({...state, selected: ["2"]}, {
|
||||
type: flowActions.REMOVE,
|
||||
data: "2",
|
||||
cmd: 'remove'
|
||||
})
|
||||
expect(next.selected).toEqual(["3"])
|
||||
|
||||
//last row
|
||||
next = reduceFlows({...state, selected: ["4"]}, {
|
||||
type: flowActions.REMOVE,
|
||||
data: "4",
|
||||
cmd: 'remove'
|
||||
})
|
||||
expect(next.selected).toEqual(["3"])
|
||||
|
||||
//multiple selection
|
||||
next = reduceFlows({...state, selected: ["2", "3", "4"]}, {
|
||||
type: flowActions.REMOVE,
|
||||
data: "3",
|
||||
cmd: 'remove'
|
||||
})
|
||||
expect(next.selected).toEqual(["2", "4"])
|
||||
})
|
||||
})
|
||||
|
||||
it('should be possible to set filter', () => {
|
||||
let filt = "~u 123"
|
||||
expect(reduceFlows(undefined, flowActions.setFilter(filt)).filter).toEqual(filt)
|
||||
})
|
||||
|
||||
it('should be possible to set highlight', () => {
|
||||
let key = "foo"
|
||||
expect(reduceFlows(undefined, flowActions.setHighlight(key)).highlight).toEqual(key)
|
||||
})
|
||||
|
||||
it('should be possible to set sort', () => {
|
||||
let sort = {column: "tls", desc: true}
|
||||
expect(reduceFlows(undefined, flowActions.setSort(sort.column, sort.desc)).sort).toEqual(sort)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('flows actions', () => {
|
||||
|
||||
let store = TStore();
|
||||
let tflow = TFlow();
|
||||
|
||||
it('should handle resume action', () => {
|
||||
store.dispatch(flowActions.resume(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/resume', {method: 'POST'})
|
||||
})
|
||||
|
||||
it('should handle resumeAll action', () => {
|
||||
store.dispatch(flowActions.resumeAll())
|
||||
expect(fetchApi).toBeCalledWith('/flows/resume', {method: 'POST'})
|
||||
})
|
||||
|
||||
it('should handle kill action', () => {
|
||||
store.dispatch(flowActions.kill(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/kill', {method: 'POST'})
|
||||
|
||||
})
|
||||
|
||||
it('should handle killAll action', () => {
|
||||
store.dispatch(flowActions.killAll())
|
||||
expect(fetchApi).toBeCalledWith('/flows/kill', {method: 'POST'})
|
||||
})
|
||||
|
||||
it('should handle remove action', () => {
|
||||
store.dispatch(flowActions.remove(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29', {method: 'DELETE'})
|
||||
})
|
||||
|
||||
it('should handle duplicate action', () => {
|
||||
store.dispatch(flowActions.duplicate(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/duplicate', {method: 'POST'})
|
||||
})
|
||||
|
||||
it('should handle replay action', () => {
|
||||
store.dispatch(flowActions.replay(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/replay', {method: 'POST'})
|
||||
})
|
||||
|
||||
it('should handle revert action', () => {
|
||||
store.dispatch(flowActions.revert(tflow))
|
||||
expect(fetchApi).toBeCalledWith('/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/revert', {method: 'POST'})
|
||||
})
|
||||
|
||||
it('should handle update action', () => {
|
||||
store.dispatch(flowActions.update(tflow, 'foo'))
|
||||
expect(fetchApi.put).toBeCalledWith('/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29', 'foo')
|
||||
})
|
||||
|
||||
it('should handle uploadContent action', () => {
|
||||
let body = new FormData(),
|
||||
file = new window.Blob(['foo'], {type: 'plain/text'})
|
||||
body.append('file', file)
|
||||
store.dispatch(flowActions.uploadContent(tflow, 'foo', 'foo'))
|
||||
// window.Blob's lastModified is always the current time,
|
||||
// which causes flaky tests on comparison.
|
||||
expect(fetchApi).toBeCalledWith('/flows/d91165be-ca1f-4612-88a9-c0f8696f3e29/foo/content.data', {
|
||||
method: 'POST',
|
||||
body: expect.anything()
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle clear action', () => {
|
||||
store.dispatch(flowActions.clear())
|
||||
expect(fetchApi).toBeCalledWith('/clear', {method: 'POST'})
|
||||
})
|
||||
|
||||
it('should handle download action', () => {
|
||||
let state = reduceFlows(undefined, {})
|
||||
expect(reduceFlows(state, flowActions.download())).toEqual(state)
|
||||
})
|
||||
|
||||
it('should handle upload action', () => {
|
||||
let body = new FormData()
|
||||
body.append('file', 'foo')
|
||||
store.dispatch(flowActions.upload('foo'))
|
||||
expect(fetchApi).toBeCalledWith('/flows/dump', {method: 'POST', body})
|
||||
})
|
||||
})
|
||||
|
||||
test("makeSort", () => {
|
||||
const a = TFlow(), b = TFlow();
|
||||
|
||||
Object.keys(FlowColumns).forEach((column) => {
|
||||
// @ts-ignore
|
||||
const sort = flowActions.makeSort({column, desc: true});
|
||||
expect(sort(a, b)).toBeDefined();
|
||||
})
|
||||
|
||||
});
|
@ -1,69 +0,0 @@
|
||||
import reduceOptions, * as OptionsActions from '../../ducks/options'
|
||||
|
||||
import configureStore from 'redux-mock-store'
|
||||
import thunk from 'redux-thunk'
|
||||
import * as OptionsEditorActions from '../../ducks/ui/optionsEditor'
|
||||
import {updateError} from "../../ducks/ui/optionsEditor";
|
||||
|
||||
const mockStore = configureStore([ thunk ])
|
||||
|
||||
describe('option reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
expect(reduceOptions(undefined, {})).toEqual(OptionsActions.defaultState)
|
||||
})
|
||||
|
||||
it('should handle receive action', () => {
|
||||
let action = { type: OptionsActions.RECEIVE, data: {id: {value: 'foo'} } }
|
||||
expect(reduceOptions(undefined, action)).toEqual({id: 'foo'})
|
||||
})
|
||||
|
||||
it('should handle update action', () => {
|
||||
let action = {type: OptionsActions.UPDATE, data: {id: {value: 1} } }
|
||||
expect(reduceOptions(undefined, action)).toEqual({...OptionsActions.defaultState, id: 1})
|
||||
})
|
||||
})
|
||||
|
||||
describe('option actions', () => {
|
||||
|
||||
it('should be possible to update option', () => {
|
||||
let store = mockStore()
|
||||
let mockResponse = { status: 200 },
|
||||
promise = Promise.resolve(mockResponse)
|
||||
global.fetch = r => { return promise }
|
||||
store.dispatch(OptionsActions.update('foo', 'bar'))
|
||||
expect(store.getActions()).toEqual([
|
||||
{ type: OptionsEditorActions.OPTION_UPDATE_START, option: 'foo', value: 'bar'}
|
||||
])
|
||||
store.clearActions()
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendUpdate', () => {
|
||||
|
||||
it('should handle error', async () => {
|
||||
let store = mockStore()
|
||||
let mockResponse = { status: 404, text: () => "fooerror" },
|
||||
promise = Promise.resolve(mockResponse)
|
||||
global.fetch = r => { return promise }
|
||||
await store.dispatch(OptionsActions.pureSendUpdate("bar", "error"))
|
||||
expect(store.getActions()).toEqual([
|
||||
OptionsEditorActions.updateError("bar", "fooerror")
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
describe('save', () => {
|
||||
|
||||
it('should dump options', () => {
|
||||
let store = mockStore()
|
||||
global.fetch = jest.fn()
|
||||
store.dispatch(OptionsActions.save())
|
||||
expect(fetch).toBeCalledWith(
|
||||
'./options/save?_xsrf=undefined',
|
||||
{
|
||||
credentials: "same-origin",
|
||||
method: "POST"
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
40
web/src/js/__tests__/ducks/optionsSpec.tsx
Normal file
40
web/src/js/__tests__/ducks/optionsSpec.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import reduceOptions, * as OptionsActions from '../../ducks/options'
|
||||
import * as OptionsEditorActions from '../../ducks/ui/optionsEditor'
|
||||
import {enableFetchMocks} from "jest-fetch-mock";
|
||||
import {TStore} from "./tutils";
|
||||
|
||||
|
||||
describe('option reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
expect(reduceOptions(undefined, {type: "other"})).toEqual(OptionsActions.defaultState)
|
||||
})
|
||||
|
||||
it('should handle receive action', () => {
|
||||
let action = {type: OptionsActions.RECEIVE, data: {id: {value: 'foo'}}}
|
||||
expect(reduceOptions(undefined, action)).toEqual({id: 'foo'})
|
||||
})
|
||||
|
||||
it('should handle update action', () => {
|
||||
let action = {type: OptionsActions.UPDATE, data: {id: {value: 1}}}
|
||||
expect(reduceOptions(undefined, action)).toEqual({...OptionsActions.defaultState, id: 1})
|
||||
})
|
||||
})
|
||||
|
||||
test("sendUpdate", async () => {
|
||||
enableFetchMocks();
|
||||
let store = TStore();
|
||||
|
||||
fetchMock.mockResponseOnce("fooerror", {status: 404});
|
||||
await store.dispatch(dispatch => OptionsActions.pureSendUpdate("intercept", "~~~", dispatch))
|
||||
expect(store.getActions()).toEqual([
|
||||
OptionsEditorActions.updateError("intercept", "fooerror")
|
||||
])
|
||||
|
||||
store.clearActions();
|
||||
fetchMock.mockResponseOnce("", {status: 200});
|
||||
await store.dispatch(dispatch => OptionsActions.pureSendUpdate("intercept", "valid", dispatch))
|
||||
expect(store.getActions()).toEqual([
|
||||
OptionsEditorActions.updateSuccess("intercept")
|
||||
])
|
||||
|
||||
});
|
@ -1,21 +1,13 @@
|
||||
import {applyMiddleware, combineReducers, createStore as createReduxStore} from 'redux'
|
||||
import thunk from 'redux-thunk'
|
||||
import configureStore, {MockStoreCreator, MockStoreEnhanced} from 'redux-mock-store'
|
||||
import {ConnectionState} from '../../ducks/connection'
|
||||
import TFlow from './_tflow'
|
||||
import {RootState} from "../../ducks";
|
||||
import {AppDispatch, RootState} from "../../ducks";
|
||||
import {HTTPFlow} from "../../flow";
|
||||
import {defaultState as defaultConf} from "../../ducks/conf"
|
||||
import {defaultState as defaultOptions} from "../../ducks/options"
|
||||
|
||||
const mockStoreCreator: MockStoreCreator<RootState> = configureStore([thunk])
|
||||
|
||||
export function createStore(parts) {
|
||||
return createReduxStore(
|
||||
combineReducers(parts),
|
||||
applyMiddleware(...[thunk])
|
||||
)
|
||||
}
|
||||
const mockStoreCreator: MockStoreCreator<RootState, AppDispatch> = configureStore([thunk])
|
||||
|
||||
export {TFlow}
|
||||
|
||||
@ -63,18 +55,9 @@ export const testState: RootState = {
|
||||
},
|
||||
ui: {
|
||||
flow: {
|
||||
contentView: 'Auto',
|
||||
displayLarge: false,
|
||||
showFullContent: true,
|
||||
maxContentLines: 10,
|
||||
content: [[['foo', 'bar']]],
|
||||
viewDescription: 'foo',
|
||||
modifiedFlow: undefined,
|
||||
contentViewFor: {},
|
||||
tab: 'request'
|
||||
},
|
||||
header: {
|
||||
tab: 'Start'
|
||||
},
|
||||
modal: {
|
||||
activeModal: undefined
|
||||
},
|
||||
@ -87,15 +70,18 @@ export const testState: RootState = {
|
||||
},
|
||||
options: defaultOptions,
|
||||
flows: {
|
||||
selected: [tflow1.id],
|
||||
selected: [tflow2.id],
|
||||
byId: {[tflow1.id]: tflow1, [tflow2.id]: tflow2},
|
||||
filter: '~d address',
|
||||
filter: '~u /second',
|
||||
highlight: '~u /path',
|
||||
sort: {
|
||||
desc: true,
|
||||
column: 'PathColumn'
|
||||
column: "path"
|
||||
},
|
||||
view: [tflow1, tflow2]
|
||||
view: [tflow2],
|
||||
list: [tflow1, tflow2],
|
||||
listIndex: {[tflow1.id]: 0, [tflow2.id]: 1},
|
||||
viewIndex: {[tflow2.id]: 0},
|
||||
},
|
||||
connection: {
|
||||
state: ConnectionState.ESTABLISHED
|
||||
@ -110,13 +96,20 @@ export const testState: RootState = {
|
||||
error: true
|
||||
},
|
||||
view: [
|
||||
{id: 1, level: 'info', message: 'foo'},
|
||||
{id: 2, level: 'error', message: 'bar'}
|
||||
]
|
||||
{id: "1", level: 'info', message: 'foo'},
|
||||
{id: "2", level: 'error', message: 'bar'}
|
||||
],
|
||||
byId: {}, // TODO: incomplete
|
||||
list: [], // TODO: incomplete
|
||||
listIndex: {}, // TODO: incomplete
|
||||
viewIndex: {}, // TODO: incomplete
|
||||
},
|
||||
commandBar: {
|
||||
visible: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function TStore(): MockStoreEnhanced<RootState> {
|
||||
export function TStore(): MockStoreEnhanced<RootState, AppDispatch> {
|
||||
return mockStoreCreator(testState)
|
||||
}
|
||||
|
@ -1,110 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
import reducer, {
|
||||
startEdit,
|
||||
setContentViewDescription,
|
||||
setShowFullContent,
|
||||
setContent,
|
||||
updateEdit,
|
||||
stopEdit,
|
||||
setContentView,
|
||||
selectTab,
|
||||
displayLarge
|
||||
} from '../../../ducks/ui/flow'
|
||||
|
||||
import * as flowActions from '../../../ducks/flows'
|
||||
|
||||
describe('flow reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
expect(reducer(undefined, {})).toEqual({
|
||||
displayLarge: false,
|
||||
viewDescription: '',
|
||||
showFullContent: false,
|
||||
modifiedFlow: undefined,
|
||||
contentView: 'Auto',
|
||||
tab: 'request',
|
||||
content: [],
|
||||
maxContentLines: 80,
|
||||
})
|
||||
})
|
||||
|
||||
it('should change to edit mode', () => {
|
||||
let testFlow = {flow : 'foo'}
|
||||
const newState = reducer(undefined, startEdit({ flow: 'foo' }))
|
||||
expect(newState.contentView).toEqual('Edit')
|
||||
expect(newState.modifiedFlow).toEqual(testFlow)
|
||||
expect(newState.showFullContent).toEqual(true)
|
||||
})
|
||||
it('should set the view description', () => {
|
||||
expect(reducer(undefined, setContentViewDescription('description')).viewDescription)
|
||||
.toEqual('description')
|
||||
})
|
||||
|
||||
it('should set show full content', () => {
|
||||
expect(reducer({showFullContent: false}, setShowFullContent()).showFullContent)
|
||||
.toBeTruthy()
|
||||
})
|
||||
|
||||
it('should set showFullContent to true', () => {
|
||||
let maxLines = 10
|
||||
let content = _.range(maxLines)
|
||||
const newState = reducer({maxContentLines: maxLines}, setContent(content) )
|
||||
expect(newState.showFullContent).toBeTruthy()
|
||||
expect(newState.content).toEqual(content)
|
||||
})
|
||||
|
||||
it('should set showFullContent to false', () => {
|
||||
let maxLines = 5
|
||||
let content = _.range(maxLines+1);
|
||||
const newState = reducer({maxContentLines: maxLines}, setContent(_.range(maxLines+1)))
|
||||
expect(newState.showFullContent).toBeFalsy()
|
||||
expect(newState.content).toEqual(content)
|
||||
})
|
||||
|
||||
it('should not change the contentview mode', () => {
|
||||
expect(reducer({contentView: 'foo'}, flowActions.select(1)).contentView).toEqual('foo')
|
||||
})
|
||||
|
||||
it('should change the contentview mode to auto after editing when a new flow will be selected', () => {
|
||||
expect(reducer({contentView: 'foo', modifiedFlow : 'test_flow'}, flowActions.select(1)).contentView).toEqual('Auto')
|
||||
})
|
||||
|
||||
it('should set update and merge the modifiedflow with the update values', () => {
|
||||
let modifiedFlow = {headers: []}
|
||||
let updateValues = {content: 'bar'}
|
||||
let result = {headers: [], content: 'bar'}
|
||||
expect(reducer({modifiedFlow}, updateEdit(updateValues)).modifiedFlow).toEqual(result)
|
||||
})
|
||||
|
||||
it('should not change the state when a flow is updated which is not selected', () => {
|
||||
let modifiedFlow = {id: 1}
|
||||
let updatedFlow = {id: 0}
|
||||
expect(reducer({modifiedFlow}, stopEdit(updatedFlow, modifiedFlow)).modifiedFlow).toEqual(modifiedFlow)
|
||||
})
|
||||
|
||||
it('should stop editing when the selected flow is updated', () => {
|
||||
let modifiedFlow = {id: 1}
|
||||
let updatedFlow = {id: 1}
|
||||
expect(reducer(
|
||||
{ modifiedFlow },
|
||||
{type: flowActions.UPDATE, data: modifiedFlow}
|
||||
).modifiedFlow
|
||||
).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should set content view', () => {
|
||||
let state = reducer(undefined, setContentView('Edit'))
|
||||
expect(state.contentView).toEqual('Edit')
|
||||
expect(state.showFullContent).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should select different tabs', () => {
|
||||
let state = reducer(undefined, selectTab('response'))
|
||||
expect(state.tab).toEqual('response')
|
||||
expect(state.displayLarge).toBeFalsy()
|
||||
expect(state.showFullContent).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should display large', () => {
|
||||
expect(reducer(undefined, displayLarge()).displayLarge).toBeTruthy()
|
||||
})
|
||||
})
|
20
web/src/js/__tests__/ducks/ui/flowSpec.tsx
Normal file
20
web/src/js/__tests__/ducks/ui/flowSpec.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import reduceFlow, * as FlowActions from '../../../ducks/ui/flow'
|
||||
|
||||
|
||||
describe('option reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
expect(reduceFlow(undefined, {type: "other"})).toEqual(FlowActions.defaultState)
|
||||
})
|
||||
|
||||
it('should handle set tab', () => {
|
||||
expect(
|
||||
reduceFlow(undefined, FlowActions.selectTab("response")).tab
|
||||
).toEqual("response")
|
||||
})
|
||||
|
||||
it('should handle set content view', () => {
|
||||
expect(
|
||||
reduceFlow(undefined, FlowActions.setContentViewFor("foo", "Raw")).contentViewFor["foo"]
|
||||
).toEqual("Raw")
|
||||
})
|
||||
})
|
@ -1,33 +0,0 @@
|
||||
import reducer, { setActiveMenu } from '../../../ducks/ui/header'
|
||||
import * as flowActions from '../../../ducks/flows'
|
||||
|
||||
describe('header reducer', () => {
|
||||
it('should return the initial state', () => {
|
||||
expect(reducer(undefined, {}).activeMenu).toEqual('Start')
|
||||
})
|
||||
|
||||
it('should return the state for view', () => {
|
||||
expect(reducer(undefined, setActiveMenu('View')).activeMenu).toEqual('View')
|
||||
})
|
||||
|
||||
it('should change the state to Start when deselecting a flow and we a currently at the flow tab', () => {
|
||||
expect(reducer(
|
||||
{ activeMenu: 'Flow', isFlowSelected: true },
|
||||
flowActions.select(undefined)).activeMenu
|
||||
).toEqual('Start')
|
||||
})
|
||||
|
||||
it('should change the state to Flow when we selected a flow and no flow was selected before', () => {
|
||||
expect(reducer(
|
||||
{ activeMenu: 'Start', isFlowSelected: false },
|
||||
flowActions.select(1)).activeMenu
|
||||
).toEqual('Flow')
|
||||
})
|
||||
|
||||
it('should not change the state to Flow when OPTIONS tab is selected and we selected a flow and a flow as selected before', () => {
|
||||
expect(reducer(
|
||||
{ activeMenu: 'Options', isFlowSelected: true },
|
||||
flowActions.select(1)
|
||||
).activeMenu).toEqual('Options')
|
||||
})
|
||||
})
|
@ -4,6 +4,5 @@ describe('reduceUI in js/ducks/ui/index.js', () => {
|
||||
it('should combine flow and header', () => {
|
||||
let state = reduceUI(undefined, {})
|
||||
expect(state.hasOwnProperty('flow')).toBeTruthy()
|
||||
expect(state.hasOwnProperty('header')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
@ -82,7 +82,7 @@ describe('onKeyDown', () => {
|
||||
|
||||
it('should handle switch to left tab', () => {
|
||||
store.dispatch(createKeyEvent(Key.LEFT))
|
||||
expect(store.getActions()).toEqual([{ tab: 'details', type: UIActions.SET_TAB }])
|
||||
expect(store.getActions()).toEqual([{ tab: 'timing', type: UIActions.SET_TAB }])
|
||||
})
|
||||
|
||||
it('should handle switch to right tab', () => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import reduce, * as storeActions from '../../../ducks/utils/store'
|
||||
import {reduce} from '../../../ducks/utils/store'
|
||||
import * as storeActions from '../../../ducks/utils/store'
|
||||
|
||||
describe('store reducer', () => {
|
||||
it('should return initial state', () => {
|
||||
|
@ -6,7 +6,9 @@ import {createAppStore} from '../ducks'
|
||||
import {testState} from "./ducks/tutils";
|
||||
|
||||
// re-export everything
|
||||
export * from '@testing-library/react'
|
||||
export {
|
||||
waitFor, fireEvent, act, screen
|
||||
} from '@testing-library/react'
|
||||
|
||||
export function render(
|
||||
ui,
|
||||
|
@ -4,6 +4,7 @@ import { updateStoreFromUrl, updateUrlFromStore } from '../urlState'
|
||||
import reduceFlows from '../ducks/flows'
|
||||
import reduceUI from '../ducks/ui/index'
|
||||
import reduceEventLog from '../ducks/eventLog'
|
||||
import reduceCommandBar from '../ducks/commandBar'
|
||||
import * as flowsActions from '../ducks/flows'
|
||||
|
||||
import configureStore from 'redux-mock-store'
|
||||
@ -64,7 +65,8 @@ describe('updateUrlFromStore', () => {
|
||||
let initialState = {
|
||||
flows: reduceFlows(undefined, {}),
|
||||
ui: reduceUI(undefined, {}),
|
||||
eventLog: reduceEventLog(undefined, {})
|
||||
eventLog: reduceEventLog(undefined, {}),
|
||||
commandBar: reduceCommandBar(undefined, {}),
|
||||
}
|
||||
|
||||
it('should update initial url', () => {
|
||||
@ -89,7 +91,8 @@ describe('initialize', () => {
|
||||
let initialState = {
|
||||
flows: reduceFlows(undefined, {}),
|
||||
ui: reduceUI(undefined, {}),
|
||||
eventLog: reduceEventLog(undefined, {})
|
||||
eventLog: reduceEventLog(undefined, {}),
|
||||
commandBar: reduceCommandBar(undefined, {}),
|
||||
}
|
||||
|
||||
it('should handle initial state', () => {
|
||||
|
@ -27,7 +27,7 @@ describe('formatTimeSTamp', () => {
|
||||
|
||||
describe('reverseString', () => {
|
||||
it('should return reversed string', () => {
|
||||
let str1 = "abc", str2="xyz"
|
||||
let str1 = "abc", str2 = "xyz"
|
||||
expect(utils.reverseString(str1) > utils.reverseString(str2)).toBeTruthy()
|
||||
})
|
||||
})
|
||||
@ -36,13 +36,13 @@ describe('fetchApi', () => {
|
||||
it('should handle fetch operation', () => {
|
||||
utils.fetchApi('http://foo/bar', {method: "POST"})
|
||||
expect(fetch.mock.calls[0][0]).toEqual(
|
||||
"http://foo/bar?_xsrf=undefined"
|
||||
"http://foo/bar"
|
||||
)
|
||||
fetch.mockClear()
|
||||
|
||||
utils.fetchApi('http://foo?bar=1', {method: "POST"})
|
||||
expect(fetch.mock.calls[0][0]).toEqual(
|
||||
"http://foo?bar=1&_xsrf=undefined"
|
||||
"http://foo?bar=1"
|
||||
)
|
||||
|
||||
})
|
||||
@ -52,11 +52,14 @@ describe('fetchApi', () => {
|
||||
utils.fetchApi.put("http://foo", [1, 2, 3], {})
|
||||
expect(fetch.mock.calls[0]).toEqual(
|
||||
[
|
||||
"http://foo?_xsrf=undefined",
|
||||
"http://foo",
|
||||
{
|
||||
body: "[1,2,3]",
|
||||
credentials: "same-origin",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-XSRFToken": undefined,
|
||||
},
|
||||
method: "PUT"
|
||||
},
|
||||
]
|
||||
@ -66,8 +69,8 @@ describe('fetchApi', () => {
|
||||
|
||||
describe('getDiff', () => {
|
||||
it('should return json object including only the changed keys value pairs', () => {
|
||||
let obj1 = {a: 1, b:{ foo: 1} , c: [3]},
|
||||
obj2 = {a: 1, b:{ foo: 2} , c: [4]}
|
||||
expect(utils.getDiff(obj1, obj2)).toEqual({ b: {foo: 2}, c:[4]})
|
||||
let obj1 = {a: 1, b: {foo: 1}, c: [3]},
|
||||
obj2 = {a: 1, b: {foo: 2}, c: [4]}
|
||||
expect(utils.getDiff(obj1, obj2)).toEqual({b: {foo: 2}, c: [4]})
|
||||
})
|
||||
})
|
||||
|
@ -100,7 +100,7 @@ export default function CommandBar() {
|
||||
setAllCommands(data["commands"])
|
||||
setCompletionCandidate(getAvailableCommands(data["commands"]))
|
||||
setAvailableCommands(Object.keys(data))
|
||||
})
|
||||
}).catch(e => console.error(e))
|
||||
}, [])
|
||||
|
||||
const parseCommand = (originalInput: string, input: string) => {
|
||||
|
@ -204,7 +204,7 @@ export const quickactions: FlowColumn = ({flow}) => {
|
||||
const ct = flow.response && ResponseUtils.getContentType(flow.response);
|
||||
|
||||
return (
|
||||
<td className={classnames("col-quickactions", {hover: open})} onClick={(e) => 0/*e.stopPropagation()*/}>
|
||||
<td className={classnames("col-quickactions", {hover: open})} onClick={() => 0}>
|
||||
<div>
|
||||
{resume_or_replay}
|
||||
<Dropdown text={<i className="fa fa-fw fa-ellipsis-h text-muted"/>} className="quickaction"
|
||||
@ -262,3 +262,15 @@ export const quickactions: FlowColumn = ({flow}) => {
|
||||
|
||||
quickactions.headerName = ''
|
||||
quickactions.sortKey = flow => 0;
|
||||
|
||||
export default {
|
||||
icon,
|
||||
method,
|
||||
path,
|
||||
quickactions,
|
||||
size,
|
||||
status,
|
||||
time,
|
||||
timestamp,
|
||||
tls
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ type TabProps = {
|
||||
flow: Flow
|
||||
}
|
||||
|
||||
export const allTabs: { [name: string]: FunctionComponent<TabProps> } = {
|
||||
export const allTabs: { [name: string]: FunctionComponent<TabProps> & {displayName: string} } = {
|
||||
request: Request,
|
||||
response: Response,
|
||||
error: Error,
|
||||
@ -57,7 +57,7 @@ export default function FlowView() {
|
||||
event.preventDefault()
|
||||
dispatch(selectTab(tabId))
|
||||
}}>
|
||||
{allTabs[tabId].name}
|
||||
{allTabs[tabId].displayName}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
|
@ -149,3 +149,4 @@ export default function Connection({flow}: { flow: Flow }) {
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Connection.displayName = "Connection"
|
||||
|
@ -18,3 +18,4 @@ export default function Error({flow}: ErrorProps) {
|
||||
</section>
|
||||
)
|
||||
}
|
||||
Error.displayName = "Error";
|
||||
|
@ -139,8 +139,10 @@ export function Request() {
|
||||
const flow = useAppSelector(state => state.flows.byId[state.flows.selected[0]]) as HTTPFlow;
|
||||
return <Message flow={flow} message={flow.request}/>;
|
||||
}
|
||||
Request.displayName = "Request"
|
||||
|
||||
export function Response() {
|
||||
const flow = useAppSelector(state => state.flows.byId[state.flows.selected[0]]) as HTTPFlow & { response: HTTPResponse }
|
||||
return <Message flow={flow} message={flow.response}/>;
|
||||
}
|
||||
Response.displayName = "Response"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user