mirror of
https://github.com/oceanprotocol/commons.git
synced 2023-03-15 18:03:00 +01:00
Merge pull request #117 from oceanprotocol/feature/tests
Add more tests
This commit is contained in:
commit
539cc0f3c8
31
client/__mocks__/user-mock.ts
Normal file
31
client/__mocks__/user-mock.ts
Normal file
@ -0,0 +1,31 @@
|
||||
const userMock = {
|
||||
isLogged: false,
|
||||
isLoading: false,
|
||||
isWeb3: false,
|
||||
isNile: false,
|
||||
account: '',
|
||||
web3: {},
|
||||
ocean: {},
|
||||
balance: { eth: 0, ocn: 0 },
|
||||
network: '',
|
||||
requestFromFaucet: jest.fn(),
|
||||
unlockAccounts: jest.fn(),
|
||||
message: ''
|
||||
}
|
||||
|
||||
const userMockConnected = {
|
||||
isLogged: true,
|
||||
isLoading: false,
|
||||
isWeb3: true,
|
||||
isNile: true,
|
||||
account: '0xxxxxx',
|
||||
web3: {},
|
||||
ocean: {},
|
||||
balance: { eth: 0, ocn: 0 },
|
||||
network: '',
|
||||
requestFromFaucet: jest.fn(),
|
||||
unlockAccounts: jest.fn(),
|
||||
message: ''
|
||||
}
|
||||
|
||||
export { userMock, userMockConnected }
|
108
client/package-lock.json
generated
108
client/package-lock.json
generated
@ -1242,14 +1242,14 @@
|
||||
"integrity": "sha512-p2n505t2K0zD1ZvGPhI6EsSviEVLCB7BYowhf/ONmVaWED138PaG4Z9nY6YuHU383uOoIWT+Lq3dLkFzDzstXw=="
|
||||
},
|
||||
"@oceanprotocol/keeper-contracts": {
|
||||
"version": "0.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.9.1.tgz",
|
||||
"integrity": "sha512-c1LvaH+e1tzow0gZLwSWe19ap+DrZuNmZfxBdwEVEPQXarI0jTXa5qVDoiBow8kBWaqSIUgFAzQOJW8rKdlS1A=="
|
||||
"version": "0.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/keeper-contracts/-/keeper-contracts-0.9.7.tgz",
|
||||
"integrity": "sha512-nOpbSE/BG+tQBfLXZ/EqSOvUPzOuot84vHxjAfEU8K3v4eOnqFJVo+oyB7KlcF87wBJXDmi/Ir9qHY4c0Saipg=="
|
||||
},
|
||||
"@oceanprotocol/squid": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/squid/-/squid-0.5.7.tgz",
|
||||
"integrity": "sha512-q2rdlVT4n0IW8FcTrE9sfyl8lC0moAKJillUSfWadZHjdaVikBTS3iiPiKn8RIvfBL4j3RxlVHdGQdEl8rIDfA==",
|
||||
"version": "0.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/squid/-/squid-0.5.8.tgz",
|
||||
"integrity": "sha512-1hEOA5rF8qsLF6uSMVBAN4c6Licn2FCGdWLCHpZ6ePzyA2/3RXxhreUE/0mcTkmdITwlx1rCFFO+rYhDqgyPVQ==",
|
||||
"requires": {
|
||||
"@oceanprotocol/keeper-contracts": "^0.9.1",
|
||||
"bignumber.js": "^8.1.1",
|
||||
@ -1606,6 +1606,16 @@
|
||||
"resolved": "https://registry.npmjs.org/@oceanprotocol/typographies/-/typographies-0.1.0.tgz",
|
||||
"integrity": "sha512-kMsZsqvzpz9KzVbVZzllwhPoIC3zbqsdRrClagZL/C2PHzgLrKGC1kYn3gPt0RMIFg9ZjrwieKaxlgIK9i9zzg=="
|
||||
},
|
||||
"@react-mock/state": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@react-mock/state/-/state-0.1.8.tgz",
|
||||
"integrity": "sha512-oX16w3FKhfF2+nQE+C4frrfVddzwhF4YEYxF8frXzboEDZsxCRpFuQC0za3T59ZxI4ygBarBqDrhYzipGsD9TQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"lodash": "^4.17.11"
|
||||
}
|
||||
},
|
||||
"@sheerun/mutationobserver-shim": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz",
|
||||
@ -1900,9 +1910,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/jest": {
|
||||
"version": "24.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.11.tgz",
|
||||
"integrity": "sha512-2kLuPC5FDnWIDvaJBzsGTBQaBbnDweznicvK7UGYzlIJP4RJR2a4A/ByLUXEyEgag6jz8eHdlWExGDtH3EYUXQ==",
|
||||
"version": "24.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.12.tgz",
|
||||
"integrity": "sha512-60sjqMhat7i7XntZckcSGV8iREJyXXI6yFHZkSZvCPUeOnEJ/VP1rU/WpEWQ56mvoh8NhC+sfKAuJRTyGtCOow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/jest-diff": "*"
|
||||
@ -1932,9 +1942,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "16.8.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.14.tgz",
|
||||
"integrity": "sha512-26tFVJ1omGmzIdFTFmnC5zhz1GTaqCjxgUxV4KzWvsybF42P7/j4RBn6UeO3KbHPXqKWZszMXMoI65xIWm954A==",
|
||||
"version": "16.8.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.15.tgz",
|
||||
"integrity": "sha512-dMhzw1rWK+wwJWvPp5Pk12ksSrm/z/C/+lOQbMZ7YfDQYnJ02bc0wtg4EJD9qrFhuxFrf/ywNgwTboucobJqQg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
@ -2009,9 +2019,9 @@
|
||||
}
|
||||
},
|
||||
"@types/react-transition-group": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.9.0.tgz",
|
||||
"integrity": "sha512-hP7vUaZMVSWKxo133P8U51U6UZ7+pbY+eAQb8+p6SZ2rB1rj3mOTDgTzhhi+R2SCB4S+sWekAAGoxdiZPG0ReQ==",
|
||||
"version": "2.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.9.1.tgz",
|
||||
"integrity": "sha512-1usq4DRUVBFnxc9KGJAlJO9EpQrLZGDDEC8wDOn2+2ODSyudYo8FiIzPDRaX/hfQjHqGeeoNaNdA2bj0l35hZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
@ -5145,7 +5155,8 @@
|
||||
"deep-equal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
|
||||
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
|
||||
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=",
|
||||
"dev": true
|
||||
},
|
||||
"deep-is": {
|
||||
"version": "0.1.3",
|
||||
@ -5439,15 +5450,15 @@
|
||||
}
|
||||
},
|
||||
"dom-testing-library": {
|
||||
"version": "3.19.3",
|
||||
"resolved": "https://registry.npmjs.org/dom-testing-library/-/dom-testing-library-3.19.3.tgz",
|
||||
"integrity": "sha512-oiI+oq91iO/Vpp+pt8PqfqLfBK074FH0eprhoFNvBCvJOk7vL4ozbe/yj/kEEGR6kiT4F3MAam19AX1fdGFjrA==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dom-testing-library/-/dom-testing-library-4.0.1.tgz",
|
||||
"integrity": "sha512-Yr0yWlpI2QdTDEgPEk0TEekwP4VyZlJpl9E7nKP2FCKni44cb1jzjsy9KX6hBDsNA7EVlPpq9DHzO2eoEaqDZg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.3.4",
|
||||
"@babel/runtime": "^7.4.3",
|
||||
"@sheerun/mutationobserver-shim": "^0.3.2",
|
||||
"pretty-format": "^24.5.0",
|
||||
"wait-for-expect": "^1.1.0"
|
||||
"pretty-format": "^24.7.0",
|
||||
"wait-for-expect": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"dom-walk": {
|
||||
@ -8810,9 +8821,9 @@
|
||||
}
|
||||
},
|
||||
"jest-dom": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-dom/-/jest-dom-3.1.3.tgz",
|
||||
"integrity": "sha512-V9LdySiA74/spcAKEG3FRMRKnisKlcYr3EeCNYI4n7CWNE7uYg5WoBUHeGXirjWjRYLLZ5vx8rUaR/6x6o75oQ==",
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/jest-dom/-/jest-dom-3.1.4.tgz",
|
||||
"integrity": "sha512-ruIRHoRVnqPRt/HSS2aFukfhTpjEoq1I6PkYptKK5U2EeRm1eeOXG7BFiaMncTaGu4COSoCF84oLHj02+J5VDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.1",
|
||||
@ -10984,9 +10995,9 @@
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz",
|
||||
"integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA=="
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz",
|
||||
"integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw=="
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "0.7.5",
|
||||
@ -13049,9 +13060,9 @@
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.4.2.tgz",
|
||||
"integrity": "sha512-DfJqAen17LfLA3rQ+H5S4uXphrF+ANU1lT2ijds4V/Tj4gZxA3gx5/tg1bz7kYCmwna7LyJNCYqO7jNRzo3aLw==",
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.5.0.tgz",
|
||||
"integrity": "sha512-TYC4hDjZSvVxLMEucDMySkuAS9UIzSbAiYGyA9GWCjLKB8fQpviFbjd20fD7uejCDxZS+ftSdBKE6DS+xucJFg==",
|
||||
"requires": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"split-on-first": "^1.0.0",
|
||||
@ -13178,9 +13189,9 @@
|
||||
}
|
||||
},
|
||||
"react-datepicker": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-2.4.0.tgz",
|
||||
"integrity": "sha512-ZOY7oYmZt+jeSFGj4NHNdCg7WzzIljPui98lGRd7YHNPO3B8Re4WVNALktp/x+mz1ofNO+TPzodMLMXzqjAUnw==",
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-2.5.0.tgz",
|
||||
"integrity": "sha512-X8D+5CqumSUwoq/x5d8O0neYDRmPmwVcyCktVbs5juXV4s73beV6sMf87hM6lxMSanWeB+jpx8waxJcPqsmCIg==",
|
||||
"requires": {
|
||||
"classnames": "^2.2.5",
|
||||
"date-fns": "^2.0.0-alpha.23",
|
||||
@ -13359,19 +13370,24 @@
|
||||
"integrity": "sha512-O9JRum1Zq/qCPFH5qVEvDDrVun8Jv9vbHtZXCR1EuRj9sKg1xJTlHxBzU6AkCzpvxRLuiY4OKImy3cDLQ+UTdg==",
|
||||
"dev": true
|
||||
},
|
||||
"react-fast-compare": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
|
||||
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
|
||||
},
|
||||
"react-ga": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/react-ga/-/react-ga-2.5.7.tgz",
|
||||
"integrity": "sha512-UmATFaZpEQDO96KFjB5FRLcT6hFcwaxOmAJZnjrSiFN/msTqylq9G+z5Z8TYzN/dbamDTiWf92m6MnXXJkAivQ=="
|
||||
},
|
||||
"react-helmet": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-5.2.0.tgz",
|
||||
"integrity": "sha1-qBgR3yExOm1VxfBYxK66XW89l6c=",
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-5.2.1.tgz",
|
||||
"integrity": "sha512-CnwD822LU8NDBnjCpZ4ySh8L6HYyngViTZLfBBb3NjtrpN8m49clH8hidHouq20I51Y6TpCTISCBbqiY5GamwA==",
|
||||
"requires": {
|
||||
"deep-equal": "^1.0.1",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.5.4",
|
||||
"react-fast-compare": "^2.0.2",
|
||||
"react-side-effect": "^1.1.0"
|
||||
}
|
||||
},
|
||||
@ -13568,13 +13584,13 @@
|
||||
}
|
||||
},
|
||||
"react-testing-library": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-testing-library/-/react-testing-library-6.1.2.tgz",
|
||||
"integrity": "sha512-z69lhRDGe7u/NOjDCeFRoe1cB5ckJ4656n0tj/Fdcr6OoBUu7q9DBw0ftR7v5i3GRpdSWelnvl+feZFOyXyxwg==",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-testing-library/-/react-testing-library-7.0.0.tgz",
|
||||
"integrity": "sha512-8SHqwG+uhN9VhAgNVkVa3f7VjTw/L5CIaoAxKmy+EZuDQ6O+VsfcpRAyUw3MDL1h8S/gGrEiazmHBVL/uXsftA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.4.2",
|
||||
"dom-testing-library": "^3.19.0"
|
||||
"@babel/runtime": "^7.4.3",
|
||||
"dom-testing-library": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"react-transition-group": {
|
||||
@ -15826,9 +15842,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.4.tgz",
|
||||
"integrity": "sha512-xt5RsIRCEaf6+j9AyOBgvVuAec0i92rgCaS3S+UVf5Z/vF2Hvtsw08wtUTJqp4djwznoAgjSxeCcU4r+CcDBJA==",
|
||||
"version": "3.4.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz",
|
||||
"integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==",
|
||||
"dev": true
|
||||
},
|
||||
"ua-parser-js": {
|
||||
|
@ -6,14 +6,14 @@
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts --max_old_space_size=4096 build",
|
||||
"test": "react-scripts test --coverage",
|
||||
"test:watch": "react-scripts test --coverage --watch",
|
||||
"test": "react-scripts test --coverage --watchAll=false",
|
||||
"test:watch": "react-scripts test --coverage",
|
||||
"eject": "react-scripts eject",
|
||||
"coverage": "cat coverage/lcov.info | codacy-coverage --token 8801f827fe1144ffa85cd7da94f2bbf7"
|
||||
},
|
||||
"dependencies": {
|
||||
"@oceanprotocol/art": "^2.2.0",
|
||||
"@oceanprotocol/squid": "^0.5.7",
|
||||
"@oceanprotocol/squid": "^0.5.8",
|
||||
"@oceanprotocol/typographies": "^0.1.0",
|
||||
"classnames": "^2.2.6",
|
||||
"ethereum-blockies": "MyEtherWallet/blockies",
|
||||
@ -21,14 +21,14 @@
|
||||
"history": "^4.9.0",
|
||||
"is-url": "^1.2.4",
|
||||
"moment": "^2.24.0",
|
||||
"query-string": "^6.4.2",
|
||||
"query-string": "^6.5.0",
|
||||
"react": "^16.8.6",
|
||||
"react-datepicker": "^2.3.0",
|
||||
"react-datepicker": "^2.5.0",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-dotdotdot": "^1.2.3",
|
||||
"react-dotdotdot": "^1.3.0",
|
||||
"react-ga": "^2.5.7",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-markdown": "^4.0.6",
|
||||
"react-helmet": "^5.2.1",
|
||||
"react-markdown": "^4.0.8",
|
||||
"react-moment": "^0.9.2",
|
||||
"react-paginate": "^6.3.0",
|
||||
"react-popper": "^1.3.3",
|
||||
@ -38,24 +38,25 @@
|
||||
"web3": "1.0.0-beta.37"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@react-mock/state": "^0.1.8",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/filesize": "^4.1.0",
|
||||
"@types/is-url": "^1.2.28",
|
||||
"@types/jest": "^24.0.11",
|
||||
"@types/react": "^16.8.13",
|
||||
"@types/react-datepicker": "^2.2.1",
|
||||
"@types/react-dom": "^16.8.3",
|
||||
"@types/jest": "^24.0.12",
|
||||
"@types/react": "^16.8.15",
|
||||
"@types/react-datepicker": "^2.3.0",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"@types/react-dotdotdot": "^1.2.0",
|
||||
"@types/react-helmet": "^5.0.8",
|
||||
"@types/react-paginate": "^6.2.1",
|
||||
"@types/react-router-dom": "^4.3.1",
|
||||
"@types/react-transition-group": "^2.8.0",
|
||||
"@types/react-router-dom": "^4.3.2",
|
||||
"@types/react-transition-group": "^2.9.1",
|
||||
"@types/web3": "^1.0.18",
|
||||
"jest-dom": "^3.1.3",
|
||||
"jest-dom": "^3.1.4",
|
||||
"node-sass": "^4.12.0",
|
||||
"react-scripts": "^3.0.0",
|
||||
"react-testing-library": "^6.1.2",
|
||||
"typescript": "^3.4.3"
|
||||
"react-testing-library": "^7.0.0",
|
||||
"typescript": "^3.4.5"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -66,5 +67,11 @@
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
],
|
||||
"jest": {
|
||||
"collectCoverageFrom": [
|
||||
"src/**/*.{ts,tsx}",
|
||||
"!src/serviceWorker.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,25 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import App from './App'
|
||||
import { User } from './context'
|
||||
import { userMock } from '../__mocks__/user-mock'
|
||||
|
||||
describe('App', () => {
|
||||
it('should be able to run tests', () => {
|
||||
expect(1 + 2).toEqual(3)
|
||||
})
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<App />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders loading state', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={{ ...userMock, isLoading: true }}>
|
||||
<App />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.querySelector('.spinner')).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
@ -4,7 +4,6 @@ import Header from './components/organisms/Header'
|
||||
import Footer from './components/organisms/Footer'
|
||||
import Spinner from './components/atoms/Spinner'
|
||||
import { User } from './context'
|
||||
import UserProvider from './context/UserProvider'
|
||||
import Routes from './Routes'
|
||||
import './styles/global.scss'
|
||||
import styles from './App.module.scss'
|
||||
@ -12,33 +11,27 @@ import styles from './App.module.scss'
|
||||
export default class App extends Component {
|
||||
public render() {
|
||||
return (
|
||||
<UserProvider>
|
||||
<div className={styles.app}>
|
||||
<Router>
|
||||
<>
|
||||
<Header />
|
||||
<div className={styles.app}>
|
||||
<Router>
|
||||
<>
|
||||
<Header />
|
||||
|
||||
<main className={styles.main}>
|
||||
<User.Consumer>
|
||||
{states =>
|
||||
states.isLoading ? (
|
||||
<div className={styles.loader}>
|
||||
<Spinner
|
||||
message={states.message}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Routes />
|
||||
)
|
||||
}
|
||||
</User.Consumer>
|
||||
</main>
|
||||
<main className={styles.main}>
|
||||
{this.context.isLoading ? (
|
||||
<div className={styles.loader}>
|
||||
<Spinner message={this.context.message} />
|
||||
</div>
|
||||
) : (
|
||||
<Routes />
|
||||
)}
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</>
|
||||
</Router>
|
||||
</div>
|
||||
</UserProvider>
|
||||
<Footer />
|
||||
</>
|
||||
</Router>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
App.contextType = User
|
||||
|
15
client/src/Routes.test.tsx
Normal file
15
client/src/Routes.test.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
import { BrowserRouter as Router } from 'react-router-dom'
|
||||
import { render } from 'react-testing-library'
|
||||
import Routes from './Routes'
|
||||
|
||||
describe('Routes', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(
|
||||
<Router>
|
||||
<Routes />
|
||||
</Router>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
28
client/src/components/atoms/Account.test.tsx
Normal file
28
client/src/components/atoms/Account.test.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import { toDataUrl } from 'ethereum-blockies'
|
||||
import Account from './Account'
|
||||
|
||||
describe('Account', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Account account={'0xxxxxxxxxxxxxxx'} />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('outputs empty state without account', () => {
|
||||
const { container } = render(<Account account={''} />)
|
||||
expect(container.firstChild).toHaveTextContent('No account selected')
|
||||
})
|
||||
|
||||
it('outputs blockie img', () => {
|
||||
const account = '0xxxxxxxxxxxxxxx'
|
||||
const blockies = toDataUrl(account)
|
||||
|
||||
const { container } = render(<Account account={account} />)
|
||||
expect(container.querySelector('.blockies')).toBeInTheDocument()
|
||||
expect(container.querySelector('.blockies')).toHaveAttribute(
|
||||
'src',
|
||||
blockies
|
||||
)
|
||||
})
|
||||
})
|
@ -4,7 +4,7 @@ import { toDataUrl } from 'ethereum-blockies'
|
||||
import styles from './Account.module.scss'
|
||||
|
||||
const Account = ({ account }: { account: string }) => {
|
||||
const blockies = toDataUrl(account)
|
||||
const blockies = account && toDataUrl(account)
|
||||
|
||||
return account && blockies ? (
|
||||
<div className={styles.account}>
|
||||
|
@ -1,16 +1,13 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import slugify from 'slugify'
|
||||
import CategoryImage from './CategoryImage'
|
||||
import formPublish from '../../data/form-publish.json'
|
||||
|
||||
describe('CategoryImage', () => {
|
||||
it('renders fallback image', () => {
|
||||
const { container, getByTestId } = render(
|
||||
<CategoryImage data-testid="image" category={''} />
|
||||
)
|
||||
const { container } = render(<CategoryImage category={''} />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
expect(getByTestId('image').style.backgroundImage).toMatch(
|
||||
expect(container.firstChild.style.backgroundImage).toMatch(
|
||||
/jellyfish-back/
|
||||
)
|
||||
})
|
||||
@ -21,13 +18,8 @@ describe('CategoryImage', () => {
|
||||
: []
|
||||
|
||||
options.map((category: string) => {
|
||||
const { getByTestId } = render(
|
||||
<CategoryImage data-testid="image" category={category} />
|
||||
)
|
||||
expect(getByTestId('image')).toBeInTheDocument()
|
||||
// expect(getByTestId('image').style.backgroundImage).toMatch(
|
||||
// slugify(category, { lower: true })
|
||||
// )
|
||||
const { container } = render(<CategoryImage category={category} />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -148,7 +148,6 @@ export default class CategoryImage extends PureComponent<{ category: string }> {
|
||||
style={{
|
||||
backgroundImage: `url(${image})`
|
||||
}}
|
||||
{...this.props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
29
client/src/components/atoms/Form/Form.test.tsx
Normal file
29
client/src/components/atoms/Form/Form.test.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Form from './Form'
|
||||
|
||||
describe('Form', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Form>Hello</Form>)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders title & description when set', () => {
|
||||
const { container } = render(
|
||||
<Form title="Hello Title" description="Hello Description">
|
||||
Hello
|
||||
</Form>
|
||||
)
|
||||
expect(container.querySelector('.formTitle')).toHaveTextContent(
|
||||
'Hello Title'
|
||||
)
|
||||
expect(container.querySelector('.formDescription')).toHaveTextContent(
|
||||
'Hello Description'
|
||||
)
|
||||
})
|
||||
|
||||
it('can switch to minimal', () => {
|
||||
const { container } = render(<Form minimal>Hello</Form>)
|
||||
expect(container.firstChild).toHaveClass('formMinimal')
|
||||
})
|
||||
})
|
90
client/src/components/atoms/Form/Input.test.tsx
Normal file
90
client/src/components/atoms/Form/Input.test.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Input from './Input'
|
||||
|
||||
describe('Input', () => {
|
||||
it('renders default without crashing', () => {
|
||||
const { container } = render(<Input name="my-input" label="My Input" />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
expect(container.querySelector('.label')).toHaveTextContent('My Input')
|
||||
expect(container.querySelector('.input')).toHaveAttribute(
|
||||
'id',
|
||||
'my-input'
|
||||
)
|
||||
})
|
||||
|
||||
it('renders as text input by default', () => {
|
||||
const { container } = render(<Input name="my-input" label="My Input" />)
|
||||
expect(container.querySelector('.input')).toHaveAttribute(
|
||||
'type',
|
||||
'text'
|
||||
)
|
||||
})
|
||||
|
||||
it('renders search', () => {
|
||||
const { container } = render(
|
||||
<Input name="my-input" label="My Input" type="search" />
|
||||
)
|
||||
expect(container.querySelector('.input')).toHaveAttribute(
|
||||
'type',
|
||||
'search'
|
||||
)
|
||||
expect(container.querySelector('label + div')).toHaveClass(
|
||||
'inputWrapSearch'
|
||||
)
|
||||
})
|
||||
|
||||
it('renders select', () => {
|
||||
const { container } = render(
|
||||
<Input
|
||||
name="my-input"
|
||||
label="My Input"
|
||||
type="select"
|
||||
options={['hello', 'hello2']}
|
||||
/>
|
||||
)
|
||||
expect(container.querySelector('select')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders textarea', () => {
|
||||
const { container } = render(
|
||||
<Input name="my-input" label="My Input" type="textarea" rows={40} />
|
||||
)
|
||||
expect(container.querySelector('textarea')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders radios', () => {
|
||||
const { container } = render(
|
||||
<Input
|
||||
name="my-input"
|
||||
label="My Input"
|
||||
type="radio"
|
||||
options={['hello', 'hello2']}
|
||||
/>
|
||||
)
|
||||
expect(container.querySelector('input[type=radio]')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders checkboxes', () => {
|
||||
const { container } = render(
|
||||
<Input
|
||||
name="my-input"
|
||||
label="My Input"
|
||||
type="checkbox"
|
||||
options={['hello', 'hello2']}
|
||||
/>
|
||||
)
|
||||
expect(
|
||||
container.querySelector('input[type=checkbox]')
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders date picker', () => {
|
||||
const { container } = render(
|
||||
<Input name="my-input" label="My Input" type="date" />
|
||||
)
|
||||
expect(
|
||||
container.querySelector('.react-datepicker-wrapper')
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -60,9 +60,8 @@ export default class Input extends PureComponent<InputProps, InputState> {
|
||||
}
|
||||
|
||||
private handleDateChange = (date: Date) => {
|
||||
this.setState({
|
||||
dateCreated: date
|
||||
})
|
||||
this.setState({ dateCreated: date })
|
||||
|
||||
const event = {
|
||||
currentTarget: {
|
||||
name: 'dateCreated',
|
||||
@ -80,7 +79,8 @@ export default class Input extends PureComponent<InputProps, InputState> {
|
||||
name,
|
||||
required,
|
||||
onChange,
|
||||
value
|
||||
value,
|
||||
rows
|
||||
} = this.props
|
||||
|
||||
const wrapClass = this.inputWrapClasses()
|
||||
@ -119,7 +119,7 @@ export default class Input extends PureComponent<InputProps, InputState> {
|
||||
className={styles.input}
|
||||
onFocus={this.toggleFocus}
|
||||
onBlur={this.toggleFocus}
|
||||
{...this.props}
|
||||
rows={rows}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
@ -174,6 +174,7 @@ export default class Input extends PureComponent<InputProps, InputState> {
|
||||
<InputGroup>
|
||||
<input
|
||||
id={name}
|
||||
type={type || 'text'}
|
||||
className={styles.input}
|
||||
onFocus={this.toggleFocus}
|
||||
onBlur={this.toggleFocus}
|
||||
@ -184,6 +185,7 @@ export default class Input extends PureComponent<InputProps, InputState> {
|
||||
) : (
|
||||
<input
|
||||
id={name}
|
||||
type={type || 'text'}
|
||||
className={styles.input}
|
||||
onFocus={this.toggleFocus}
|
||||
onBlur={this.toggleFocus}
|
||||
|
10
client/src/components/atoms/Form/InputGroup.test.tsx
Normal file
10
client/src/components/atoms/Form/InputGroup.test.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import InputGroup from './InputGroup'
|
||||
|
||||
describe('InputGroup', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<InputGroup>Hello</InputGroup>)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
20
client/src/components/atoms/Form/Label.test.tsx
Normal file
20
client/src/components/atoms/Form/Label.test.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Label from './Label'
|
||||
|
||||
describe('Label', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Label htmlFor="hello">Hello</Label>)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders required state', () => {
|
||||
const { container } = render(
|
||||
<Label required htmlFor="hello">
|
||||
Hello
|
||||
</Label>
|
||||
)
|
||||
expect(container.firstChild).toHaveAttribute('title', 'Required')
|
||||
expect(container.firstChild).toHaveClass('required')
|
||||
})
|
||||
})
|
10
client/src/components/atoms/Form/Row.test.tsx
Normal file
10
client/src/components/atoms/Form/Row.test.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Row from './Row'
|
||||
|
||||
describe('Row', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Row>Hello</Row>)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
10
client/src/components/atoms/Markdown.test.tsx
Normal file
10
client/src/components/atoms/Markdown.test.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Markdown from './Markdown'
|
||||
|
||||
describe('Markdown', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Markdown text={'#hello'} />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
|
||||
const Description = ({
|
||||
const Markdown = ({
|
||||
text,
|
||||
className
|
||||
}: {
|
||||
@ -15,4 +15,4 @@ const Description = ({
|
||||
return <ReactMarkdown source={textCleaned} className={className} />
|
||||
}
|
||||
|
||||
export default Description
|
||||
export default Markdown
|
||||
|
@ -0,0 +1,49 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Popover from './Popover'
|
||||
import { userMock, userMockConnected } from '../../../../__mocks__/user-mock'
|
||||
import { User } from '../../../context'
|
||||
|
||||
describe('Popover', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={userMock}>
|
||||
<Popover forwardedRef={() => null} style={{}} />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders connected without crashing', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={userMockConnected}>
|
||||
<Popover forwardedRef={() => null} style={{}} />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders correct network', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={{ ...userMockConnected, network: 'Nile' }}>
|
||||
<Popover forwardedRef={() => null} style={{}} />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
expect(container.firstChild).toHaveTextContent('Connected to Nile')
|
||||
})
|
||||
|
||||
it('renders with wrong network', () => {
|
||||
const { container } = render(
|
||||
<User.Provider
|
||||
value={{ ...userMockConnected, isNile: false, network: '1' }}
|
||||
>
|
||||
<Popover forwardedRef={() => null} style={{}} />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
expect(container.firstChild).toHaveTextContent(
|
||||
'Please connect to Custom RPC'
|
||||
)
|
||||
})
|
||||
})
|
@ -9,6 +9,7 @@ export default class Popover extends PureComponent<{
|
||||
}> {
|
||||
public render() {
|
||||
const { account, balance, network, isWeb3, isNile } = this.context
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.popover}
|
||||
|
20
client/src/components/molecules/AccountStatus/index.test.tsx
Normal file
20
client/src/components/molecules/AccountStatus/index.test.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react'
|
||||
import { render, fireEvent } from 'react-testing-library'
|
||||
import AccountStatus from '.'
|
||||
|
||||
describe('AccountStatus', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<AccountStatus />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('togglePopover fires', () => {
|
||||
const { container } = render(<AccountStatus />)
|
||||
|
||||
const indicator = container.querySelector('.statusIndicator')
|
||||
|
||||
indicator && fireEvent.mouseOver(indicator)
|
||||
expect(container.querySelector('.popover')).toBeInTheDocument()
|
||||
indicator && fireEvent.mouseOut(indicator)
|
||||
})
|
||||
})
|
@ -19,7 +19,7 @@ export default class AccountStatus extends PureComponent<
|
||||
isPopoverOpen: false
|
||||
}
|
||||
|
||||
public togglePopover() {
|
||||
private togglePopover() {
|
||||
this.setState(prevState => ({
|
||||
isPopoverOpen: !prevState.isPopoverOpen
|
||||
}))
|
||||
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Pagination from './Pagination'
|
||||
|
||||
describe('Button', () => {
|
||||
describe('Pagination', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(
|
||||
<Pagination
|
||||
|
@ -8,25 +8,19 @@ import styles from './Header.module.scss'
|
||||
import menu from '../../data/menu.json'
|
||||
import meta from '../../data/meta.json'
|
||||
|
||||
const MenuItem = ({ item, isWeb3 }: { item: any; isWeb3: boolean }) => {
|
||||
if (item.web3 && !isWeb3) return null
|
||||
|
||||
return (
|
||||
<NavLink
|
||||
to={item.link}
|
||||
className={styles.link}
|
||||
activeClassName={styles.linkActive}
|
||||
exact
|
||||
>
|
||||
{item.title}
|
||||
</NavLink>
|
||||
)
|
||||
}
|
||||
const MenuItem = ({ item }: { item: any }) => (
|
||||
<NavLink
|
||||
to={item.link}
|
||||
className={styles.link}
|
||||
activeClassName={styles.linkActive}
|
||||
exact
|
||||
>
|
||||
{item.title}
|
||||
</NavLink>
|
||||
)
|
||||
|
||||
export default class Header extends PureComponent {
|
||||
public render() {
|
||||
const { isWeb3 } = this.context
|
||||
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<div className={styles.headerContent}>
|
||||
@ -37,11 +31,7 @@ export default class Header extends PureComponent {
|
||||
|
||||
<nav className={styles.headerMenu}>
|
||||
{menu.map(item => (
|
||||
<MenuItem
|
||||
key={item.title}
|
||||
item={item}
|
||||
isWeb3={isWeb3}
|
||||
/>
|
||||
<MenuItem key={item.title} item={item} />
|
||||
))}
|
||||
<AccountStatus className={styles.accountStatus} />
|
||||
</nav>
|
||||
|
@ -1,11 +1,62 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import { render, fireEvent } from 'react-testing-library'
|
||||
import Web3message from './Web3message'
|
||||
import { User } from '../../context'
|
||||
import { userMock, userMockConnected } from '../../../__mocks__/user-mock'
|
||||
|
||||
describe('Web3message', () => {
|
||||
it('default renders without crashing', () => {
|
||||
const { container } = render(<Web3message />)
|
||||
it('renders with noWeb3 message', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={{ ...userMock }}>
|
||||
<Web3message />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toHaveTextContent('Not a Web3 Browser')
|
||||
})
|
||||
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
it('renders with wrongNetwork message', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={{ ...userMock, isWeb3: true }}>
|
||||
<Web3message />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toHaveTextContent(
|
||||
'Not connected to Nile network'
|
||||
)
|
||||
})
|
||||
|
||||
it('renders with noAccount message', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={{ ...userMock, isWeb3: true, isNile: true }}>
|
||||
<Web3message />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toHaveTextContent('No accounts detected')
|
||||
})
|
||||
|
||||
it('renders with hasAccount message', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={userMockConnected}>
|
||||
<Web3message />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toHaveTextContent('0xxxxxx')
|
||||
})
|
||||
|
||||
it('button click fires unlockAccounts', () => {
|
||||
const { getByText } = render(
|
||||
<User.Provider
|
||||
value={{
|
||||
...userMock,
|
||||
isWeb3: true,
|
||||
isNile: true
|
||||
}}
|
||||
>
|
||||
<Web3message />
|
||||
</User.Provider>
|
||||
)
|
||||
|
||||
fireEvent.click(getByText('Unlock Account'))
|
||||
expect(userMock.unlockAccounts).toBeCalled()
|
||||
})
|
||||
})
|
||||
|
24
client/src/components/templates/Route.test.tsx
Normal file
24
client/src/components/templates/Route.test.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Route from './Route'
|
||||
|
||||
describe('Route', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Route title="Hello Title">Hello</Route>)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders title & description', () => {
|
||||
const { container } = render(
|
||||
<Route title="Hello Title" description="Hello Description">
|
||||
Hello
|
||||
</Route>
|
||||
)
|
||||
expect(container.querySelector('.title')).toHaveTextContent(
|
||||
'Hello Title'
|
||||
)
|
||||
expect(container.querySelector('.description')).toHaveTextContent(
|
||||
'Hello Description'
|
||||
)
|
||||
})
|
||||
})
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import Web3 from 'web3'
|
||||
import { Logger } from '@oceanprotocol/squid'
|
||||
import { Logger, Ocean, Account } from '@oceanprotocol/squid'
|
||||
import { User } from '.'
|
||||
import { provideOcean, requestFromFaucet, FaucetResponse } from '../ocean'
|
||||
import { nodeHost, nodePort, nodeScheme } from '../config'
|
||||
@ -54,7 +54,7 @@ interface UserProviderState {
|
||||
}
|
||||
network: string
|
||||
web3: Web3
|
||||
ocean: any
|
||||
ocean: Ocean
|
||||
requestFromFaucet(account: string): Promise<FaucetResponse>
|
||||
unlockAccounts(): Promise<any>
|
||||
message: string
|
||||
@ -117,7 +117,7 @@ export default class UserProvider extends PureComponent<{}, UserProviderState> {
|
||||
}
|
||||
}
|
||||
|
||||
private getWeb3 = async () => {
|
||||
private getWeb3 = () => {
|
||||
// Modern dapp browsers
|
||||
if (window.ethereum) {
|
||||
window.web3 = new Web3(window.ethereum)
|
||||
@ -236,7 +236,7 @@ export default class UserProvider extends PureComponent<{}, UserProviderState> {
|
||||
}
|
||||
}
|
||||
|
||||
private fetchBalance = async (account: any) => {
|
||||
private fetchBalance = async (account: Account) => {
|
||||
const balance = await account.getBalance()
|
||||
const { eth, ocn } = balance
|
||||
if (eth !== this.state.balance.eth || ocn !== this.state.balance.ocn) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"noweb3": "Not a Web3 Browser. For publishing and downloading an asset you need to <a href='https://docs.oceanprotocol.com/tutorials/metamask-setup/' target='_blank' rel='noopener noreferrer'>setup MetaMask</a> or use any other Web3-capable plugin or browser.",
|
||||
"noAccount": "No accounts detected. For publishing and downloading an asset you need to unlock your Web3 account.",
|
||||
"hasAccount": "Connected with account ",
|
||||
"hasAccount": "",
|
||||
"wrongNetwork": "Not connected to Nile network.<br />Please connect in MetaMask with Custom RPC <code>https://nile.dev-ocean.com</code>"
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ const withTracker = <P extends RouteComponentProps>(
|
||||
options: FieldsObject = {}
|
||||
) => {
|
||||
ReactGA.initialize(analyticsId, {
|
||||
testMode: process.env.NODE_ENV === 'development',
|
||||
testMode: process.env.NODE_ENV === 'test',
|
||||
debug: false
|
||||
})
|
||||
|
||||
|
22
client/src/index.test.tsx
Normal file
22
client/src/index.test.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import ReactDOM from 'react-dom'
|
||||
import { renderToDOM } from './index'
|
||||
|
||||
describe('test ReactDOM.render', () => {
|
||||
const originalRender = ReactDOM.render
|
||||
const originalGetElement = global.document.getElementById
|
||||
|
||||
beforeEach(() => {
|
||||
global.document.getElementById = () => true
|
||||
ReactDOM.render = jest.fn()
|
||||
})
|
||||
|
||||
afterAll(() => {
|
||||
global.document.getElementById = originalGetElement
|
||||
ReactDOM.render = originalRender
|
||||
})
|
||||
|
||||
it('should call ReactDOM.render', () => {
|
||||
renderToDOM()
|
||||
expect(ReactDOM.render).toHaveBeenCalled()
|
||||
})
|
||||
})
|
@ -1,9 +1,25 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import UserProvider from './context/UserProvider'
|
||||
import App from './App'
|
||||
import * as serviceWorker from './serviceWorker'
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'))
|
||||
function renderToDOM() {
|
||||
const root = document.getElementById('root')
|
||||
|
||||
if (root !== null) {
|
||||
ReactDOM.render(
|
||||
<UserProvider>
|
||||
<App />
|
||||
</UserProvider>,
|
||||
root
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export { renderToDOM }
|
||||
|
||||
renderToDOM()
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
// unregister() to register() below. Note this comes with some pitfalls.
|
||||
|
17
client/src/ocean.test.ts
Normal file
17
client/src/ocean.test.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import Web3 from 'web3'
|
||||
import { provideOcean, requestFromFaucet } from './ocean'
|
||||
|
||||
describe('ocean', () => {
|
||||
const web3 = new Web3(Web3.givenProvider)
|
||||
|
||||
it('provideOcean can be called', async () => {
|
||||
const response = await provideOcean(web3)
|
||||
expect(response.ocean).toBeTruthy()
|
||||
})
|
||||
|
||||
it('requestFromFaucet can be called', async () => {
|
||||
const response = await requestFromFaucet('0xxxxxx')
|
||||
response &&
|
||||
expect(response.errors[0].msg).toBe('Invalid Ethereum address')
|
||||
})
|
||||
})
|
@ -72,6 +72,6 @@ export async function requestFromFaucet(account: string) {
|
||||
})
|
||||
return response.json()
|
||||
} catch (error) {
|
||||
Logger.log('requestFromFaucet', error)
|
||||
Logger.error('requestFromFaucet', error)
|
||||
}
|
||||
}
|
||||
|
10
client/src/routes/About.test.tsx
Normal file
10
client/src/routes/About.test.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import About from './About'
|
||||
|
||||
describe('About', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<About />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
68
client/src/routes/Details/AssetDetails.test.tsx
Normal file
68
client/src/routes/Details/AssetDetails.test.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import { DDO, MetaData } from '@oceanprotocol/squid'
|
||||
import { BrowserRouter as Router } from 'react-router-dom'
|
||||
import AssetDetails, { datafilesLine } from './AssetDetails'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
describe('AssetDetails', () => {
|
||||
it('renders loading without crashing', () => {
|
||||
const { container } = render(
|
||||
<AssetDetails
|
||||
metadata={({ base: { name: '' } } as any) as MetaData}
|
||||
ddo={({} as any) as DDO}
|
||||
/>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders with data', () => {
|
||||
const { container } = render(
|
||||
<Router>
|
||||
<AssetDetails
|
||||
metadata={
|
||||
({
|
||||
base: {
|
||||
name: 'Hello',
|
||||
description: 'Description',
|
||||
categories: ['Category'],
|
||||
files: [{ index: 0 }]
|
||||
}
|
||||
} as any) as MetaData
|
||||
}
|
||||
ddo={({} as any) as DDO}
|
||||
/>
|
||||
</Router>
|
||||
)
|
||||
expect(container.querySelector('.description')).toHaveTextContent(
|
||||
'Description'
|
||||
)
|
||||
expect(container.firstChild).toHaveTextContent('Category')
|
||||
})
|
||||
|
||||
it('datafilesLine renders correctly for one file', () => {
|
||||
const files = [
|
||||
{
|
||||
index: 0,
|
||||
url: 'https://hello.com'
|
||||
}
|
||||
]
|
||||
const { container } = render(datafilesLine(files))
|
||||
expect(container.firstChild).toHaveTextContent('1 data file')
|
||||
})
|
||||
|
||||
it('datafilesLine renders correctly for multiple files', () => {
|
||||
const files = [
|
||||
{
|
||||
index: 0,
|
||||
url: 'https://hello.com'
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
url: 'https://hello2.com'
|
||||
}
|
||||
]
|
||||
const { container } = render(datafilesLine(files))
|
||||
expect(container.firstChild).toHaveTextContent('2 data files')
|
||||
})
|
||||
})
|
@ -1,23 +1,24 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import Moment from 'react-moment'
|
||||
import { DDO, MetaData, File } from '@oceanprotocol/squid'
|
||||
import Markdown from '../../components/atoms/Markdown'
|
||||
import styles from './AssetDetails.module.scss'
|
||||
import AssetFilesDetails from './AssetFilesDetails'
|
||||
|
||||
interface AssetDetailsProps {
|
||||
metadata: any
|
||||
ddo: any
|
||||
metadata: MetaData
|
||||
ddo: DDO
|
||||
}
|
||||
|
||||
export function datafilesLine(files: File[]) {
|
||||
if (files.length === 1) {
|
||||
return <span>{files.length} data file</span>
|
||||
}
|
||||
return <span>{files.length} data files</span>
|
||||
}
|
||||
|
||||
export default class AssetDetails extends PureComponent<AssetDetailsProps> {
|
||||
private datafilesLine = (files: any) => {
|
||||
if (files.length === 1) {
|
||||
return <span>{files.length} data file</span>
|
||||
}
|
||||
return <span>{files.length} data files</span>
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { metadata, ddo } = this.props
|
||||
const { base } = metadata
|
||||
@ -51,14 +52,16 @@ export default class AssetDetails extends PureComponent<AssetDetailsProps> {
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{base.files && this.datafilesLine(base.files)}
|
||||
{base.files && datafilesLine(base.files)}
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<Markdown
|
||||
text={base.description}
|
||||
className={styles.description}
|
||||
/>
|
||||
{base.description && (
|
||||
<Markdown
|
||||
text={base.description}
|
||||
className={styles.description}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ul className={styles.meta}>
|
||||
<li>
|
||||
|
77
client/src/routes/Details/AssetFile.test.tsx
Normal file
77
client/src/routes/Details/AssetFile.test.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import React from 'react'
|
||||
import { render, fireEvent } from 'react-testing-library'
|
||||
import { DDO } from '@oceanprotocol/squid'
|
||||
import { StateMock } from '@react-mock/state'
|
||||
import { User } from '../../context'
|
||||
import AssetFile from './AssetFile'
|
||||
|
||||
const file = {
|
||||
index: 0,
|
||||
url: 'https://hello.com',
|
||||
contentType: 'zip',
|
||||
contentLength: 100
|
||||
}
|
||||
|
||||
const ddo = ({ id: 'xxx' } as any) as DDO
|
||||
|
||||
const contextConnectedMock = {
|
||||
isLogged: true,
|
||||
isLoading: false,
|
||||
isWeb3: true,
|
||||
isNile: true,
|
||||
account: '',
|
||||
web3: {},
|
||||
ocean: {},
|
||||
balance: { eth: 0, ocn: 0 },
|
||||
network: '',
|
||||
requestFromFaucet: () => {},
|
||||
unlockAccounts: () => {},
|
||||
message: ''
|
||||
}
|
||||
|
||||
describe('AssetFile', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<AssetFile file={file} ddo={ddo} />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('button to be disabled when not connected', () => {
|
||||
const { container } = render(<AssetFile file={file} ddo={ddo} />)
|
||||
expect(container.querySelector('button')).toHaveAttribute('disabled')
|
||||
})
|
||||
|
||||
it('button to be enabled when connected', async () => {
|
||||
const { getByText } = render(
|
||||
<User.Provider value={contextConnectedMock}>
|
||||
<AssetFile file={file} ddo={ddo} />
|
||||
</User.Provider>
|
||||
)
|
||||
const button = getByText('Get file')
|
||||
expect(button).not.toHaveAttribute('disabled')
|
||||
|
||||
fireEvent.click(button)
|
||||
})
|
||||
|
||||
it('renders loading state', async () => {
|
||||
const { container } = render(
|
||||
<StateMock state={{ isLoading: true }}>
|
||||
<AssetFile file={file} ddo={ddo} />
|
||||
</StateMock>
|
||||
)
|
||||
expect(container.querySelector('.spinner')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders error', async () => {
|
||||
const { container } = render(
|
||||
<StateMock state={{ error: 'Hello Error' }}>
|
||||
<AssetFile file={file} ddo={ddo} />
|
||||
</StateMock>
|
||||
)
|
||||
expect(container.querySelector('.error')).toBeInTheDocument()
|
||||
expect(container.querySelector('.error')).toHaveTextContent(
|
||||
'Hello Error'
|
||||
)
|
||||
})
|
||||
})
|
@ -1,5 +1,5 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import { Logger } from '@oceanprotocol/squid'
|
||||
import { Logger, DDO, File } from '@oceanprotocol/squid'
|
||||
import filesize from 'filesize'
|
||||
import Button from '../../components/atoms/Button'
|
||||
import Spinner from '../../components/atoms/Spinner'
|
||||
@ -8,8 +8,8 @@ import styles from './AssetFile.module.scss'
|
||||
import ReactGA from 'react-ga'
|
||||
|
||||
interface AssetFileProps {
|
||||
file: any
|
||||
ddo: any
|
||||
file: File
|
||||
ddo: DDO
|
||||
}
|
||||
|
||||
interface AssetFileState {
|
||||
@ -30,7 +30,7 @@ export default class AssetFile extends PureComponent<
|
||||
|
||||
private resetState = () => this.setState({ isLoading: true, error: '' })
|
||||
|
||||
private purchaseAsset = async (ddo: any, index: number) => {
|
||||
private purchaseAsset = async (ddo: DDO, index: number) => {
|
||||
this.resetState()
|
||||
|
||||
ReactGA.event({
|
||||
@ -77,6 +77,7 @@ export default class AssetFile extends PureComponent<
|
||||
const { ddo, file } = this.props
|
||||
const { isLoading, message, error } = this.state
|
||||
const { isLogged, isNile } = this.context
|
||||
const { index } = file
|
||||
|
||||
return (
|
||||
<div className={styles.fileWrap}>
|
||||
@ -97,7 +98,7 @@ export default class AssetFile extends PureComponent<
|
||||
<Button
|
||||
primary
|
||||
className={styles.buttonMain}
|
||||
onClick={() => this.purchaseAsset(ddo, file.index)}
|
||||
onClick={() => index && this.purchaseAsset(ddo, index)}
|
||||
disabled={!isLogged || !isNile}
|
||||
>
|
||||
Get file
|
||||
|
43
client/src/routes/Details/AssetFilesDetails.test.tsx
Normal file
43
client/src/routes/Details/AssetFilesDetails.test.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import { DDO } from '@oceanprotocol/squid'
|
||||
import AssetFilesDetails from './AssetFilesDetails'
|
||||
import { User } from '../../context'
|
||||
import { userMockConnected } from '../../../__mocks__/user-mock'
|
||||
|
||||
describe('AssetFilesDetails', () => {
|
||||
it('renders without crashing', () => {
|
||||
const files = [
|
||||
{
|
||||
index: 0,
|
||||
url: 'https://hello.com'
|
||||
}
|
||||
]
|
||||
|
||||
const { container } = render(
|
||||
<AssetFilesDetails files={files} ddo={({} as any) as DDO} />
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders nothing when no files', () => {
|
||||
const { container } = render(
|
||||
<AssetFilesDetails files={[]} ddo={({} as any) as DDO} />
|
||||
)
|
||||
expect(container.firstChild).toHaveTextContent('No files attached.')
|
||||
})
|
||||
|
||||
it('hides Web3message when all connected', () => {
|
||||
const { container } = render(
|
||||
<User.Provider value={userMockConnected}>
|
||||
<AssetFilesDetails
|
||||
files={[{ index: 0, url: '' }]}
|
||||
ddo={({} as any) as DDO}
|
||||
/>
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.querySelector('.status')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -1,31 +1,32 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import { DDO, File } from '@oceanprotocol/squid'
|
||||
import AssetFile from './AssetFile'
|
||||
import { User } from '../../context'
|
||||
import Web3message from '../../components/organisms/Web3message'
|
||||
import styles from './AssetFilesDetails.module.scss'
|
||||
|
||||
export default class AssetFilesDetails extends PureComponent<{
|
||||
files: any[]
|
||||
ddo: any
|
||||
files: File[]
|
||||
ddo: DDO
|
||||
}> {
|
||||
public render() {
|
||||
const { files, ddo } = this.props
|
||||
|
||||
return files ? (
|
||||
return files.length ? (
|
||||
<>
|
||||
<div className={styles.files}>
|
||||
{files.map(file => (
|
||||
<AssetFile key={file.index} ddo={ddo} file={file} />
|
||||
))}
|
||||
</div>
|
||||
<User.Consumer>
|
||||
{states =>
|
||||
(!states.isNile || !states.isLogged) && <Web3message />
|
||||
}
|
||||
</User.Consumer>
|
||||
{(!this.context.isNile || !this.context.isLogged) && (
|
||||
<Web3message />
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div>No files attached.</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AssetFilesDetails.contextType = User
|
||||
|
21
client/src/routes/Details/index.test.tsx
Normal file
21
client/src/routes/Details/index.test.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Details from './index'
|
||||
|
||||
describe('Details', () => {
|
||||
it('renders loading state by default', () => {
|
||||
const { container } = render(
|
||||
<Details
|
||||
location={{
|
||||
search: '',
|
||||
pathname: '/',
|
||||
state: '',
|
||||
hash: ''
|
||||
}}
|
||||
match={{ params: { did: '' } }}
|
||||
/>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
expect(container.querySelector('.loader')).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react'
|
||||
import { DDO, MetaData, Logger } from '@oceanprotocol/squid'
|
||||
import Route from '../../components/templates/Route'
|
||||
import Spinner from '../../components/atoms/Spinner'
|
||||
import { User } from '../../context'
|
||||
@ -7,23 +8,37 @@ import stylesApp from '../../App.module.scss'
|
||||
|
||||
interface DetailsProps {
|
||||
location: Location
|
||||
match: any
|
||||
match: {
|
||||
params: {
|
||||
did: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface DetailsState {
|
||||
ddo: any
|
||||
metadata: { base: { name: string } }
|
||||
ddo: DDO
|
||||
metadata: MetaData
|
||||
}
|
||||
|
||||
export default class Details extends Component<DetailsProps, DetailsState> {
|
||||
public state = { ddo: {}, metadata: { base: { name: '' } } }
|
||||
public state = {
|
||||
ddo: ({} as any) as DDO,
|
||||
metadata: ({ base: { name: '' } } as any) as MetaData
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const ddo = await this.context.ocean.assets.resolve(
|
||||
this.props.match.params.did
|
||||
)
|
||||
const { metadata } = ddo.findServiceByType('Metadata')
|
||||
this.setState({ ddo, metadata: { base: metadata.base } })
|
||||
this.getData()
|
||||
}
|
||||
|
||||
private async getData() {
|
||||
try {
|
||||
const { ocean } = this.context
|
||||
const ddo = await ocean.assets.resolve(this.props.match.params.did)
|
||||
const { metadata } = ddo.findServiceByType('Metadata')
|
||||
this.setState({ ddo, metadata })
|
||||
} catch (error) {
|
||||
Logger.error(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
43
client/src/routes/Faucet.test.tsx
Normal file
43
client/src/routes/Faucet.test.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import React from 'react'
|
||||
import { render, fireEvent } from 'react-testing-library'
|
||||
import Faucet from './Faucet'
|
||||
import { User } from '../context'
|
||||
import { userMockConnected } from '../../__mocks__/user-mock'
|
||||
|
||||
const setup = () => {
|
||||
const utils = render(
|
||||
<User.Provider value={userMockConnected}>
|
||||
<Faucet />
|
||||
</User.Provider>
|
||||
)
|
||||
const button = utils.getByText('Request Ether')
|
||||
const { container } = utils
|
||||
return {
|
||||
button,
|
||||
container,
|
||||
...utils
|
||||
}
|
||||
}
|
||||
|
||||
describe('Faucet', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Faucet />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('shows actions when connected', () => {
|
||||
const { button } = setup()
|
||||
|
||||
expect(button).toBeInTheDocument()
|
||||
expect(button).not.toHaveAttribute('disabled')
|
||||
})
|
||||
|
||||
it('fires requestFromFaucet', () => {
|
||||
const { button, getByText } = setup()
|
||||
|
||||
fireEvent.click(button)
|
||||
expect(userMockConnected.requestFromFaucet).toHaveBeenCalledTimes(1)
|
||||
// check for spinner
|
||||
expect(getByText('Getting Ether...')).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -46,7 +46,7 @@ export default class Faucet extends PureComponent<{}, FaucetState> {
|
||||
trxHash
|
||||
})
|
||||
} catch (error) {
|
||||
this.setState({ isLoading: false, error })
|
||||
this.setState({ isLoading: false, error: error.message })
|
||||
}
|
||||
}
|
||||
|
||||
|
38
client/src/routes/History.test.tsx
Normal file
38
client/src/routes/History.test.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import { User } from '../context'
|
||||
import History from './History'
|
||||
|
||||
describe('History', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<History />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('outputs Web3 message when no Web3 detected', () => {
|
||||
const context = {
|
||||
isLogged: false,
|
||||
isLoading: false,
|
||||
isWeb3: false,
|
||||
isNile: false,
|
||||
account: '',
|
||||
web3: {},
|
||||
ocean: {},
|
||||
balance: { eth: 0, ocn: 0 },
|
||||
network: '',
|
||||
requestFromFaucet: () => {},
|
||||
unlockAccounts: () => {},
|
||||
message: ''
|
||||
}
|
||||
|
||||
const { container } = render(
|
||||
<User.Provider value={context}>
|
||||
<History />
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.querySelector('.message')).toBeInTheDocument()
|
||||
expect(container.querySelector('.message')).toHaveTextContent(
|
||||
'Not a Web3 Browser.'
|
||||
)
|
||||
})
|
||||
})
|
10
client/src/routes/Home.test.tsx
Normal file
10
client/src/routes/Home.test.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Home from './Home'
|
||||
|
||||
describe('Home', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Home history={''} />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -7,9 +7,10 @@ import AssetsUser from '../components/organisms/AssetsUser'
|
||||
import styles from './Home.module.scss'
|
||||
|
||||
import meta from '../data/meta.json'
|
||||
import { History } from 'history'
|
||||
|
||||
interface HomeProps {
|
||||
history: any
|
||||
history: History
|
||||
}
|
||||
|
||||
interface HomeState {
|
||||
|
10
client/src/routes/NotFound.test.tsx
Normal file
10
client/src/routes/NotFound.test.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import NotFound from './NotFound'
|
||||
|
||||
describe('NotFound', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<NotFound />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
39
client/src/routes/Publish/Files/Item.test.tsx
Normal file
39
client/src/routes/Publish/Files/Item.test.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Item from './Item'
|
||||
|
||||
describe('Item', () => {
|
||||
it('renders without crashing', () => {
|
||||
const item = {
|
||||
url: 'https://hello.com/hello.zip',
|
||||
found: true,
|
||||
contentType: 'application/zip',
|
||||
contentLength: 10
|
||||
}
|
||||
const { container } = render(
|
||||
<Item item={item} removeItem={() => null} />
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('returns unknown strings', () => {
|
||||
const item = {
|
||||
url: 'https://hello.com/hello.zip',
|
||||
found: false,
|
||||
contentType: '',
|
||||
contentLength: 10
|
||||
}
|
||||
const { container } = render(
|
||||
<Item item={item} removeItem={() => null} />
|
||||
)
|
||||
expect(container.querySelector('.details')).toHaveTextContent(
|
||||
'unknown type'
|
||||
)
|
||||
expect(container.querySelector('.details')).toHaveTextContent(
|
||||
'unknown size'
|
||||
)
|
||||
expect(container.querySelector('.details')).toHaveTextContent(
|
||||
'not confirmed'
|
||||
)
|
||||
})
|
||||
})
|
63
client/src/routes/Publish/Files/ItemForm.test.tsx
Normal file
63
client/src/routes/Publish/Files/ItemForm.test.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import React from 'react'
|
||||
import { render, fireEvent } from 'react-testing-library'
|
||||
import ItemForm from './ItemForm'
|
||||
|
||||
const addItem = jest.fn()
|
||||
|
||||
const setup = () => {
|
||||
const utils = render(<ItemForm placeholder={'Hello'} addItem={addItem} />)
|
||||
const input = utils.getByPlaceholderText('Hello')
|
||||
const button = utils.getByText('Add File')
|
||||
const { container } = utils
|
||||
return {
|
||||
input,
|
||||
button,
|
||||
container,
|
||||
...utils
|
||||
}
|
||||
}
|
||||
|
||||
describe('ItemForm', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = setup()
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('fires addItem', async () => {
|
||||
const { input, button } = setup()
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'https://hello.com' }
|
||||
})
|
||||
fireEvent.click(button)
|
||||
expect(addItem).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does not fire addItem when no url present', () => {
|
||||
const { input, button, container } = setup()
|
||||
|
||||
// empty url
|
||||
fireEvent.change(input, {
|
||||
target: { value: '' }
|
||||
})
|
||||
fireEvent.click(button)
|
||||
expect(container.querySelector('.error')).toHaveTextContent(
|
||||
'Please fill in all required fields.'
|
||||
)
|
||||
|
||||
// invalid url
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'blabla' }
|
||||
})
|
||||
fireEvent.click(button)
|
||||
expect(container.querySelector('.error')).toHaveTextContent(
|
||||
'Please enter a valid URL.'
|
||||
)
|
||||
|
||||
// clear out errors
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'blablabla' }
|
||||
})
|
||||
expect(container.querySelector('.error')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -25,7 +25,7 @@ export default class ItemForm extends PureComponent<
|
||||
noUrl: false
|
||||
}
|
||||
|
||||
public handleSubmit = (e: Event) => {
|
||||
private handleSubmit = (e: Event) => {
|
||||
e.preventDefault()
|
||||
|
||||
const { url } = this.state
|
||||
@ -45,14 +45,14 @@ export default class ItemForm extends PureComponent<
|
||||
this.props.addItem(url)
|
||||
}
|
||||
|
||||
public onChangeUrl = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
private onChangeUrl = (e: React.FormEvent<HTMLInputElement>) => {
|
||||
this.setState({ url: e.currentTarget.value })
|
||||
this.clearErrors()
|
||||
}
|
||||
|
||||
public clearErrors() {
|
||||
private clearErrors() {
|
||||
if (this.state.hasError) this.setState({ hasError: false })
|
||||
if (this.state.noUrl) this.setState({ noUrl: true })
|
||||
if (this.state.noUrl) this.setState({ noUrl: false })
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
90
client/src/routes/Publish/Files/index.test.tsx
Normal file
90
client/src/routes/Publish/Files/index.test.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import React from 'react'
|
||||
import { render, fireEvent, waitForElement } from 'react-testing-library'
|
||||
import Files, { getFileCompression } from '.'
|
||||
|
||||
const onChange = jest.fn()
|
||||
|
||||
const files = [
|
||||
{
|
||||
found: true,
|
||||
url: 'https://hello.com',
|
||||
checksum: 'cccccc',
|
||||
checksumType: 'MD5',
|
||||
contentLength: 100,
|
||||
contentType: 'application/zip',
|
||||
resourceId: 'xxx',
|
||||
encoding: 'UTF-8',
|
||||
compression: 'zip'
|
||||
}
|
||||
]
|
||||
|
||||
const setup = () => {
|
||||
const utils = render(
|
||||
<Files
|
||||
files={files}
|
||||
placeholder={'Hello'}
|
||||
name={'Hello'}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)
|
||||
const { container } = utils
|
||||
return { container, ...utils }
|
||||
}
|
||||
|
||||
describe('Files', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = setup()
|
||||
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
expect(container.querySelector('.itemForm')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('new file form can be opened and closed', async () => {
|
||||
const { container, getByText } = setup()
|
||||
|
||||
// open
|
||||
fireEvent.click(getByText('+ Add a file'))
|
||||
await waitForElement(() => getByText('- Cancel'))
|
||||
expect(container.querySelector('.itemForm')).toBeInTheDocument()
|
||||
|
||||
// close
|
||||
fireEvent.click(getByText('- Cancel'))
|
||||
await waitForElement(() => getByText('+ Add a file'))
|
||||
expect(container.querySelector('.grow-exit')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('item can be removed', async () => {
|
||||
const { getByTitle } = setup()
|
||||
|
||||
fireEvent.click(getByTitle('Remove item'))
|
||||
expect(files.length).toBe(0)
|
||||
})
|
||||
|
||||
it('item can be added', async () => {
|
||||
const { getByText, getByPlaceholderText } = setup()
|
||||
|
||||
fireEvent.click(getByText('+ Add a file'))
|
||||
await waitForElement(() => getByText('- Cancel'))
|
||||
fireEvent.change(getByPlaceholderText('Hello'), {
|
||||
target: { value: 'https://hello.com' }
|
||||
})
|
||||
fireEvent.click(getByText('Add File'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('getFileCompression', () => {
|
||||
it('outputs known compression', async () => {
|
||||
const compression = await getFileCompression('application/zip')
|
||||
expect(compression).toBe('zip')
|
||||
})
|
||||
|
||||
it('outputs known x- compression', async () => {
|
||||
const compression = await getFileCompression('application/x-gtar')
|
||||
expect(compression).toBe('gtar')
|
||||
})
|
||||
|
||||
it('outputs unknown compression', async () => {
|
||||
const compression = await getFileCompression('blabla')
|
||||
expect(compression).toBe('none')
|
||||
})
|
||||
})
|
@ -38,7 +38,7 @@ interface FilesStates {
|
||||
isFormShown: boolean
|
||||
}
|
||||
|
||||
const getFileCompression = async (contentType: string) => {
|
||||
export const getFileCompression = async (contentType: string) => {
|
||||
// TODO: add all the possible archive & compression MIME types
|
||||
if (
|
||||
contentType === 'application/zip' ||
|
||||
@ -69,14 +69,21 @@ export default class Files extends PureComponent<FilesProps, FilesStates> {
|
||||
isFormShown: false
|
||||
}
|
||||
|
||||
public toggleForm = (e: Event) => {
|
||||
private toggleForm = (e: Event) => {
|
||||
e.preventDefault()
|
||||
|
||||
this.setState({ isFormShown: !this.state.isFormShown })
|
||||
}
|
||||
|
||||
public addItem = async (value: string) => {
|
||||
let res: any
|
||||
private addItem = async (value: string) => {
|
||||
let res: {
|
||||
result: {
|
||||
contentLength: number
|
||||
contentType: string
|
||||
found: boolean
|
||||
}
|
||||
}
|
||||
|
||||
let file: File = {
|
||||
url: value,
|
||||
found: false,
|
||||
@ -104,6 +111,7 @@ export default class Files extends PureComponent<FilesProps, FilesStates> {
|
||||
} catch (error) {
|
||||
// error
|
||||
}
|
||||
|
||||
this.props.files.push(file)
|
||||
const event = {
|
||||
currentTarget: {
|
||||
@ -115,7 +123,7 @@ export default class Files extends PureComponent<FilesProps, FilesStates> {
|
||||
this.setState({ isFormShown: !this.state.isFormShown })
|
||||
}
|
||||
|
||||
public removeItem = (index: number) => {
|
||||
private removeItem = (index: number) => {
|
||||
this.props.files.splice(index, 1)
|
||||
const event = {
|
||||
currentTarget: {
|
||||
|
19
client/src/routes/Publish/Progress.test.tsx
Normal file
19
client/src/routes/Publish/Progress.test.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Progress from './Progress'
|
||||
|
||||
describe('Progress', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(
|
||||
<Progress currentStep={1} steps={[{ title: '' }]} />
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders completed state', () => {
|
||||
const { container } = render(
|
||||
<Progress currentStep={2} steps={[{ title: '' }]} />
|
||||
)
|
||||
expect(container.querySelector('li')).toHaveClass('completed')
|
||||
})
|
||||
})
|
46
client/src/routes/Publish/Step.test.tsx
Normal file
46
client/src/routes/Publish/Step.test.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Step from './Step'
|
||||
|
||||
const stateMock = {
|
||||
validationStatus: {
|
||||
1: { allFieldsValid: true },
|
||||
2: { allFieldsValid: true },
|
||||
3: { allFieldsValid: true }
|
||||
}
|
||||
}
|
||||
|
||||
const propsMock = {
|
||||
inputChange: () => null,
|
||||
inputToArrayChange: () => null,
|
||||
state: stateMock,
|
||||
title: 'Hello',
|
||||
description: 'description',
|
||||
next: () => null,
|
||||
prev: () => null,
|
||||
tryAgain: () => null,
|
||||
toStart: () => null
|
||||
}
|
||||
|
||||
describe('Step', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(
|
||||
<Step currentStep={1} index={0} totalSteps={3} {...propsMock} />
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders previous button one page bigger than 1', () => {
|
||||
const { queryByText } = render(
|
||||
<Step currentStep={2} index={1} totalSteps={3} {...propsMock} />
|
||||
)
|
||||
expect(queryByText('← Previous')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render next button when on last step', () => {
|
||||
const { queryByText } = render(
|
||||
<Step currentStep={3} index={2} totalSteps={3} {...propsMock} />
|
||||
)
|
||||
expect(queryByText('Next →')).toBeNull()
|
||||
})
|
||||
})
|
76
client/src/routes/Publish/StepRegisterContent.test.tsx
Normal file
76
client/src/routes/Publish/StepRegisterContent.test.tsx
Normal file
@ -0,0 +1,76 @@
|
||||
import React from 'react'
|
||||
import { render, fireEvent } from 'react-testing-library'
|
||||
import { BrowserRouter as Router } from 'react-router-dom'
|
||||
import StepRegisterContent from './StepRegisterContent'
|
||||
|
||||
const stateMock = {
|
||||
publishedDid: '',
|
||||
publishingError: '',
|
||||
isPublishing: false,
|
||||
isPublished: false
|
||||
}
|
||||
|
||||
const propsMock = {
|
||||
tryAgain: jest.fn(),
|
||||
toStart: jest.fn(),
|
||||
content: 'Hello'
|
||||
}
|
||||
|
||||
describe('StepRegisterContent', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(
|
||||
<Router>
|
||||
<StepRegisterContent state={stateMock} {...propsMock} />
|
||||
</Router>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders publishing state', () => {
|
||||
const { container } = render(
|
||||
<Router>
|
||||
<StepRegisterContent
|
||||
state={{ ...stateMock, isPublishing: true }}
|
||||
{...propsMock}
|
||||
/>
|
||||
</Router>
|
||||
)
|
||||
expect(container.querySelector('.spinnerMessage')).toHaveTextContent(
|
||||
'Please sign with your crypto wallet'
|
||||
)
|
||||
})
|
||||
|
||||
it('renders published state', () => {
|
||||
const { container, getByText } = render(
|
||||
<Router>
|
||||
<StepRegisterContent
|
||||
state={{ ...stateMock, isPublished: true }}
|
||||
{...propsMock}
|
||||
/>
|
||||
</Router>
|
||||
)
|
||||
expect(container.querySelector('.success')).toHaveTextContent(
|
||||
'Your asset is published!'
|
||||
)
|
||||
|
||||
fireEvent.click(getByText('Publish another asset'))
|
||||
expect(propsMock.toStart).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('renders error state', () => {
|
||||
const { container, getByText } = render(
|
||||
<Router>
|
||||
<StepRegisterContent
|
||||
state={{ ...stateMock, publishingError: 'Error!' }}
|
||||
{...propsMock}
|
||||
/>
|
||||
</Router>
|
||||
)
|
||||
expect(
|
||||
container.querySelector('.message:last-child')
|
||||
).toHaveTextContent('Something went wrong')
|
||||
|
||||
fireEvent.click(getByText('try again'))
|
||||
expect(propsMock.tryAgain).toHaveBeenCalled()
|
||||
})
|
||||
})
|
@ -7,7 +7,12 @@ import styles from './StepRegisterContent.module.scss'
|
||||
interface StepRegisterContentProps {
|
||||
tryAgain(): void
|
||||
toStart(): void
|
||||
state: any
|
||||
state: {
|
||||
publishedDid: string
|
||||
isPublishing: boolean
|
||||
publishingError: string
|
||||
isPublished: boolean
|
||||
}
|
||||
content?: string
|
||||
}
|
||||
|
||||
|
11
client/src/routes/Publish/index.test.tsx
Normal file
11
client/src/routes/Publish/index.test.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Publish from '.'
|
||||
|
||||
describe('Progress', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container, getByText } = render(<Publish />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
expect(getByText('Next →')).toHaveAttribute('disabled')
|
||||
})
|
||||
})
|
51
client/src/routes/Search.test.tsx
Normal file
51
client/src/routes/Search.test.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Search from './Search'
|
||||
import { User } from '../context'
|
||||
import { createMemoryHistory } from 'history'
|
||||
|
||||
describe('Search', () => {
|
||||
it('renders without crashing', () => {
|
||||
const history = createMemoryHistory()
|
||||
|
||||
const { container } = render(
|
||||
<User.Provider
|
||||
value={{
|
||||
isLogged: false,
|
||||
isLoading: false,
|
||||
isWeb3: false,
|
||||
isNile: false,
|
||||
account: '',
|
||||
web3: {},
|
||||
ocean: {
|
||||
aquarius: {
|
||||
queryMetadata: () => {
|
||||
return {
|
||||
results: [],
|
||||
totalResults: 1,
|
||||
totalPages: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
balance: { eth: 0, ocn: 0 },
|
||||
network: '',
|
||||
requestFromFaucet: () => {},
|
||||
unlockAccounts: () => {},
|
||||
message: ''
|
||||
}}
|
||||
>
|
||||
<Search
|
||||
location={{
|
||||
search: '?text=Hello&page=1',
|
||||
pathname: '/search',
|
||||
state: '',
|
||||
hash: ''
|
||||
}}
|
||||
history={history}
|
||||
/>
|
||||
</User.Provider>
|
||||
)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
@ -1,5 +1,6 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import queryString from 'query-string'
|
||||
import { History, Location } from 'history'
|
||||
import { Logger } from '@oceanprotocol/squid'
|
||||
import Spinner from '../components/atoms/Spinner'
|
||||
import Route from '../components/templates/Route'
|
||||
@ -10,7 +11,7 @@ import styles from './Search.module.scss'
|
||||
|
||||
interface SearchProps {
|
||||
location: Location
|
||||
history: any
|
||||
history: History
|
||||
}
|
||||
|
||||
interface SearchState {
|
||||
@ -53,6 +54,8 @@ export default class Search extends PureComponent<SearchProps, SearchState> {
|
||||
}
|
||||
|
||||
private searchAssets = async () => {
|
||||
const { ocean } = this.context
|
||||
|
||||
const searchQuery = {
|
||||
offset: this.state.offset,
|
||||
page: this.state.currentPage,
|
||||
@ -65,16 +68,18 @@ export default class Search extends PureComponent<SearchProps, SearchState> {
|
||||
}
|
||||
}
|
||||
|
||||
const search = await this.context.ocean.aquarius.queryMetadata(
|
||||
searchQuery
|
||||
)
|
||||
this.setState({
|
||||
results: search.results,
|
||||
totalResults: search.totalResults,
|
||||
totalPages: search.totalPages,
|
||||
isLoading: false
|
||||
})
|
||||
Logger.log(`Loaded ${this.state.results.length} assets`)
|
||||
try {
|
||||
const search = await ocean.aquarius.queryMetadata(searchQuery)
|
||||
this.setState({
|
||||
results: search.results,
|
||||
totalResults: search.totalResults,
|
||||
totalPages: search.totalPages,
|
||||
isLoading: false
|
||||
})
|
||||
} catch (error) {
|
||||
Logger.error(error)
|
||||
this.setState({ isLoading: false })
|
||||
}
|
||||
}
|
||||
|
||||
private handlePageClick = async (data: { selected: number }) => {
|
||||
|
10
client/src/routes/Styleguide.test.tsx
Normal file
10
client/src/routes/Styleguide.test.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-testing-library'
|
||||
import Styleguide from './Styleguide'
|
||||
|
||||
describe('Styleguide', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = render(<Styleguide />)
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
})
|
1688
package-lock.json
generated
1688
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -31,16 +31,16 @@
|
||||
"concurrently": "^4.1.0",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-oceanprotocol": "^1.3.0",
|
||||
"eslint-config-prettier": "^4.1.0",
|
||||
"eslint-config-prettier": "^4.2.0",
|
||||
"eslint-plugin-prettier": "^3.0.1",
|
||||
"prettier": "^1.16.4",
|
||||
"prettier": "^1.17.0",
|
||||
"prettier-stylelint": "^0.4.2",
|
||||
"release-it": "^10.4.3",
|
||||
"release-it": "^11.0.2",
|
||||
"stylelint": "^10.0.1",
|
||||
"stylelint-config-bigchaindb": "^1.2.1",
|
||||
"stylelint-config-css-modules": "^1.3.0",
|
||||
"stylelint-config-standard": "^18.2.0",
|
||||
"typescript": "^3.4.4"
|
||||
"stylelint-config-bigchaindb": "^1.2.2",
|
||||
"stylelint-config-css-modules": "^1.4.0",
|
||||
"stylelint-config-standard": "^18.3.0",
|
||||
"typescript": "^3.4.5"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
1106
server/package-lock.json
generated
1106
server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,22 +14,17 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"body-parser": "^1.18.3",
|
||||
"color-js": "^1.0.5",
|
||||
"compression": "^1.7.4",
|
||||
"debug": "^4.1.1",
|
||||
"express": "^4.16.4",
|
||||
"express-validator": "^5.3.1",
|
||||
"lusca": "^1.6.1",
|
||||
"morgan": "^1.9.1",
|
||||
"multer": "^1.4.1",
|
||||
"request": "^2.88.0",
|
||||
"uuid": "^3.3.2"
|
||||
"request": "^2.88.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/body-parser": "^1.17.0",
|
||||
"@types/compression": "0.0.36",
|
||||
"@types/debug": "^4.1.4",
|
||||
"@types/dotenv": "^6.1.1",
|
||||
"@types/express": "^4.16.1",
|
||||
"@types/jasmine": "^3.3.12",
|
||||
"@types/jest": "^24.0.11",
|
||||
@ -42,7 +37,7 @@
|
||||
"supertest": "^4.0.2",
|
||||
"ts-jest": "^24.0.2",
|
||||
"ts-node": "^8.1.0",
|
||||
"typescript": "^3.4.3"
|
||||
"typescript": "^3.4.5"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Router, Request, Response, NextFunction } from 'express'
|
||||
import { Router, Request, Response } from 'express'
|
||||
import request from 'request'
|
||||
|
||||
export class UrlCheckRouter {
|
||||
@ -11,7 +11,7 @@ export class UrlCheckRouter {
|
||||
this.router = Router()
|
||||
}
|
||||
|
||||
public checkUrl(req: Request, res: Response, next: NextFunction) {
|
||||
public checkUrl(req: Request, res: Response) {
|
||||
if (!req.body.url) {
|
||||
return res.send({ status: 'error', message: 'missing url' })
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ app.use(morgan('dev'))
|
||||
app.use(bodyParser.json())
|
||||
app.use(bodyParser.urlencoded({ extended: false }))
|
||||
app.use(compression())
|
||||
|
||||
// routes
|
||||
app.use('/api/v1/urlcheck', UrlCheckRouter)
|
||||
|
||||
|
@ -7,9 +7,21 @@ afterAll(done => {
|
||||
})
|
||||
|
||||
describe('POST /api/v1/urlcheck', () => {
|
||||
it('responds with json', function(done) {
|
||||
request(server)
|
||||
.post('/api/v1/urlcheck')
|
||||
.expect(200, done)
|
||||
it('responds with json', async () => {
|
||||
const response = await request(server).post('/api/v1/urlcheck')
|
||||
expect(response.statusCode).toBe(200)
|
||||
})
|
||||
|
||||
it('responds with error message when url is missing', async () => {
|
||||
const response = await request(server).post('/api/v1/urlcheck')
|
||||
const text = await JSON.parse(response.text)
|
||||
expect(text.message).toBe('missing url')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Errors', () => {
|
||||
it('responds with 404 on unknown path', async () => {
|
||||
const response = await request(server).post('/whatever')
|
||||
expect(response.statusCode).toBe(404)
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user