@@ -37,11 +31,7 @@ export default class Header extends PureComponent {
diff --git a/client/src/components/organisms/Web3message.module.scss b/client/src/components/organisms/Web3message.module.scss
index 2abcc23..5a86272 100644
--- a/client/src/components/organisms/Web3message.module.scss
+++ b/client/src/components/organisms/Web3message.module.scss
@@ -3,27 +3,20 @@
.message {
margin-bottom: $spacer;
color: $brand-grey;
- padding-left: 2rem;
position: relative;
border-bottom: .1rem solid $brand-grey-lighter;
border-top: .1rem solid $brand-grey-lighter;
padding-top: $spacer / 2;
padding-bottom: $spacer / 2;
text-align: left;
-
- > div {
- display: inline-block;
- }
}
-.account {
- display: inline-block;
- margin-left: $spacer / 8;
- background: none;
+.warnings {
+ padding-left: $spacer;
}
.status {
margin-left: -($spacer);
- margin-right: $spacer / 3;
+ margin-right: $spacer / 2;
padding: 0;
}
diff --git a/client/src/components/organisms/Web3message.test.tsx b/client/src/components/organisms/Web3message.test.tsx
index ca0384c..9c5b223 100644
--- a/client/src/components/organisms/Web3message.test.tsx
+++ b/client/src/components/organisms/Web3message.test.tsx
@@ -1,11 +1,64 @@
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(
)
+ it('renders with noWeb3 message', () => {
+ const { container } = render(
+
+
+
+ )
+ expect(container.firstChild).toHaveTextContent('Not a Web3 Browser')
+ })
- expect(container.firstChild).toBeInTheDocument()
+ it('renders with wrongNetwork message', () => {
+ const { container } = render(
+
+
+
+ )
+ expect(container.firstChild).toHaveTextContent(
+ 'Not connected to Nile network'
+ )
+ })
+
+ it('renders with noAccount message', () => {
+ const { container } = render(
+
+
+
+ )
+ expect(container.firstChild).toHaveTextContent('No accounts detected')
+ })
+
+ it('renders with hasAccount message', () => {
+ const { container } = render(
+
+
+
+ )
+ expect(container.firstChild).toHaveTextContent('0xxxxxx')
+ })
+
+ it('button click fires unlockAccounts', () => {
+ const { getByText } = render(
+
+
+
+ )
+
+ fireEvent.click(getByText('Unlock Account'))
+ expect(userMock.unlockAccounts).toBeCalled()
})
})
diff --git a/client/src/components/organisms/Web3message.tsx b/client/src/components/organisms/Web3message.tsx
index bc93c57..e726ae8 100644
--- a/client/src/components/organisms/Web3message.tsx
+++ b/client/src/components/organisms/Web3message.tsx
@@ -1,5 +1,5 @@
import React, { PureComponent } from 'react'
-import Dotdotdot from 'react-dotdotdot'
+import Account from '../atoms/Account'
import Button from '../atoms/Button'
import AccountStatus from '../molecules/AccountStatus'
import styles from './Web3message.module.scss'
@@ -13,21 +13,18 @@ export default class Web3message extends PureComponent {
unlockAccounts?: () => any
) => (
-
{' '}
{account ? (
-
- {message}
- {account}
-
+
) : (
- <>
+
+
{' '}
{unlockAccounts && (
)}
- >
+
)}
)
@@ -35,7 +32,7 @@ export default class Web3message extends PureComponent {
public render() {
const {
isWeb3,
- isNile,
+ isOceanNetwork,
isLogged,
account,
unlockAccounts
@@ -43,7 +40,7 @@ export default class Web3message extends PureComponent {
return !isWeb3
? this.message(content.noweb3)
- : !isNile
+ : !isOceanNetwork
? this.message(content.wrongNetwork)
: !isLogged
? this.message(content.noAccount, '', unlockAccounts)
diff --git a/client/src/components/templates/Route.test.tsx b/client/src/components/templates/Route.test.tsx
new file mode 100644
index 0000000..014c0d2
--- /dev/null
+++ b/client/src/components/templates/Route.test.tsx
@@ -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(
Hello)
+ expect(container.firstChild).toBeInTheDocument()
+ })
+
+ it('renders title & description', () => {
+ const { container } = render(
+
+ Hello
+
+ )
+ expect(container.querySelector('.title')).toHaveTextContent(
+ 'Hello Title'
+ )
+ expect(container.querySelector('.description')).toHaveTextContent(
+ 'Hello Description'
+ )
+ })
+})
diff --git a/client/src/context/UserProvider.tsx b/client/src/context/UserProvider.tsx
index 335c6b4..743975a 100644
--- a/client/src/context/UserProvider.tsx
+++ b/client/src/context/UserProvider.tsx
@@ -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'
@@ -46,7 +46,7 @@ interface UserProviderState {
isLogged: boolean
isLoading: boolean
isWeb3: boolean
- isNile: boolean
+ isOceanNetwork: boolean
account: string
balance: {
eth: number
@@ -54,7 +54,7 @@ interface UserProviderState {
}
network: string
web3: Web3
- ocean: any
+ ocean: Ocean
requestFromFaucet(account: string): Promise
unlockAccounts(): Promise
message: string
@@ -74,7 +74,7 @@ export default class UserProvider extends PureComponent<{}, UserProviderState> {
isLogged: false,
isLoading: true,
isWeb3: false,
- isNile: false,
+ isOceanNetwork: false,
balance: {
eth: 0,
ocn: 0
@@ -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)
@@ -151,23 +151,32 @@ export default class UserProvider extends PureComponent<{}, UserProviderState> {
//
// Detecting network with window.web3
//
- let isNile
+ let isOceanNetwork
await window.web3.eth.net.getId((err, netId) => {
if (err) return
- isNile = netId === 8995
- const network = isNile ? 'Nile' : netId.toString()
+ const isNile = netId === 8995
+ const isDuero = netId === 2199
+ const isSpree = netId === 8996
+
+ isOceanNetwork = isNile || isDuero || isSpree
+
+ const network = isNile
+ ? 'Nile'
+ : isDuero
+ ? 'Duero'
+ : netId.toString()
if (
- isNile !== this.state.isNile ||
+ isOceanNetwork !== this.state.isOceanNetwork ||
network !== this.state.network
) {
- this.setState({ isNile, network })
+ this.setState({ isOceanNetwork, network })
}
})
- if (!isNile) {
+ if (!isOceanNetwork) {
web3 = this.state.web3 // eslint-disable-line
}
@@ -195,19 +204,19 @@ export default class UserProvider extends PureComponent<{}, UserProviderState> {
} catch (e) {
// error in bootstrap process
// show error connecting to ocean
- Logger.log('web3 error', e)
+ Logger.error('web3 error', e.message)
this.setState({ isLoading: false })
}
}
private fetchAccounts = async () => {
- const { ocean, isWeb3, isLogged, isNile } = this.state
+ const { ocean, isWeb3, isLogged, isOceanNetwork } = this.state
if (isWeb3) {
let accounts
// Modern dapp browsers
- if (window.ethereum && !isLogged && isNile) {
+ if (window.ethereum && !isLogged && isOceanNetwork) {
// simply set to empty, and have user click a button somewhere
// to initiate account unlocking
accounts = []
@@ -236,7 +245,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) {
@@ -250,8 +259,12 @@ export default class UserProvider extends PureComponent<{}, UserProviderState> {
if (isWeb3) {
const network = await ocean.keeper.getNetworkName()
const isNile = network === 'Nile'
+ const isDuero = network === 'Duero'
+ const isSpree = network === 'Spree'
+ const isOceanNetwork = isNile || isDuero || isSpree
- network !== this.state.network && this.setState({ isNile, network })
+ network !== this.state.network &&
+ this.setState({ isOceanNetwork, network })
}
}
diff --git a/client/src/context/index.tsx b/client/src/context/index.tsx
index eab3aa1..0cdf47d 100644
--- a/client/src/context/index.tsx
+++ b/client/src/context/index.tsx
@@ -4,7 +4,7 @@ export const User = React.createContext({
isLogged: false,
isLoading: false,
isWeb3: false,
- isNile: false,
+ isOceanNetwork: false,
account: '',
web3: {},
ocean: {},
diff --git a/client/src/data/form-publish.json b/client/src/data/form-publish.json
index ab011a8..c90cda0 100644
--- a/client/src/data/form-publish.json
+++ b/client/src/data/form-publish.json
@@ -38,6 +38,7 @@
"type": "select",
"required": true,
"options": [
+ "AI for Good",
"Image Recognition",
"Dataset Of Datasets",
"Language",
diff --git a/client/src/data/web3message.json b/client/src/data/web3message.json
index db9dc81..a441d40 100644
--- a/client/src/data/web3message.json
+++ b/client/src/data/web3message.json
@@ -1,6 +1,6 @@
{
"noweb3": "Not a Web3 Browser. For publishing and downloading an asset you need to setup MetaMask 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.
Please connect in MetaMask with Custom RPC https://nile.dev-ocean.com
"
}
diff --git a/client/src/hoc/withTracker.tsx b/client/src/hoc/withTracker.tsx
index f976590..272b8dc 100644
--- a/client/src/hoc/withTracker.tsx
+++ b/client/src/hoc/withTracker.tsx
@@ -3,15 +3,15 @@ import ReactGA, { FieldsObject } from 'react-ga'
import { RouteComponentProps } from 'react-router-dom'
import { analyticsId } from '../config'
+ReactGA.initialize(analyticsId, {
+ testMode: process.env.NODE_ENV === 'test',
+ debug: false
+})
+
const withTracker = (
WrappedComponent: any,
options: FieldsObject = {}
) => {
- ReactGA.initialize(analyticsId, {
- testMode: process.env.NODE_ENV === 'development',
- debug: false
- })
-
const trackPage = (page: string) => {
options.isWeb3 = window.web3 !== undefined
diff --git a/client/src/index.test.tsx b/client/src/index.test.tsx
new file mode 100644
index 0000000..4bf2b26
--- /dev/null
+++ b/client/src/index.test.tsx
@@ -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()
+ })
+})
diff --git a/client/src/index.tsx b/client/src/index.tsx
index 9dd7ba7..54596d0 100644
--- a/client/src/index.tsx
+++ b/client/src/index.tsx
@@ -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(, document.getElementById('root'))
+function renderToDOM() {
+ const root = document.getElementById('root')
+
+ if (root !== null) {
+ ReactDOM.render(
+
+
+ ,
+ 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.
diff --git a/client/src/ocean.test.ts b/client/src/ocean.test.ts
new file mode 100644
index 0000000..2628ee6
--- /dev/null
+++ b/client/src/ocean.test.ts
@@ -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')
+ })
+})
diff --git a/client/src/ocean.ts b/client/src/ocean.ts
index e752aec..8ce2ed8 100644
--- a/client/src/ocean.ts
+++ b/client/src/ocean.ts
@@ -72,6 +72,6 @@ export async function requestFromFaucet(account: string) {
})
return response.json()
} catch (error) {
- Logger.log('requestFromFaucet', error)
+ Logger.error('requestFromFaucet', error.message)
}
}
diff --git a/client/src/routes/About.test.tsx b/client/src/routes/About.test.tsx
new file mode 100644
index 0000000..0b1f795
--- /dev/null
+++ b/client/src/routes/About.test.tsx
@@ -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()
+ expect(container.firstChild).toBeInTheDocument()
+ })
+})
diff --git a/client/src/routes/Details/AssetDetails.test.tsx b/client/src/routes/Details/AssetDetails.test.tsx
new file mode 100644
index 0000000..8de750c
--- /dev/null
+++ b/client/src/routes/Details/AssetDetails.test.tsx
@@ -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(
+
+ )
+ expect(container.firstChild).toBeInTheDocument()
+ })
+
+ it('renders with data', () => {
+ const { container } = render(
+
+
+
+ )
+ 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')
+ })
+})
diff --git a/client/src/routes/Details/AssetDetails.tsx b/client/src/routes/Details/AssetDetails.tsx
index 1c418ac..655cd9c 100644
--- a/client/src/routes/Details/AssetDetails.tsx
+++ b/client/src/routes/Details/AssetDetails.tsx
@@ -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 {files.length} data file
+ }
+ return {files.length} data files
}
export default class AssetDetails extends PureComponent {
- private datafilesLine = (files: any) => {
- if (files.length === 1) {
- return {files.length} data file
- }
- return {files.length} data files
- }
-
public render() {
const { metadata, ddo } = this.props
const { base } = metadata
@@ -51,14 +52,16 @@ export default class AssetDetails extends PureComponent {
)}
- {base.files && this.datafilesLine(base.files)}
+ {base.files && datafilesLine(base.files)}
-