Lints top-level test files (#1594)

* lint broadcastClient

* lint client

* fix most of connection

* remove unused files

* lint mockRippled

* lint mockRippledTest

* lint runClientTests

* lint setupClient

* lint setupClientWeb

* lint shamap

* lint testUtils

* resolve tsc issues

* Fix tests

* lint rest of connection

* respond to comments
This commit is contained in:
Mayukha Vadari
2021-09-07 14:25:39 -05:00
parent c8a2a6690b
commit 949cc031ee
44 changed files with 342 additions and 402 deletions

View File

@@ -88,6 +88,8 @@ module.exports = {
// We need to test things without type guards sometimes // We need to test things without type guards sometimes
"@typescript-eslint/no-unsafe-assignment": "off", "@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/consistent-type-assertions": "off",
// We need to mess with internal things to generate certain testing situations // We need to mess with internal things to generate certain testing situations
"@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/no-unsafe-member-access": "off",
@@ -99,6 +101,9 @@ module.exports = {
allowModules: ["xrpl-local"], allowModules: ["xrpl-local"],
}, },
], ],
// Tests are already in 2 callbacks, so max 3 is pretty restrictive
"max-nested-callbacks": "off",
}, },
}, },
{ {

View File

@@ -1,34 +1,29 @@
import { assert } from 'chai' import { assert } from 'chai'
import _ from 'lodash' import _ from 'lodash'
import { ServerInfoResponse } from '../src'
import responses from './fixtures/responses' import responses from './fixtures/responses'
import rippled from './fixtures/rippled' import rippled from './fixtures/rippled'
import setupClient from './setupClient' import { setupBroadcast, teardownClient } from './setupClient'
import { ignoreWebSocketDisconnect } from './testUtils' import { assertResultMatch, ignoreWebSocketDisconnect } from './testUtils'
const TIMEOUT = 20000 const TIMEOUT = 20000
function checkResult(expected, response) {
if (expected.txJSON) {
assert(response.txJSON)
assert.deepEqual(JSON.parse(response.txJSON), JSON.parse(expected.txJSON))
}
assert.deepEqual(_.omit(response, 'txJSON'), _.omit(expected, 'txJSON'))
return response
}
describe('BroadcastClient', function () { describe('BroadcastClient', function () {
this.timeout(TIMEOUT) this.timeout(TIMEOUT)
beforeEach(setupClient.setupBroadcast) beforeEach(setupBroadcast)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('base', function () { it('base', async function () {
this.mocks.forEach((mock) => { this.mocks.forEach((mock) => {
mock.addResponse('server_info', rippled.server_info.normal) mock.addResponse('server_info', rippled.server_info.normal)
}) })
assert(this.client.isConnected()) assert(this.client.isConnected())
return this.client.request({ command: 'server_info' }).then((response) => { this.client
return checkResult(responses.getServerInfo, response.result.info) .request({ command: 'server_info' })
.then((response: ServerInfoResponse) => {
assertResultMatch(responses.getServerInfo, response.result.info)
}) })
}) })

View File

@@ -2,27 +2,19 @@ import { assert } from 'chai'
import _ from 'lodash' import _ from 'lodash'
import { Client } from 'xrpl-local' import { Client } from 'xrpl-local'
import {
RecursiveData,
renameCounterpartyToIssuerInOrder,
compareTransactions,
getRecursive,
} from 'xrpl-local/ledger/utils'
import { toRippledAmount } from '../src' import { setupClient, teardownClient } from './setupClient'
import setupClient from './setupClient'
import { assertRejects } from './testUtils'
// how long before each test case times out // how long before each test case times out
const TIMEOUT = 20000 const TIMEOUT = 20000
describe('Client', function () { describe('Client', function () {
this.timeout(TIMEOUT) this.timeout(TIMEOUT)
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('Client - implicit server port', function () { it('Client - implicit server port', function () {
// eslint-disable-next-line no-new -- Need to test constructor
new Client('wss://s1.ripple.com') new Client('wss://s1.ripple.com')
}) })
@@ -33,6 +25,7 @@ describe('Client', function () {
it('Client valid options', function () { it('Client valid options', function () {
const client = new Client('wss://s:1') const client = new Client('wss://s:1')
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TODO: fix when src/client linting is merged
const privateConnectionUrl = (client.connection as any).url const privateConnectionUrl = (client.connection as any).url
assert.deepEqual(privateConnectionUrl, 'wss://s:1') assert.deepEqual(privateConnectionUrl, 'wss://s:1')
}) })
@@ -45,54 +38,4 @@ describe('Client', function () {
// TODO: Use a timer mock like https://jestjs.io/docs/en/timer-mocks // TODO: Use a timer mock like https://jestjs.io/docs/en/timer-mocks
// to test that connect() times out after 2 seconds. // to test that connect() times out after 2 seconds.
}) })
describe('[private] validator', function () {
it('common utils - toRippledAmount', async function () {
const amount = { issuer: 'is', currency: 'c', value: 'v' }
assert.deepEqual(toRippledAmount(amount), {
issuer: 'is',
currency: 'c',
value: 'v',
})
})
it('ledger utils - renameCounterpartyToIssuerInOrder', async function () {
const order = {
taker_gets: { counterparty: '1', currency: 'XRP' },
taker_pays: { counterparty: '1', currency: 'XRP' },
}
const expected = {
taker_gets: { issuer: '1', currency: 'XRP' },
taker_pays: { issuer: '1', currency: 'XRP' },
}
assert.deepEqual(renameCounterpartyToIssuerInOrder(order), expected)
})
it('ledger utils - compareTransactions', async function () {
// @ts-expect-error
assert.strictEqual(compareTransactions({}, {}), 0)
let first: any = { outcome: { ledgerVersion: 1, indexInLedger: 100 } }
let second: any = { outcome: { ledgerVersion: 1, indexInLedger: 200 } }
assert.strictEqual(compareTransactions(first, second), -1)
first = { outcome: { ledgerVersion: 1, indexInLedger: 100 } }
second = { outcome: { ledgerVersion: 1, indexInLedger: 100 } }
assert.strictEqual(compareTransactions(first, second), 0)
first = { outcome: { ledgerVersion: 1, indexInLedger: 200 } }
second = { outcome: { ledgerVersion: 1, indexInLedger: 100 } }
assert.strictEqual(compareTransactions(first, second), 1)
})
it('ledger utils - getRecursive', async function () {
async function getter(marker) {
return new Promise<RecursiveData>((resolve, reject) => {
if (marker != null) {
reject(new Error())
return
}
resolve({ marker: 'A', results: [1] })
})
}
await assertRejects(getRecursive(getter, 10), Error)
})
})
}) })

View File

@@ -3,15 +3,15 @@ import binary from 'ripple-binary-codec'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch } from '../testUtils' import { assertResultMatch } from '../testUtils'
const { combine: REQUEST_FIXTURES } = requests const { combine: REQUEST_FIXTURES } = requests
const { combine: RESPONSE_FIXTURES } = responses const { combine: RESPONSE_FIXTURES } = responses
describe('client.combine', function () { describe('client.combine', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('combine', async function () { it('combine', async function () {
const combined = this.client.combine(REQUEST_FIXTURES.setDomain) const combined = this.client.combine(REQUEST_FIXTURES.setDomain)

View File

@@ -1,10 +1,10 @@
import { assert } from 'chai' import { assert } from 'chai'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
describe('client errors', function () { describe('client errors', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('XrplError with data', async function () { it('XrplError with data', async function () {
const error = new this.client.errors.XrplError('_message_', '_data_') const error = new this.client.errors.XrplError('_message_', '_data_')

View File

@@ -1,7 +1,7 @@
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import rippledAccountLines from '../fixtures/rippled/accountLines' import rippledAccountLines from '../fixtures/rippled/accountLines'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
/** /**
@@ -10,8 +10,8 @@ import { assertResultMatch, addressTests } from '../testUtils'
* - Check out "test/client/index.ts" for more information about the test runner. * - Check out "test/client/index.ts" for more information about the test runner.
*/ */
describe('getBalances', function () { describe('getBalances', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,11 +1,11 @@
import { assert } from 'chai' import { assert } from 'chai'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
describe('client.getFee', function () { describe('client.getFee', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('getFee', async function () { it('getFee', async function () {
this.mockRippled.addResponse('server_info', rippled.server_info.normal) this.mockRippled.addResponse('server_info', rippled.server_info.normal)

View File

@@ -4,7 +4,7 @@ import { BookOffersRequest } from '../../src'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { addressTests, assertResultMatch, assertRejects } from '../testUtils' import { addressTests, assertResultMatch, assertRejects } from '../testUtils'
// import BigNumber from 'bignumber.js' // import BigNumber from 'bignumber.js'
@@ -83,8 +83,8 @@ function xrpRippledResponse(request: BookOffersRequest): object {
} }
describe('client.getOrderbook', function () { describe('client.getOrderbook', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,7 +1,7 @@
import addresses from '../fixtures/addresses.json' import addresses from '../fixtures/addresses.json'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertRejects } from '../testUtils' import { assertRejects } from '../testUtils'
// import responses from '../fixtures/responses' // import responses from '../fixtures/responses'
const { getPaths: REQUEST_FIXTURES } = requests const { getPaths: REQUEST_FIXTURES } = requests
@@ -15,8 +15,8 @@ const rippledResponse = rippled.path_find.generate.generateIOUPaymentPaths(
) )
describe('client.getPaths', function () { describe('client.getPaths', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
// 'simple test', function () { // 'simple test', function () {
// const response = await this.client.getPaths(REQUEST_FIXTURES.normal) // const response = await this.client.getPaths(REQUEST_FIXTURES.normal)
// assertResultMatch(response, RESPONSE_FIXTURES.XrpToUsd, 'getPaths') // assertResultMatch(response, RESPONSE_FIXTURES.XrpToUsd, 'getPaths')

View File

@@ -1,13 +1,13 @@
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled/accountLines' import rippled from '../fixtures/rippled/accountLines'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const { getTrustlines: RESPONSE_FIXTURES } = responses const { getTrustlines: RESPONSE_FIXTURES } = responses
describe('client.getTrustlines', function () { describe('client.getTrustlines', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -2,11 +2,11 @@ import { assert } from 'chai'
import { Client } from '../../src' import { Client } from '../../src'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
describe('client.hasNextPage', function () { describe('client.hasNextPage', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('returns true when there is another page', async function () { it('returns true when there is another page', async function () {
this.mockRippled.addResponse('ledger_data', rippled.ledger_data.first_page) this.mockRippled.addResponse('ledger_data', rippled.ledger_data.first_page)

View File

@@ -1,10 +1,10 @@
import { assert } from 'chai' import { assert } from 'chai'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
describe('client.isConnected', function () { describe('client.isConnected', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('disconnect & isConnected', async function () { it('disconnect & isConnected', async function () {
assert.strictEqual(this.client.isConnected(), true) assert.strictEqual(this.client.isConnected(), true)

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareCheckCancel', function () { describe('client.prepareCheckCancel', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareCheckCash', function () { describe('client.prepareCheckCash', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareCheckCreate', function () { describe('client.prepareCheckCreate', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareEscrowCancellation', function () { describe('client.prepareEscrowCancellation', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -2,21 +2,14 @@ import addresses from '../fixtures/addresses.json'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch } from '../testUtils' import { assertResultMatch } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
export const config = {
// TODO: The mock server right now returns a hard-coded string, no matter
// what "Account" value you pass. We'll need it to support more accurate
// responses before we can turn these tests on.
skipXAddress: true,
}
describe('client.prepareEscrowCreation', function () { describe('client.prepareEscrowCreation', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('prepareEscrowCreation', async function () { it('prepareEscrowCreation', async function () {
this.mockRippled.addResponse('server_info', rippled.server_info.normal) this.mockRippled.addResponse('server_info', rippled.server_info.normal)

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { addressTests, assertRejects, assertResultMatch } from '../testUtils' import { addressTests, assertRejects, assertResultMatch } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareEscrowExecution', function () { describe('client.prepareEscrowExecution', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareOrder', function () { describe('client.prepareOrder', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareOrderCancellation', function () { describe('client.prepareOrderCancellation', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -3,7 +3,7 @@ import { ValidationError } from 'xrpl-local/common/errors'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests, assertRejects } from '../testUtils' import { assertResultMatch, addressTests, assertRejects } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
@@ -12,8 +12,8 @@ const { preparePayment: RESPONSE_FIXTURES } = responses
const RECIPIENT_ADDRESS = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo' const RECIPIENT_ADDRESS = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo'
describe('client.preparePayment', function () { describe('client.preparePayment', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -3,7 +3,7 @@ import { assert } from 'chai'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
@@ -11,8 +11,8 @@ const { preparePaymentChannelClaim: REQUEST_FIXTURES } = requests
const { preparePaymentChannelClaim: RESPONSE_FIXTURES } = responses const { preparePaymentChannelClaim: RESPONSE_FIXTURES } = responses
describe('client.preparePaymentChannelClaim', function () { describe('client.preparePaymentChannelClaim', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -2,21 +2,14 @@ import addresses from '../fixtures/addresses.json'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch } from '../testUtils' import { assertResultMatch } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
export const config = {
// TODO: The mock server right now returns a hard-coded string, no matter
// what "Account" value you pass. We'll need it to support more accurate
// responses before we can turn these tests on.
skipXAddress: true,
}
describe('client.preparePaymentChannelCreate', function () { describe('client.preparePaymentChannelCreate', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('preparePaymentChannelCreate', async function () { it('preparePaymentChannelCreate', async function () {
this.mockRippled.addResponse('server_info', rippled.server_info.normal) this.mockRippled.addResponse('server_info', rippled.server_info.normal)

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.preparePaymentChannelFund', function () { describe('client.preparePaymentChannelFund', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -4,14 +4,14 @@ import { FormattedSettings } from '../../src/common/types/objects'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareSettings', function () { describe('client.prepareSettings', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,5 +1,5 @@
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
// import responses from '../fixtures/responses' // import responses from '../fixtures/responses'
// import requests from '../fixtures/requests' // import requests from '../fixtures/requests'
@@ -15,8 +15,8 @@ import { assertResultMatch, addressTests } from '../testUtils'
// const ADDRESS = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo' // const ADDRESS = 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo'
describe('client.prepareTicket', function () { describe('client.prepareTicket', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -5,21 +5,14 @@ import { xrpToDrops, ISOTimeToRippleTime } from '../../src/utils'
import addresses from '../fixtures/addresses.json' import addresses from '../fixtures/addresses.json'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertRejects, assertResultMatch } from '../testUtils' import { assertRejects, assertResultMatch } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
export const config = {
// TODO: The mock server right now returns a hard-coded string, no matter
// what "Account" value you pass. We'll need it to support more accurate
// responses before we can turn these tests on.
skipXAddress: true,
}
describe('client.prepareTransaction', function () { describe('client.prepareTransaction', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('auto-fillable fields - does not overwrite Fee in txJSON', async function () { it('auto-fillable fields - does not overwrite Fee in txJSON', async function () {
this.mockRippled.addResponse('server_info', rippled.server_info.normal) this.mockRippled.addResponse('server_info', rippled.server_info.normal)

View File

@@ -1,14 +1,14 @@
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertResultMatch, addressTests } from '../testUtils' import { assertResultMatch, addressTests } from '../testUtils'
const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 } const instructionsWithMaxLedgerVersionOffset = { maxLedgerVersionOffset: 100 }
describe('client.prepareTrustline', function () { describe('client.prepareTrustline', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -1,11 +1,11 @@
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { addressTests, assertResultMatch } from '../testUtils' import { addressTests, assertResultMatch } from '../testUtils'
describe('client.request', function () { describe('client.request', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
addressTests.forEach(function (test) { addressTests.forEach(function (test) {
describe(test.type, function () { describe(test.type, function () {

View File

@@ -2,7 +2,7 @@ import { assert } from 'chai'
import { Client } from '../../src' import { Client } from '../../src'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { assertRejects } from '../testUtils' import { assertRejects } from '../testUtils'
const rippledResponse = function (request: Request): object { const rippledResponse = function (request: Request): object {
@@ -13,8 +13,8 @@ const rippledResponse = function (request: Request): object {
} }
describe('client.requestNextPage', function () { describe('client.requestNextPage', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('requests the next page', async function () { it('requests the next page', async function () {
this.mockRippled.addResponse('ledger_data', rippledResponse) this.mockRippled.addResponse('ledger_data', rippledResponse)
const response = await this.client.request({ command: 'ledger_data' }) const response = await this.client.request({ command: 'ledger_data' })

View File

@@ -4,15 +4,15 @@ import binary from 'ripple-binary-codec'
import requests from '../fixtures/requests' import requests from '../fixtures/requests'
import responses from '../fixtures/responses' import responses from '../fixtures/responses'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
import { addressTests } from '../testUtils' import { addressTests } from '../testUtils'
const { sign: REQUEST_FIXTURES } = requests const { sign: REQUEST_FIXTURES } = requests
const { sign: RESPONSE_FIXTURES } = responses const { sign: RESPONSE_FIXTURES } = responses
describe('client.sign', function () { describe('client.sign', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('sign', async function () { it('sign', async function () {
const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV' const secret = 'shsWGZcmZz6YsWWmcnpfr6fLTdtFV'
const result = this.client.sign(REQUEST_FIXTURES.normal.txJSON, secret) const result = this.client.sign(REQUEST_FIXTURES.normal.txJSON, secret)

View File

@@ -1,11 +1,11 @@
import { assert } from 'chai' import { assert } from 'chai'
import rippled from '../fixtures/rippled' import rippled from '../fixtures/rippled'
import setupClient from '../setupClient' import { setupClient, teardownClient } from '../setupClient'
describe('Subscription', function () { describe('Subscription', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('Successfully Subscribes', async function () { it('Successfully Subscribes', async function () {
this.mockRippled.addResponse('subscribe', rippled.subscribe.success) this.mockRippled.addResponse('subscribe', rippled.subscribe.success)

View File

@@ -16,13 +16,16 @@ import {
} from '../src/common/errors' } from '../src/common/errors'
import rippled from './fixtures/rippled' import rippled from './fixtures/rippled'
import setupClient from './setupClient' import { setupClient, teardownClient } from './setupClient'
import { ignoreWebSocketDisconnect } from './testUtils' import { ignoreWebSocketDisconnect } from './testUtils'
const TIMEOUT = 200000 // how long before each test case times out // how long before each test case times out
const TIMEOUT = 20000
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Necessary to get browser info
const isBrowser = (process as any).browser const isBrowser = (process as any).browser
async function createServer() { async function createServer(): Promise<net.Server> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const server = net.createServer() const server = net.createServer()
server.on('listening', function () { server.on('listening', function () {
@@ -37,56 +40,89 @@ async function createServer() {
describe('Connection', function () { describe('Connection', function () {
this.timeout(TIMEOUT) this.timeout(TIMEOUT)
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('default options', function () { it('default options', function () {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Need to access private methods
const connection: any = new Connection('url') const connection: any = new Connection('url')
assert.strictEqual(connection.url, 'url') assert.strictEqual(connection.getUrl(), 'url')
assert(connection.config.proxy == null) assert(connection.config.proxy == null)
assert(connection.config.authorization == null) assert(connection.config.authorization == null)
}) })
describe('trace', function () { describe('trace', function () {
const mockedRequestData = { mocked: 'request' } let mockedRequestData
const mockedResponse = JSON.stringify({ mocked: 'response', id: 0 }) let mockedResponse
const expectedMessages = [ let expectedMessages
let originalConsoleLog
beforeEach(function () {
mockedRequestData = { mocked: 'request' }
mockedResponse = JSON.stringify({ mocked: 'response', id: 0 })
expectedMessages = [
// We add the ID here, since it's not a part of the user-provided request. // We add the ID here, since it's not a part of the user-provided request.
['send', JSON.stringify({ ...mockedRequestData, id: 0 })], ['send', JSON.stringify({ ...mockedRequestData, id: 0 })],
['receive', mockedResponse], ['receive', mockedResponse],
] ]
const originalConsoleLog = console.log // eslint-disable-next-line no-console -- Testing trace
originalConsoleLog = console.log
})
afterEach(function () { afterEach(function () {
// eslint-disable-next-line no-console -- Testing trace
console.log = originalConsoleLog console.log = originalConsoleLog
}) })
it('as false', function () { it('as false', function () {
const messages: any[] = [] const messages: Array<[number | string, string]> = []
console.log = (id, message) => messages.push([id, message]) // eslint-disable-next-line no-console -- Testing trace
console.log = function (id: number, message: string): void {
messages.push([id, message])
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Need to access private methods
const connection: any = new Connection('url', { trace: false }) const connection: any = new Connection('url', { trace: false })
connection.ws = { send() {} } connection.ws = {
send(): void {
/* purposefully empty */
},
}
connection.request(mockedRequestData) connection.request(mockedRequestData)
connection.onMessage(mockedResponse) connection.onMessage(mockedResponse)
assert.deepEqual(messages, []) assert.deepEqual(messages, [])
}) })
it('as true', function () { it('as true', function () {
const messages: any[] = [] const messages: Array<[number | string, string]> = []
console.log = (id, message) => messages.push([id, message]) // eslint-disable-next-line no-console -- Testing trace
console.log = function (id: number | string, message: string): void {
messages.push([id, message])
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Need to access private methods
const connection: any = new Connection('url', { trace: true }) const connection: any = new Connection('url', { trace: true })
connection.ws = { send() {} } connection.ws = {
send(): void {
/* purposefully empty */
},
}
connection.request(mockedRequestData) connection.request(mockedRequestData)
connection.onMessage(mockedResponse) connection.onMessage(mockedResponse)
assert.deepEqual(messages, expectedMessages) assert.deepEqual(messages, expectedMessages)
}) })
it('as a function', function () { it('as a function', function () {
const messages: any[] = [] const messages: Array<[number | string, string]> = []
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Need to access private methods
const connection: any = new Connection('url', { const connection: any = new Connection('url', {
trace: (id, message) => messages.push([id, message]), trace(id: number | string, message: string): void {
messages.push([id, message])
},
}) })
connection.ws = { send() {} } connection.ws = {
send(): void {
/* purposefully empty */
},
}
connection.request(mockedRequestData) connection.request(mockedRequestData)
connection.onMessage(mockedResponse) connection.onMessage(mockedResponse)
assert.deepEqual(messages, expectedMessages) assert.deepEqual(messages, expectedMessages)
@@ -98,9 +134,16 @@ describe('Connection', function () {
done() done()
return return
} }
createServer().then((server: any) => { createServer().then((server: net.Server) => {
const port = server.address().port const port = (server.address() as net.AddressInfo).port
const options = {
proxy: `ws://localhost:${port}`,
authorization: 'authorization',
trustedCertificates: ['path/to/pem'],
}
const connection = new Connection(this.client.connection.url, options)
const expect = 'CONNECT localhost' const expect = 'CONNECT localhost'
server.on('connection', (socket) => { server.on('connection', (socket) => {
socket.on('data', (data) => { socket.on('data', (data) => {
const got = data.toString('ascii', 0, expect.length) const got = data.toString('ascii', 0, expect.length)
@@ -111,25 +154,19 @@ describe('Connection', function () {
}) })
}) })
const options = {
proxy: `ws://localhost:${port}`,
authorization: 'authorization',
trustedCertificates: ['path/to/pem'],
}
const connection = new Connection(this.client.connection.url, options)
connection.connect().catch((err) => { connection.connect().catch((err) => {
assert(err instanceof NotConnectedError) assert(err instanceof NotConnectedError)
}) })
}, done) }, done)
}) })
it('Multiply disconnect calls', function () { it('Multiply disconnect calls', async function () {
this.client.disconnect()
this.client.disconnect() this.client.disconnect()
return this.client.disconnect()
}) })
it('reconnect', function () { it('reconnect', function () {
return this.client.connection.reconnect() this.client.connection.reconnect()
}) })
it('NotConnectedError', async function () { it('NotConnectedError', async function () {
@@ -166,7 +203,7 @@ describe('Connection', function () {
}) })
it('DisconnectedError', async function () { it('DisconnectedError', async function () {
return this.client this.client
.request({ command: 'test_command', data: { closeServer: true } }) .request({ command: 'test_command', data: { closeServer: true } })
.then(() => { .then(() => {
assert.fail('Should throw DisconnectedError') assert.fail('Should throw DisconnectedError')
@@ -177,11 +214,11 @@ describe('Connection', function () {
}) })
it('TimeoutError', function () { it('TimeoutError', function () {
this.client.connection.ws.send = function (_, callback) { this.client.connection.ws.send = function (_ignore, sendCallback): void {
callback(null) sendCallback(null)
} }
const request = { command: 'server_info' } const request = { command: 'server_info' }
return this.client.connection this.client.connection
.request(request, 10) .request(request, 10)
.then(() => { .then(() => {
assert.fail('Should throw TimeoutError') assert.fail('Should throw TimeoutError')
@@ -192,10 +229,10 @@ describe('Connection', function () {
}) })
it('DisconnectedError on send', function () { it('DisconnectedError on send', function () {
this.client.connection.ws.send = function (_, callback) { this.client.connection.ws.send = function (_ignore, sendCallback): void {
callback({ message: 'not connected' }) sendCallback({ message: 'not connected' })
} }
return this.client this.client
.request({ command: 'server_info' }) .request({ command: 'server_info' })
.then(() => { .then(() => {
assert.fail('Should throw DisconnectedError') assert.fail('Should throw DisconnectedError')
@@ -211,21 +248,20 @@ describe('Connection', function () {
// do not rely on the client.setup hook to test this as it bypasses the case, disconnect client connection first // do not rely on the client.setup hook to test this as it bypasses the case, disconnect client connection first
await this.client.disconnect() await this.client.disconnect()
// stub onOpen to only run logic relevant to test case // stub _onOpen to only run logic relevant to test case
this.client.connection.onOpen = () => { this.client.connection.onOpen = (): void => {
// overload websocket send on open when _ws exists // overload websocket send on open when _ws exists
this.client.connection.ws.send = function (_0, _1, _2) { this.client.connection.ws.send = function (_0, _1, _2): void {
// recent ws throws this error instead of calling back // recent ws throws this error instead of calling back
throw new Error('WebSocket is not open: readyState 0 (CONNECTING)') throw new Error('WebSocket is not open: readyState 0 (CONNECTING)')
} }
const request = { command: 'subscribe', streams: ['ledger'] } const request = { command: 'subscribe', streams: ['ledger'] }
return this.client.connection.request(request) this.client.connection.request(request)
} }
try { try {
await this.client.connect() await this.client.connect()
} catch (error) { } catch (error) {
console.log(error)
assert.instanceOf(error, DisconnectedError) assert.instanceOf(error, DisconnectedError)
assert.strictEqual( assert.strictEqual(
error.message, error.message,
@@ -235,7 +271,7 @@ describe('Connection', function () {
}) })
it('ResponseFormatError', function () { it('ResponseFormatError', function () {
return this.client this.client
.request({ .request({
command: 'test_command', command: 'test_command',
data: { unrecognizedResponse: true }, data: { unrecognizedResponse: true },
@@ -267,8 +303,9 @@ describe('Connection', function () {
} }
} }
this.timeout(70001) this.timeout(70001)
// eslint-disable-next-line @typescript-eslint/no-this-alias -- Avoid shadow alias
const self = this const self = this
function breakConnection() { function breakConnection(): void {
self.client.connection self.client.connection
.request({ .request({
command: 'test_command', command: 'test_command',
@@ -307,6 +344,7 @@ describe('Connection', function () {
`reconnectsCount must be equal to ${num} (got ${reconnectsCount} instead)`, `reconnectsCount must be equal to ${num} (got ${reconnectsCount} instead)`,
), ),
) )
// eslint-disable-next-line no-negated-condition -- Necessary
} else if (code !== 1006) { } else if (code !== 1006) {
done( done(
new Error(`disconnect must send code 1006 (got ${code} instead)`), new Error(`disconnect must send code 1006 (got ${code} instead)`),
@@ -336,8 +374,8 @@ describe('Connection', function () {
// Hook up a listener for the reconnect event // Hook up a listener for the reconnect event
this.client.connection.on('reconnect', () => done()) this.client.connection.on('reconnect', () => done())
// Trigger a heartbeat // Trigger a heartbeat
this.client.connection.heartbeat().catch((error) => { this.client.connection.heartbeat().catch((_error) => {
/* ignore - test expects heartbeat failure */ /* Ignore error */
}) })
}) })
@@ -354,7 +392,7 @@ describe('Connection', function () {
// Drop the test runner timeout, since this should be a quick test // Drop the test runner timeout, since this should be a quick test
this.timeout(5000) this.timeout(5000)
// fail on reconnect/connection // fail on reconnect/connection
this.client.connection.reconnect = async () => { this.client.connection.reconnect = async (): Promise<void> => {
throw new Error('error on reconnect') throw new Error('error on reconnect')
} }
// Hook up a listener for the reconnect error event // Hook up a listener for the reconnect error event
@@ -398,8 +436,8 @@ describe('Connection', function () {
}) })
it('Multiply connect calls', function () { it('Multiply connect calls', function () {
return this.client.connect().then(() => { this.client.connect().then(() => {
return this.client.connect() this.client.connect()
}) })
}) })
@@ -417,8 +455,10 @@ describe('Connection', function () {
it('connect multiserver error', function () { it('connect multiserver error', function () {
assert.throws(function () { assert.throws(function () {
// eslint-disable-next-line no-new -- Testing constructor
new Client({ new Client({
servers: ['wss://server1.com', 'wss://server2.com'], servers: ['wss://server1.com', 'wss://server2.com'],
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Testing invalid constructor
} as any) } as any)
}, XrplError) }, XrplError)
}) })
@@ -436,10 +476,10 @@ describe('Connection', function () {
let transactionCount = 0 let transactionCount = 0
let pathFindCount = 0 let pathFindCount = 0
this.client.connection.on('transaction', () => { this.client.connection.on('transaction', () => {
transactionCount++ transactionCount += 1
}) })
this.client.connection.on('path_find', () => { this.client.connection.on('path_find', () => {
pathFindCount++ pathFindCount += 1
}) })
this.client.connection.on('response', (message) => { this.client.connection.on('response', (message) => {
assert.strictEqual(message.id, 1) assert.strictEqual(message.id, 1)
@@ -552,13 +592,13 @@ describe('Connection', function () {
let disconnectedCount = 0 let disconnectedCount = 0
this.client.on('connected', () => { this.client.on('connected', () => {
done( done(
disconnectedCount !== 1 disconnectedCount === 1
? new Error('Wrong number of disconnects') ? undefined
: undefined, : new Error('Wrong number of disconnects'),
) )
}) })
this.client.on('disconnected', () => { this.client.on('disconnected', () => {
disconnectedCount++ disconnectedCount += 1
}) })
this.client.connection.request({ this.client.connection.request({
command: 'test_command', command: 'test_command',

View File

@@ -1,31 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<!-- encoding must be set for mocha's special characters to render properly -->
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
<script src="./vendor/lodash.min.js"></script>
</head>
<body>
<div id="deb"></div>
<div id="mocha"></div>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="hacks/phantomhacks.js"></script>
<script src="../build/ripple-latest.js"></script>
<script>
if (window.initMochaPhantomJS) {
window.initMochaPhantomJS();
}
mocha.ui('bdd')
</script>
<script src="../testCompiledForWeb/runClientTests.js"></script>
<script src="../testCompiledForWeb/broadcastClient.js"></script>
<script src="../testCompiledForWeb/connection.js"></script>
<script>
mocha.run()
</script>
</body>
</html>

View File

@@ -1,31 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<!-- encoding must be set for mocha's special characters to render properly -->
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" />
<script src="./vendor/lodash.min.js"></script>
</head>
<body>
<div id="deb"></div>
<div id="mocha"></div>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="hacks/phantomhacks.js"></script>
<script src="../build/ripple-latest-min.js"></script>
<script>
if (window.initMochaPhantomJS) {
window.initMochaPhantomJS();
}
mocha.ui('bdd')
</script>
<script src="../testCompiledForWeb/runClientTests.js"></script>
<script src="../testCompiledForWeb/broadcastClient.js"></script>
<script src="../testCompiledForWeb/connection.js"></script>
<script>
mocha.run()
</script>
</body>
</html>

View File

@@ -7,7 +7,10 @@ import type { BaseResponse } from '../src/models/methods/baseMethod'
import { getFreePort } from './testUtils' import { getFreePort } from './testUtils'
function createResponse(request: { id: number | string }, response: object) { function createResponse(
request: { id: number | string },
response: Record<string, unknown>,
): string {
if (!('type' in response) && !('error' in response)) { if (!('type' in response) && !('error' in response)) {
throw new Error( throw new Error(
`Bad response format. Must contain \`type\` or \`error\`. ${JSON.stringify( `Bad response format. Must contain \`type\` or \`error\`. ${JSON.stringify(
@@ -18,7 +21,7 @@ function createResponse(request: { id: number | string }, response: object) {
return JSON.stringify({ ...response, id: request.id }) return JSON.stringify({ ...response, id: request.id })
} }
function ping(conn, request) { function ping(conn, request): void {
setTimeout(() => { setTimeout(() => {
conn.send( conn.send(
createResponse(request, { createResponse(request, {
@@ -38,23 +41,29 @@ export interface PortResponse extends BaseResponse {
// We mock out WebSocketServer in these tests and add a lot of custom // We mock out WebSocketServer in these tests and add a lot of custom
// properties not defined on the normal WebSocketServer object. // properties not defined on the normal WebSocketServer object.
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- typing is too complicated otherwise
type MockedWebSocketServer = any type MockedWebSocketServer = any
export function createMockRippled(port) { // eslint-disable-next-line @typescript-eslint/promise-function-async -- Not a promise that's returned
export default function createMockRippled(port: number): MockedWebSocketServer {
const mock = new WebSocketServer({ port }) as MockedWebSocketServer const mock = new WebSocketServer({ port }) as MockedWebSocketServer
Object.assign(mock, EventEmitter2.prototype) Object.assign(mock, EventEmitter2.prototype)
mock.responses = {} mock.responses = {}
mock.suppressOutput = false mock.suppressOutput = false
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Typing is too complicated otherwise
mock.on('connection', function (this: MockedWebSocketServer, conn: any) { mock.on('connection', function (this: MockedWebSocketServer, conn: any) {
this.socket = conn this.socket = conn
conn.on('message', function (requestJSON) { conn.on('message', function (requestJSON: string) {
let request let request
try { try {
request = JSON.parse(requestJSON) request = JSON.parse(requestJSON)
if (request.id == null) { if (request.id == null) {
throw new Error('Request has no id') throw new Error(`Request has no id: ${requestJSON}`)
}
if (request.command == null) {
throw new Error(`Request has no id: ${requestJSON}`)
} }
if (request.command === 'ping') { if (request.command === 'ping') {
ping(conn, request) ping(conn, request)
@@ -64,11 +73,13 @@ export function createMockRippled(port) {
conn.send(createResponse(request, mock.getResponse(request))) conn.send(createResponse(request, mock.getResponse(request)))
} else { } else {
throw new Error( throw new Error(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- We know it's there
`No event handler registered in mock rippled for ${request.command}`, `No event handler registered in mock rippled for ${request.command}`,
) )
} }
} catch (err) { } catch (err) {
if (!mock.suppressOutput) { if (!mock.suppressOutput) {
// eslint-disable-next-line no-console, @typescript-eslint/restrict-template-expressions -- Error
console.error(`Error: ${err.message}`) console.error(`Error: ${err.message}`)
} }
if (request != null) { if (request != null) {
@@ -87,10 +98,12 @@ export function createMockRippled(port) {
// Adds a mocked response // Adds a mocked response
// If an object is passed in for `response`, then the response is static for the command // If an object is passed in for `response`, then the response is static for the command
// If a function is passed in for `response`, then the response can be determined by the exact request shape // If a function is passed in for `response`, then the response can be determined by the exact request shape
mock.addResponse = ( mock.addResponse = function (
command: string, command: string,
response: object | ((r: Request) => object), response:
) => { | Record<string, unknown>
| ((r: Request) => Record<string, unknown>),
): void {
if (typeof command !== 'string') { if (typeof command !== 'string') {
throw new Error('command is not a string') throw new Error('command is not a string')
} }
@@ -108,18 +121,18 @@ export function createMockRippled(port) {
mock.responses[command] = response mock.responses[command] = response
} }
mock.getResponse = (request: Request): object => { mock.getResponse = (request: Request): Record<string, unknown> => {
if (!(request.command in mock.responses)) { if (!(request.command in mock.responses)) {
throw new Error(`No handler for ${request.command}`) throw new Error(`No handler for ${request.command}`)
} }
const functionOrObject = mock.responses[request.command] const functionOrObject = mock.responses[request.command]
if (typeof functionOrObject === 'function') { if (typeof functionOrObject === 'function') {
return functionOrObject(request) return functionOrObject(request) as Record<string, unknown>
} }
return functionOrObject return functionOrObject as Record<string, unknown>
} }
mock.testCommand = function testCommand(conn, request) { mock.testCommand = function testCommand(conn, request): void {
if (request.data.disconnectIn) { if (request.data.disconnectIn) {
setTimeout(conn.terminate.bind(conn), request.data.disconnectIn) setTimeout(conn.terminate.bind(conn), request.data.disconnectIn)
conn.send( conn.send(
@@ -143,7 +156,7 @@ export function createMockRippled(port) {
} else if (request.data.closeServerAndReopen) { } else if (request.data.closeServerAndReopen) {
setTimeout(() => { setTimeout(() => {
conn.terminate() conn.terminate()
mock.close.call(mock, () => { mock.close(() => {
setTimeout(() => { setTimeout(() => {
createMockRippled(port) createMockRippled(port)
}, request.data.closeServerAndReopen) }, request.data.closeServerAndReopen)

View File

@@ -2,12 +2,12 @@ import { assert } from 'chai'
import { RippledError } from '../src/common/errors' import { RippledError } from '../src/common/errors'
import setupClient from './setupClient' import { setupClient, teardownClient } from './setupClient'
import { assertRejects } from './testUtils' import { assertRejects } from './testUtils'
describe('mock rippled tests', function () { describe('mock rippled tests', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('errors if a mock is not provided', async function () { it('errors if a mock is not provided', async function () {
this.mockRippled.suppressOutput = true this.mockRippled.suppressOutput = true
await assertRejects( await assertRejects(
@@ -17,10 +17,14 @@ describe('mock rippled tests', function () {
}) })
it('provide bad response shape', async function () { it('provide bad response shape', async function () {
assert.throws( try {
() => this.mockRippled.addResponse('account_info', { data: {} }), this.mockRippled.addResponse('account_info', { data: {} })
Error, assert.fail('Should have errored')
) } catch (err) {
if (!(err instanceof Error)) {
assert.fail(`Wrong error type: ${err as string}`)
}
}
}) })
it('provide bad response shape in function', async function () { it('provide bad response shape in function', async function () {

View File

@@ -1,17 +0,0 @@
import { createMockRippled } from './mockRippled'
const port = 34371
function main() {
// @ts-expect-error -- mocha.
if (global.describe) {
// we are running inside mocha, exiting
return
}
console.log(`starting server on port ${port}`)
createMockRippled(port)
console.log(`starting server on port ${String(port + 1)}`)
createMockRippled(port + 1)
}
main()

View File

@@ -1,3 +1,4 @@
/* eslint-disable mocha/no-setup-in-describe -- Necessary to programmatically generate tests */
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
@@ -9,18 +10,23 @@ import { Client } from 'xrpl-local'
* Throws errors when we detect the absence of tests. * Throws errors when we detect the absence of tests.
* Puts all the client methods under one "describe" umbrella. * Puts all the client methods under one "describe" umbrella.
*/ */
describe('Client [Test Runner]', function () {
describe('Client', function () {
// doesn't need a functional client, just needs to instantiate to get a list of public methods // doesn't need a functional client, just needs to instantiate to get a list of public methods
// (to determine what methods are missing from ) // (to determine what methods are missing from )
const allPublicMethods = getAllPublicMethods(new Client('wss://')) const allPublicMethods = getAllPublicMethods(new Client('wss://'))
const allTestSuites = loadTestSuites() const allTestSuites = loadTestSuites()
// Report any missing tests. // Report any missing tests.
const allTestedMethods = new Set(allTestSuites.map((s) => s.name)) const allTestedMethods = new Set(
allTestSuites.map((testsuite) => testsuite.name),
)
for (const methodName of allPublicMethods) { for (const methodName of allPublicMethods) {
if (!allTestedMethods.has(methodName)) { if (!allTestedMethods.has(methodName)) {
// TODO: Once migration is complete, remove `.skip()` so that missing tests are reported as failures. // TODO: Once migration is complete, remove `.skip()` so that missing tests are reported as failures.
// eslint-disable-next-line mocha/no-skipped-tests -- See above TODO
it.skip(`${methodName} - no test suite found`, function () { it.skip(`${methodName} - no test suite found`, function () {
throw new Error( throw new Error(
`Test file not found! Create file "test/client/${methodName}.ts".`, `Test file not found! Create file "test/client/${methodName}.ts".`,
@@ -30,13 +36,14 @@ describe('Client [Test Runner]', function () {
} }
}) })
function getAllPublicMethods(client: Client) { function getAllPublicMethods(client: Client): string[] {
return Array.from( return Array.from(
new Set([ new Set([
...Object.getOwnPropertyNames(client), ...Object.getOwnPropertyNames(client),
...Object.getOwnPropertyNames(Client.prototype), ...Object.getOwnPropertyNames(Client.prototype),
]), ]),
).filter((key) => !key.startsWith('_')) // removes private methods // removes private methods
).filter((key) => !key.startsWith('_'))
} }
/** /**
@@ -51,18 +58,24 @@ interface LoadedTestSuite {
} }
function loadTestSuites(): LoadedTestSuite[] { function loadTestSuites(): LoadedTestSuite[] {
const allTests: any[] = fs.readdirSync(path.join(__dirname, 'client'), { // eslint-disable-next-line node/no-sync -- Necessary for file processing
const allTests = fs.readdirSync(path.join(__dirname, 'client'), {
encoding: 'utf8', encoding: 'utf8',
}) })
return allTests return allTests
.map((methodName) => { .map((filename) => {
if (methodName.startsWith('.DS_Store')) { if (filename.startsWith('.DS_Store')) {
return null return null
} }
if (methodName.endsWith('.ts')) { let methodName: string
methodName = methodName.slice(0, -3) if (filename.endsWith('.ts')) {
methodName = filename.slice(0, -3)
} else {
methodName = filename
} }
const testSuite = require(`./client/${methodName}`) // eslint-disable-next-line max-len -- Many errors to disable
// eslint-disable-next-line @typescript-eslint/no-var-requires, node/global-require, global-require, @typescript-eslint/no-require-imports, import/no-dynamic-require -- Necessary for client tests
const testSuite = require(path.join(__dirname, 'client', filename))
return { return {
name: methodName, name: methodName,
config: testSuite.config || {}, config: testSuite.config || {},

View File

@@ -1,9 +1,15 @@
/* eslint-disable no-param-reassign -- Necessary for test setup */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types -- Necessary for test setup */
import { Client, BroadcastClient } from 'xrpl-local' import { Client, BroadcastClient } from 'xrpl-local'
import { createMockRippled } from './mockRippled' import createMockRippled from './mockRippled'
import { getFreePort } from './testUtils' import { getFreePort } from './testUtils'
async function setupMockRippledConnection(testcase, port) { async function setupMockRippledConnection(
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Typing is too complicated
testcase: any,
port: number,
): Promise<void> {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
testcase.mockRippled = createMockRippled(port) testcase.mockRippled = createMockRippled(port)
testcase._mockedServerPort = port testcase._mockedServerPort = port
@@ -12,44 +18,47 @@ async function setupMockRippledConnection(testcase, port) {
}) })
} }
async function setupMockRippledConnectionForBroadcast(testcase, ports) { async function setupMockRippledConnectionForBroadcast(
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Typing is too complicated
testcase: any,
ports: number[],
): Promise<void> {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
const servers = ports.map((port) => `ws://localhost:${port}`) const servers = ports.map((port) => `ws://localhost:${port}`)
// eslint-disable-next-line max-len -- Too many rules to disable
// eslint-disable-next-line @typescript-eslint/promise-function-async, @typescript-eslint/no-unsafe-return -- Typing is too complicated, not an async function
testcase.mocks = ports.map((port) => createMockRippled(port)) testcase.mocks = ports.map((port) => createMockRippled(port))
testcase.client = new BroadcastClient(servers) testcase.client = new BroadcastClient(servers)
testcase.client.connect().then(resolve).catch(reject) testcase.client.connect().then(resolve).catch(reject)
}) })
} }
async function setup(this: any) { async function setupClient(this: unknown): Promise<void> {
return getFreePort().then(async (port) => { return getFreePort().then(async (port) => {
return setupMockRippledConnection(this, port) return setupMockRippledConnection(this, port)
}) })
} }
async function setupBroadcast(this: any) { async function setupBroadcast(this: unknown): Promise<void> {
return Promise.all([getFreePort(), getFreePort()]).then(async (ports) => { return Promise.all([getFreePort(), getFreePort()]).then(async (ports) => {
return setupMockRippledConnectionForBroadcast(this, ports) return setupMockRippledConnectionForBroadcast(this, ports)
}) })
} }
function teardown(this: any, done) { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Typing is too complicated
function teardownClient(this: any, done: () => void): void {
this.client this.client
.disconnect() .disconnect()
.then(() => { .then(() => {
// eslint-disable-next-line no-negated-condition -- Easier to read with negation
if (this.mockRippled != null) { if (this.mockRippled != null) {
this.mockRippled.close() this.mockRippled.close()
} else { } else {
this.mocks.forEach((mock) => mock.close()) this.mocks.forEach((mock: { close: () => void }) => mock.close())
} }
setImmediate(done) setImmediate(done)
}) })
.catch(done) .catch(done)
} }
export default { export { setupClient, teardownClient, setupBroadcast, createMockRippled }
setup,
teardown,
setupBroadcast,
createMockRippled,
}

View File

@@ -1,12 +1,14 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types -- Necessary for test setup */
import { Client, BroadcastClient } from 'xrpl-local' import { Client, BroadcastClient } from 'xrpl-local'
import { PortResponse } from './mockRippled' import { PortResponse } from './mockRippled'
const port = 34371 const defaultPort = 34371
const baseUrl = 'ws://testripple.circleci.com:' const baseUrl = 'ws://testripple.circleci.com:'
async function setup(this: any, port_ = port) { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Needed for setup
const tclient = new Client(baseUrl + port_) async function setupClient(this: any, port = defaultPort): Promise<void> {
const tclient = new Client(`${baseUrl}${port}`)
return tclient return tclient
.connect() .connect()
.then(async () => { .then(async () => {
@@ -15,9 +17,11 @@ async function setup(this: any, port_ = port) {
data: { openOnOtherPort: true }, data: { openOnOtherPort: true },
}) })
}) })
.then(async (got) => { .then(async (got: unknown) => {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
this.client = new Client(baseUrl + (got as PortResponse).result.port) this.client = new Client(
`${baseUrl}${(got as PortResponse).result.port}`,
)
this.client.connect().then(resolve).catch(reject) this.client.connect().then(resolve).catch(reject)
}) })
}) })
@@ -26,23 +30,23 @@ async function setup(this: any, port_ = port) {
}) })
} }
async function setupBroadcast(this: any) { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Needed for setup
const servers = [port, port + 1].map((port_) => baseUrl + port_) async function setupBroadcast(this: any): Promise<void> {
const servers = [defaultPort, defaultPort + 1].map(
(port) => `${baseUrl}${port}`,
)
this.client = new BroadcastClient(servers) this.client = new BroadcastClient(servers)
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
this.client.connect().then(resolve).catch(reject) this.client.connect().then(resolve).catch(reject)
}) })
} }
function teardown(this: any) { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Needed for teardown
function teardownClient(this: any): undefined {
if (this.client.isConnected()) { if (this.client.isConnected()) {
return this.client.disconnect() return this.client.disconnect() as undefined
} }
return undefined return undefined
} }
export default { export { setupClient as setup, teardownClient as teardown, setupBroadcast }
setup,
teardown,
setupBroadcast,
}

View File

@@ -5,16 +5,19 @@ import { SHAMap, NodeType } from '../src/utils/hashes/shamap'
const TYPE_TRANSACTION_NO_METADATA = NodeType.TRANSACTION_NO_METADATA const TYPE_TRANSACTION_NO_METADATA = NodeType.TRANSACTION_NO_METADATA
const HEX_ZERO = const HEX_ZERO =
'00000000000000000000000000000000' + '00000000000000000000000000000000' '0000000000000000000000000000000000000000000000000000000000000000'
/** /**
* Generates data to hash for testing. * Generates data to hash for testing.
* *
* @param v * @param v - TODO: fill in.
* @returns TODO: fill in.
*/ */
// eslint-disable-next-line id-length -- TODO: figure out what this variable means
function intToVuc(v: number): string { function intToVuc(v: number): string {
let ret = '' let ret = ''
// eslint-disable-next-line id-length -- TODO: figure out what this variable means
for (let i = 0; i < 32; i++) { for (let i = 0; i < 32; i++) {
ret += '0' ret += '0'
ret += v.toString(16).toUpperCase() ret += v.toString(16).toUpperCase()
@@ -22,11 +25,19 @@ function intToVuc(v: number): string {
return ret return ret
} }
function fillShamapTest(shamap: any, keys: string[], hashes: string[]) { function fillShamapTest(
for (let i = 0; i < keys.length; i++) { shamap: SHAMap,
const data = intToVuc(i) keys: string[],
shamap.addItem(keys[i].toUpperCase(), data, TYPE_TRANSACTION_NO_METADATA) hashes: string[],
assert.equal(shamap.hash, hashes[i]) ): void {
for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) {
const data = intToVuc(keyIndex)
shamap.addItem(
keys[keyIndex].toUpperCase(),
data,
TYPE_TRANSACTION_NO_METADATA,
)
assert.equal(shamap.hash, hashes[keyIndex])
} }
} }

View File

@@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any -- Necessary for these methods TODO: further cleanup */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types -- Necessary for these methods TODO: further cleanup */
import net from 'net' import net from 'net'
import { assert } from 'chai' import { assert } from 'chai'
@@ -19,18 +21,18 @@ export const addressTests = [
* *
* @param response - Response received from the method. * @param response - Response received from the method.
* @param expected - Expected response from the method. * @param expected - Expected response from the method.
* @param schemaName - Name of the schema used to validate the shape of the response. * @param _schemaName - Name of the schema used to validate the shape of the response.
*/ */
export function assertResultMatch( export function assertResultMatch(
response: any, response: any,
expected: any, expected: any,
schemaName?: string, _schemaName?: string,
) { ): void {
if (expected.txJSON) { if (expected.txJSON) {
assert(response.txJSON) assert(response.txJSON)
assert.deepEqual( assert.deepEqual(
JSON.parse(response.txJSON), JSON.parse(response.txJSON as string),
JSON.parse(expected.txJSON), JSON.parse(expected.txJSON as string),
'checkResult: txJSON must match', 'checkResult: txJSON must match',
) )
} }
@@ -56,10 +58,10 @@ export function assertResultMatch(
* @param message - Expected error message/substring of the error message. * @param message - Expected error message/substring of the error message.
*/ */
export async function assertRejects( export async function assertRejects(
promise: PromiseLike<any>, promise: PromiseLike<Record<string, unknown>>,
instanceOf: any, instanceOf: any,
message?: string | RegExp, message?: string | RegExp,
) { ): Promise<void> {
try { try {
await promise await promise
assert(false, 'Expected an error to be thrown') assert(false, 'Expected an error to be thrown')
@@ -74,12 +76,12 @@ export async function assertRejects(
} }
// using a free port instead of a constant port enables parallelization // using a free port instead of a constant port enables parallelization
export async function getFreePort() { export async function getFreePort(): Promise<number> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const server = net.createServer() const server = net.createServer()
let port let port: number
server.on('listening', function () { server.on('listening', function () {
port = (server.address() as any).port port = (server.address() as net.AddressInfo).port
server.close() server.close()
}) })
server.on('close', function () { server.on('close', function () {
@@ -98,6 +100,7 @@ export async function getFreePort() {
* has come back. * has come back.
* *
* @param error - Thrown error. * @param error - Thrown error.
* @throws If error is not websocket disconnect error.
*/ */
export function ignoreWebSocketDisconnect(error: Error): void { export function ignoreWebSocketDisconnect(error: Error): void {
if (error.message === 'websocket was closed') { if (error.message === 'websocket was closed') {

View File

@@ -2,11 +2,11 @@ import { assert } from 'chai'
import { getFaucetUrl, FaucetNetwork } from '../src/wallet/generateFaucetWallet' import { getFaucetUrl, FaucetNetwork } from '../src/wallet/generateFaucetWallet'
import setupClient from './setupClient' import { setupClient, teardownClient } from './setupClient'
describe('Get Faucet URL', function () { describe('Get Faucet URL', function () {
beforeEach(setupClient.setup) beforeEach(setupClient)
afterEach(setupClient.teardown) afterEach(teardownClient)
it('returns the Devnet URL', function () { it('returns the Devnet URL', function () {
const expectedFaucet = FaucetNetwork.Devnet const expectedFaucet = FaucetNetwork.Devnet