diff --git a/package-lock.json b/package-lock.json
index c70bed0..a994ab3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7914,6 +7914,15 @@
"@jest/types": "^24.9.0"
}
},
+ "jest-mock-axios": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/jest-mock-axios/-/jest-mock-axios-3.1.1.tgz",
+ "integrity": "sha512-3GCDj4aMk9+tRbU4wKZCHrewMdmyI/SuNF/2/ezzxRNAct+herwvy44Seeq7iLTAeFBiuEcL7gVfyf4TV+hUwg==",
+ "dev": true,
+ "requires": {
+ "synchronous-promise": "^2.0.10"
+ }
+ },
"jest-pnp-resolver": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz",
@@ -13099,6 +13108,12 @@
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
},
+ "synchronous-promise": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.10.tgz",
+ "integrity": "sha512-6PC+JRGmNjiG3kJ56ZMNWDPL8hjyghF5cMXIFOKg+NiwwEZZIvxTWd0pinWKyD227odg9ygF8xVhhz7gb8Uq7A==",
+ "dev": true
+ },
"table": {
"version": "5.4.6",
"resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
diff --git a/package.json b/package.json
index fdc8417..37eb694 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
"test": "npm run lint && react-scripts test --coverage --watchAll=false",
"test:watch": "react-scripts test --coverage",
"lint": "eslint --ignore-path .gitignore --ext .js .",
- "format": "prettier ./src/**/*.{js,json} --write"
+ "format": "prettier ./src/**/*.{js,scss,json} --write"
},
"dependencies": {
"@ethereum-navigator/atlas": "^0.4.0",
@@ -23,9 +23,11 @@
"devDependencies": {
"@testing-library/jest-dom": "^4.1.0",
"@testing-library/react": "^9.1.4",
+ "eslint": "^6.4.0",
"eslint-config-oceanprotocol": "^1.5.0",
"eslint-config-prettier": "^6.3.0",
"eslint-plugin-prettier": "^3.1.0",
+ "jest-mock-axios": "^3.1.1",
"node-sass": "^4.12.0",
"prettier": "^1.18.2"
},
diff --git a/src/App.module.scss b/src/App.module.scss
index 3317b59..4094587 100644
--- a/src/App.module.scss
+++ b/src/App.module.scss
@@ -34,5 +34,6 @@ h1, h2 {
display: grid;
gap: $spacer;
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
- margin-top: $spacer * 2;
+ margin: $spacer * 2 auto;
+ max-width: 80rem;
}
diff --git a/src/App.test.js b/src/App.test.js
index b6835b5..97a40b5 100644
--- a/src/App.test.js
+++ b/src/App.test.js
@@ -3,11 +3,7 @@ import { render } from '@testing-library/react'
import App from './App'
describe('App', () => {
- it('should be able to run tests', () => {
- expect(1 + 2).toEqual(3)
- })
-
- it('renders without crashing', async () => {
+ it('renders without crashing', () => {
const { container } = render()
expect(container.firstChild).toBeInTheDocument()
})
diff --git a/src/Network.js b/src/Network.js
index 32c0c71..d172398 100644
--- a/src/Network.js
+++ b/src/Network.js
@@ -14,42 +14,45 @@ Network.propTypes = {
}
export default function Network({ network }) {
- const [status, setStatus] = useState('...')
- const [block, setBlock] = useState('...')
- const [latency, setLatency] = useState('...')
- const [clientVersion, setClientVersion] = useState('...')
+ const [status, setStatus] = useState('')
+ const [block, setBlock] = useState('')
+ const [latency, setLatency] = useState('')
+ const [clientVersion, setClientVersion] = useState('')
useEffect(() => {
- getStatusAndBlock(network, setStatus, setBlock, setLatency)
- getClientVersion(network, setClientVersion)
+ async function getStatusAndBlock() {
+ const response = await axiosRpcRequest(network.url, 'eth_blockNumber')
- const timer = setInterval(() => {
- getStatusAndBlock(network, setStatus, setBlock, setLatency)
- getClientVersion(network, setClientVersion)
- }, 5000) // run every 5 sec.
- return () => clearInterval(timer)
- }, [network])
+ if (!response || response.status !== 200) {
+ setStatus('Offline')
+ return
+ }
- async function getStatusAndBlock(network, setStatus, setBlock, setLatency) {
- const response = await axiosRpcRequest(network.url, 'eth_blockNumber')
+ setStatus('Online')
+ response.duration && setLatency(response.duration)
- if (response.status !== 200) {
- setStatus('Offline')
- return
+ const blockNumber =
+ response && response.data && parseInt(response.data.result, 16)
+
+ setBlock(blockNumber)
}
- setStatus('Online')
- setLatency(response.duration)
+ async function getClientVersion() {
+ const response = await axiosRpcRequest(network.url, 'web3_clientVersion')
+ response && response.data && setClientVersion(response.data.result)
+ }
- const blockNumber = parseInt(response.data.result, 16)
+ getStatusAndBlock()
+ getClientVersion()
- setBlock(blockNumber)
- }
-
- async function getClientVersion(network, setClientVersion) {
- const response = await axiosRpcRequest(network.url, 'web3_clientVersion')
- setClientVersion(response.data.result)
- }
+ const timer = setInterval(() => {
+ getStatusAndBlock()
+ getClientVersion()
+ }, 5000) // run every 5 sec.
+ return () => {
+ clearInterval(timer)
+ }
+ }, [network.url])
const isOnline = status === 'Online'
@@ -57,8 +60,8 @@ export default function Network({ network }) {
{network.name}
- {network.type}
{network.networkId}
+ {network.type}
{network.url}
@@ -67,14 +70,18 @@ export default function Network({ network }) {
{status}
-
- {latency} ms
-
+ {latency && (
+
+ {latency} ms
+
+ )}
-
- At block #{block}
-
-
{clientVersion}
+ {block && (
+
+ At block #{block}
+
+ )}
+ {clientVersion &&
{clientVersion}
}
)
}
diff --git a/src/Network.test.js b/src/Network.test.js
index 7c551e2..8ae4161 100644
--- a/src/Network.test.js
+++ b/src/Network.test.js
@@ -1,7 +1,18 @@
import React from 'react'
-import { render } from '@testing-library/react'
+import { render, waitForElement } from '@testing-library/react'
+import mockAxios from 'axios'
import Network from './Network'
+const mockResponse = {
+ status: 200,
+ duration: 1000,
+ data: { result: '0x345' }
+}
+
+afterEach(() => {
+ mockAxios.reset()
+})
+
describe('Network', () => {
const network = {
name: 'Pacific',
@@ -12,8 +23,12 @@ describe('Network', () => {
explorer: 'https://submarine.oceanprotocol.com'
}
- it('renders without crashing', () => {
- const { container } = render()
+ it('renders without crashing', async () => {
+ mockAxios.post.mockResolvedValueOnce(mockResponse)
+
+ const { container, getByTitle } = render()
expect(container.firstChild).toBeInTheDocument()
+ await waitForElement(() => getByTitle('Current block number'))
+ expect(mockAxios.post).toHaveBeenCalledTimes(2)
})
})
diff --git a/src/__mocks__/axios.js b/src/__mocks__/axios.js
new file mode 100644
index 0000000..ef28bf2
--- /dev/null
+++ b/src/__mocks__/axios.js
@@ -0,0 +1,2 @@
+import mockAxios from 'jest-mock-axios'
+export default mockAxios
diff --git a/src/index.js b/src/index.js
index 257c623..ac78d82 100644
--- a/src/index.js
+++ b/src/index.js
@@ -4,6 +4,16 @@ import './styles/global.scss'
import App from './App'
import * as serviceWorker from './serviceWorker'
-ReactDOM.render(, document.getElementById('root'))
+function renderToDOM() {
+ const rootElement = document.getElementById('root')
+
+ if (rootElement !== null) {
+ ReactDOM.render(, rootElement)
+ }
+}
+
+export { renderToDOM }
+
+renderToDOM()
serviceWorker.register()
diff --git a/src/index.test.js b/src/index.test.js
new file mode 100644
index 0000000..c8b4c46
--- /dev/null
+++ b/src/index.test.js
@@ -0,0 +1,12 @@
+import { act } from '@testing-library/react'
+import { renderToDOM } from '.'
+
+describe('index', () => {
+ it('should be able to run tests', () => {
+ expect(1 + 2).toEqual(3)
+ })
+
+ it('renders without crashing', () => {
+ act(() => renderToDOM())
+ })
+})
diff --git a/src/rpc.js b/src/rpc.js
index de74e60..b21754b 100644
--- a/src/rpc.js
+++ b/src/rpc.js
@@ -35,7 +35,6 @@ async function axiosRpcRequest(url, method) {
return response
} catch (error) {
- console.error(error.message)
return error
}
}
diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss
index 2a37273..26a4a2a 100644
--- a/src/styles/_variables.scss
+++ b/src/styles/_variables.scss
@@ -22,17 +22,17 @@ $body-background: $brand-black;
// Fonts
$font-family-base: 'Sharp Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
- Helvetica, Arial, sans-serif;
+ Helvetica, Arial, sans-serif;
$font-family-title: 'Sharp Sans Display', -apple-system, BlinkMacSystemFont,
- 'Segoe UI', Helvetica, Arial, sans-serif;
+ 'Segoe UI', Helvetica, Arial, sans-serif;
$font-family-monospace: 'Fira Code', 'Fira Mono', Menlo, Monaco, Consolas,
- 'Courier New', monospace;
+ 'Courier New', monospace;
$font-size-root: 16px;
$font-size-base: 1rem;
$font-size-large: 1.2rem;
-$font-size-small: .85rem;
-$font-size-mini: .65rem;
+$font-size-small: 0.85rem;
+$font-size-mini: 0.65rem;
$font-size-text: $font-size-base;
$font-size-label: $font-size-base;
$font-size-title: 1.4rem;
@@ -49,7 +49,7 @@ $line-height: 1.6;
// Sizes
$spacer: 2rem;
-$page-frame: .75rem;
+$page-frame: 0.75rem;
$break-point--small: 640px;
$break-point--medium: 860px;
@@ -57,6 +57,6 @@ $break-point--large: 1140px;
$break-point--huge: 1400px;
$brand-border-width: 1px;
-$border-radius: .2rem;
+$border-radius: 0.2rem;
$narrowWidth: 35rem;
diff --git a/src/styles/global.scss b/src/styles/global.scss
index d625847..ec38374 100644
--- a/src/styles/global.scss
+++ b/src/styles/global.scss
@@ -4,123 +4,123 @@
*,
*:before,
*:after {
- box-sizing: border-box;
+ box-sizing: border-box;
}
/* stylelint-disable selector-max-id */
html,
body,
#root {
- height: 100%;
+ height: 100%;
}
/* stylelint-enable selector-max-id */
html {
- font-size: $font-size-root;
+ font-size: $font-size-root;
}
body {
- color: $brand-grey-light;
- font-size: $font-size-base;
- font-family: $font-family-base;
- font-weight: $font-weight-base;
- line-height: $line-height;
- background: $body-background;
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- position: relative;
- margin: 0;
+ color: $brand-grey-light;
+ font-size: $font-size-base;
+ font-family: $font-family-base;
+ font-weight: $font-weight-base;
+ line-height: $line-height;
+ background: $body-background;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ position: relative;
+ margin: 0;
- @media screen and (min-width: $break-point--small) {
- padding: $page-frame;
- }
+ @media screen and (min-width: $break-point--small) {
+ padding: $page-frame;
+ }
}
a {
+ text-decoration: none;
+ color: $brand-pink;
+ transition: 0.2s ease-out;
+
+ &:hover,
+ &:focus {
+ color: darken($brand-pink, 15%);
text-decoration: none;
- color: $brand-pink;
- transition: .2s ease-out;
+ transform: translate3d(0, -0.1rem, 0);
+ }
- &:hover,
- &:focus {
- color: darken($brand-pink, 15%);
- text-decoration: none;
- transform: translate3d(0, -.1rem, 0);
- }
-
- &:active {
- color: darken($brand-pink, 15%);
- text-decoration: none;
- transform: none;
- transition: none;
- }
+ &:active {
+ color: darken($brand-pink, 15%);
+ text-decoration: none;
+ transform: none;
+ transition: none;
+ }
}
p {
- margin: 0;
- margin-bottom: $spacer / $line-height;
+ margin: 0;
+ margin-bottom: $spacer / $line-height;
}
// Lists
/////////////////////////////////////
ul {
- li {
- &:before {
- content: ' \25AA'; // Black Small Square: ▪ ▪
- top: -2px;
- }
+ li {
+ &:before {
+ content: ' \25AA'; // Black Small Square: ▪ ▪
+ top: -2px;
}
+ }
}
ol {
- counter-reset: ol-counter;
+ counter-reset: ol-counter;
- li {
- &:before {
- content: counter(ol-counter) '.';
- counter-increment: ol-counter;
- font-weight: $font-weight-bold;
- top: -1px;
- }
+ li {
+ &:before {
+ content: counter(ol-counter) '.';
+ counter-increment: ol-counter;
+ font-weight: $font-weight-bold;
+ top: -1px;
}
+ }
- ul li:before {
- content: ' \25AA';
- }
+ ul li:before {
+ content: ' \25AA';
+ }
}
ul,
ol {
- margin-top: 0;
- margin-bottom: $spacer;
- padding-left: $spacer / $line-height;
- list-style: none;
+ margin-top: 0;
+ margin-bottom: $spacer;
+ padding-left: $spacer / $line-height;
+ list-style: none;
- li {
- position: relative;
- display: block;
+ li {
+ position: relative;
+ display: block;
- &:before {
- position: absolute;
- left: -($spacer / $line-height);
- color: $brand-grey-light;
- user-select: none;
- }
-
- + li {
- margin-top: $spacer / 8;
- }
-
- ul,
- ol,
- p {
- margin-bottom: 0;
- margin-top: $spacer / 8;
- }
+ &:before {
+ position: absolute;
+ left: -($spacer / $line-height);
+ color: $brand-grey-light;
+ user-select: none;
}
+
+ + li {
+ margin-top: $spacer / 8;
+ }
+
+ ul,
+ ol,
+ p {
+ margin-bottom: 0;
+ margin-top: $spacer / 8;
+ }
+ }
}
// Inline typography
@@ -129,27 +129,27 @@ ol {
b,
strong,
.bold {
- font-weight: $font-weight-bold;
+ font-weight: $font-weight-bold;
}
em,
.italic {
- font-style: italic;
+ font-style: italic;
}
small {
- font-size: $font-size-small;
- display: inline-block;
+ font-size: $font-size-small;
+ display: inline-block;
}
abbr[title],
dfn {
- text-transform: none;
- font-style: normal;
- font-size: inherit;
- border-bottom: 1px dashed $brand-grey-light;
- cursor: help;
- font-feature-settings: inherit;
+ text-transform: none;
+ font-style: normal;
+ font-size: inherit;
+ border-bottom: 1px dashed $brand-grey-light;
+ cursor: help;
+ font-feature-settings: inherit;
}
h1,
@@ -157,30 +157,30 @@ h2,
h3,
h4,
h5 {
- font-family: $font-family-title;
- color: inherit;
- line-height: 1.2;
- font-weight: $font-weight-bold;
+ font-family: $font-family-title;
+ color: inherit;
+ line-height: 1.2;
+ font-weight: $font-weight-bold;
}
h1 {
- font-size: $font-size-h1;
+ font-size: $font-size-h1;
}
h2 {
- font-size: $font-size-h2;
+ font-size: $font-size-h2;
}
h3 {
- font-size: $font-size-h3;
+ font-size: $font-size-h3;
}
h4 {
- font-size: $font-size-h4;
+ font-size: $font-size-h4;
}
h5 {
- font-size: $font-size-h5;
+ font-size: $font-size-h5;
}
// Responsive Media
@@ -194,75 +194,75 @@ audio,
embed,
canvas,
picture {
- max-width: 100%;
- height: auto;
- margin: 0 auto;
- display: block;
+ max-width: 100%;
+ height: auto;
+ margin: 0 auto;
+ display: block;
}
hr {
- margin: $spacer 0;
- border: 0;
- border-bottom: .1rem solid $brand-grey-lighter;
+ margin: $spacer 0;
+ border: 0;
+ border-bottom: 0.1rem solid $brand-grey-lighter;
}
// Quotes
/////////////////////////////////////
q {
- font-style: italic;
+ font-style: italic;
}
cite {
- font-style: normal;
- text-transform: uppercase;
+ font-style: normal;
+ text-transform: uppercase;
}
blockquote,
blockquote > p {
- font-style: italic;
- color: lighten($brand-grey, 15%);
+ font-style: italic;
+ color: lighten($brand-grey, 15%);
}
blockquote {
- margin: 0 0 $spacer;
- padding-left: $spacer / 2;
- border-left: .2rem solid $brand-grey-lighter;
+ margin: 0 0 $spacer;
+ padding-left: $spacer / 2;
+ border-left: 0.2rem solid $brand-grey-lighter;
- @media screen and (min-width: $break-point--small) {
- padding-left: $spacer / $line-height;
- }
+ @media screen and (min-width: $break-point--small) {
+ padding-left: $spacer / $line-height;
+ }
}
// Tables
/////////////////////////////////////
table {
- width: 100%;
- margin-bottom: $spacer * $line-height;
- border-collapse: collapse;
+ width: 100%;
+ margin-bottom: $spacer * $line-height;
+ border-collapse: collapse;
- th,
- td {
- border: 0;
- margin: 0;
- padding: $spacer / 2;
- border-bottom: 1px solid $brand-grey-lighter;
- text-align: left;
- font-size: 90%;
+ th,
+ td {
+ border: 0;
+ margin: 0;
+ padding: $spacer / 2;
+ border-bottom: 1px solid $brand-grey-lighter;
+ text-align: left;
+ font-size: 90%;
- &[align='center'] {
- text-align: center;
- }
-
- &[align='right'] {
- text-align: right;
- }
+ &[align='center'] {
+ text-align: center;
}
- th {
- font-weight: 600;
+ &[align='right'] {
+ text-align: right;
}
+ }
+
+ th {
+ font-weight: 600;
+ }
}
// Code
@@ -272,63 +272,63 @@ code,
kbd,
pre,
samp {
- font-family: $font-family-monospace;
- font-size: $font-size-small;
- border-radius: $border-radius;
- text-shadow: none;
- overflow-wrap: break-word;
- word-wrap: break-word;
- word-break: break-all;
+ font-family: $font-family-monospace;
+ font-size: $font-size-small;
+ border-radius: $border-radius;
+ text-shadow: none;
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ word-break: break-all;
- h1 &,
- h2 &,
- h3 &,
- h4 &,
- h5 & {
- font-size: inherit;
- }
+ h1 &,
+ h2 &,
+ h3 &,
+ h4 &,
+ h5 & {
+ font-size: inherit;
+ }
}
:not(pre) > code {
- color: inherit;
- display: inline-block;
+ color: inherit;
+ display: inline-block;
}
a > code {
- color: $brand-pink;
+ color: $brand-pink;
}
pre {
+ display: block;
+ margin-bottom: $spacer;
+ padding: 0;
+ background: lighten($brand-grey-lighter, 5%);
+
+ // make 'em scrollable
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+
+ code {
+ padding: $spacer;
+ white-space: pre;
display: block;
- margin-bottom: $spacer;
- padding: 0;
- background: lighten($brand-grey-lighter, 5%);
-
- // make 'em scrollable
+ color: $brand-grey-lighter;
+ overflow-wrap: normal;
+ word-wrap: normal;
+ word-break: normal;
overflow: auto;
- -webkit-overflow-scrolling: touch;
-
- code {
- padding: $spacer;
- white-space: pre;
- display: block;
- color: $brand-grey-lighter;
- overflow-wrap: normal;
- word-wrap: normal;
- word-break: normal;
- overflow: auto;
- }
+ }
}
// Selection
/////////////////////////////////////
::-moz-selection {
- background: $brand-grey-light;
- color: #fff;
+ background: $brand-grey-light;
+ color: #fff;
}
::selection {
- background: $brand-grey-light;
- color: #fff;
+ background: $brand-grey-light;
+ color: #fff;
}