A reactive data-store for web3 and smart contracts
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

176 lines
5.1 KiB

import { initializeWeb3, getNetworkId } from '../src/web3/web3Saga'
import { call, put } from 'redux-saga/effects'
import { runSaga } from 'redux-saga'
import * as Action from '../src/web3/constants'
const hasWeb3Shape = obj => {
expect(obj).toHaveProperty('currentProvider')
expect(obj).toHaveProperty('BatchRequest')
expect(obj).toHaveProperty('version')
expect(obj).toHaveProperty('utils')
expect(obj).toHaveProperty('eth')
}
describe('Resolving Web3', () => {
let web3Options, resolvedWeb3, gen
describe('with customProvider', () => {
beforeAll(async () => {
global.window = {}
web3Options = { customProvider: global.provider }
})
test('get web3', async () => {
gen = initializeWeb3(web3Options)
// First action dispatched
expect(gen.next().value).toEqual(put({ type: Action.WEB3_INITIALIZED }))
resolvedWeb3 = gen.next().value
expect(resolvedWeb3).toEqual(global.provider)
})
})
describe('with ethereum, EIP-1102 compliance', () => {
test('invokes `ethereum.enable`', async () => {
const mockedEthereumEnable = jest.fn()
const ethereum = { enable: mockedEthereumEnable }
global.window = { ethereum }
gen = initializeWeb3({})
let next = gen.next()
// get permission according to EIP 1102
//
expect(next.value).toEqual(
call({ context: ethereum, fn: ethereum.enable })
)
// return an account to simulate opt-in
next = gen.next('0x123')
expect(next.value).toEqual(put({ type: Action.WEB3_INITIALIZED }))
resolvedWeb3 = gen.next().value
hasWeb3Shape(resolvedWeb3)
})
test('loads when user opts in', async () => {
const mockedEthereumEnable = jest.fn(() => '0x123')
const ethereum = { enable: mockedEthereumEnable }
global.window = { ethereum }
const dispatched = []
const result = await runSaga({
dispatch: (action) => dispatched.push(action),
getState: () => ({ state: 'test' })
}, initializeWeb3, {}).done
// result should be a proper web3 provider
expect(result).toBeInstanceOf(require('web3'))
})
test('does not load when user opts out', async () => {
// opt out
global.window = { ethereum: { enable: jest.fn(() => undefined) } }
const dispatched = []
const web3Result = await runSaga(
{
dispatch: action => dispatched.push(action),
getState: () => ({ state: 'test' })
},
initializeWeb3,
{}
).done
// saga result should be undefined if an exception occurs
expect(web3Result).toBe(undefined)
// and the last action should be WEB3_USER_DENIED
expect(dispatched.pop()).toEqual({ type: Action.WEB3_USER_DENIED })
})
test('does not load when provider throws an error', async () => {
// simulate opting out
const mockedEthereumEnable = jest.fn(() => { throw new Error('oops') })
const ethereum = { enable: mockedEthereumEnable }
global.window = { ethereum }
const dispatched = []
const result = await runSaga({
dispatch: (action) => dispatched.push(action),
getState: () => ({ state: 'test' })
}, initializeWeb3, {}).done
// saga result is undefined when exception is thrown
expect(result).toBe(undefined)
// and the last action should be WEB3_FAILED
expect(dispatched.pop()).toEqual({ type: Action.WEB3_FAILED })
})
})
describe('with injected web3', () => {
beforeAll(async () => {
global.window = {}
global.window.web3 = { currentProvider: global.provider }
gen = initializeWeb3({})
})
test('get web3', async () => {
// First action dispatched
expect(gen.next().value).toEqual(put({ type: Action.WEB3_INITIALIZED }))
})
})
describe('with websocket fallback web3', () => {
let gen
beforeAll(async () => {
global.window = {}
global.provider.providers = { WebSocketProvider: jest.fn() }
})
test('get web3', async () => {
web3Options = {
fallback: {
type: 'ws',
url: 'ws://localhost:12345'
}
}
gen = initializeWeb3(web3Options)
// First action dispatched
expect(gen.next().value).toEqual(put({ type: Action.WEB3_INITIALIZED }))
resolvedWeb3 = gen.next().value
// is it a Web3 object?
hasWeb3Shape(resolvedWeb3)
})
test('fails when fallback type is unknown', async () => {
web3Options = {
fallback: {
type: 'thewrongtype',
url: 'ws://localhost:12345'
}
}
gen = initializeWeb3(web3Options)
const error = new Error('Invalid web3 fallback provided.')
expect(gen.next().value).toEqual(put({ type: Action.WEB3_FAILED, error }))
})
})
describe('Exhausts options', () => {
beforeAll(async () => {
global.window = {}
gen = initializeWeb3({})
})
test('with failure', async () => {
const error = new Error('Cannot find injected web3 or valid fallback.')
expect(gen.next().value).toEqual(put({ type: Action.WEB3_FAILED, error }))
})
})
})