mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
feat: Jest Test Runner (#2170)
This commit is contained in:
@@ -6,7 +6,12 @@ module.exports = {
|
||||
parserOptions: {
|
||||
// Enable linting rules with type information from our tsconfig
|
||||
tsconfigRootDir: __dirname,
|
||||
project: ['./tsconfig.eslint.json'],
|
||||
project: [
|
||||
'./tsconfig.eslint.json',
|
||||
'../ripple-binary-codec/tsconfig.eslint.json',
|
||||
'../ripple-address-codec/tsconfig.eslint.json',
|
||||
'../ripple-keypairs/tsconfig.eslint.json',
|
||||
],
|
||||
|
||||
// Allow the use of imports / ES modules
|
||||
sourceType: 'module',
|
||||
@@ -23,11 +28,13 @@ module.exports = {
|
||||
node: true,
|
||||
// Add all ECMAScript 2020 globals and automatically set the ecmaVersion parser option to ES2020
|
||||
es2020: true,
|
||||
jest: true,
|
||||
},
|
||||
|
||||
plugins: [],
|
||||
extends: ['@xrplf/eslint-config/base', 'plugin:mocha/recommended'],
|
||||
extends: ['@xrplf/eslint-config/base'],
|
||||
rules: {
|
||||
'multiline-comment-style': 'off',
|
||||
// Disabled until https://github.com/import-js/eslint-plugin-import/pull/2305 is resolved to
|
||||
// accomodate this change https://github.com/XRPLF/xrpl.js/pull/2133
|
||||
'import/no-unused-modules': 'off',
|
||||
@@ -51,7 +58,6 @@ module.exports = {
|
||||
// no-shadow has false-positives for enum, @typescript-eslint version fixes that
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': ['error'],
|
||||
'multiline-comment-style': ['error', 'starred-block'],
|
||||
'jsdoc/check-examples': 'off',
|
||||
|
||||
'tsdoc/syntax': 'off',
|
||||
@@ -74,13 +80,16 @@ module.exports = {
|
||||
'max-statements': 'off',
|
||||
// Snippets have logs on console to better understand the working.
|
||||
'no-console': 'off',
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['test/**/*.ts'],
|
||||
rules: {
|
||||
// Because this project is managed by lerna, dev dependencies are
|
||||
// hoisted and do not appear in the package.json.
|
||||
/*
|
||||
* Because this project is managed by lerna, dev dependencies are
|
||||
* hoisted and do not appear in the package.json.
|
||||
*/
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
'node/no-extraneous-import': 'off',
|
||||
|
||||
@@ -102,19 +111,12 @@ module.exports = {
|
||||
// Tests are already in 2 callbacks, so max 3 is pretty restrictive
|
||||
'max-nested-callbacks': 'off',
|
||||
|
||||
// setup/teardown client is easier to do in before/after, even if there is only one testcase
|
||||
'mocha/no-hooks-for-single-case': 'off',
|
||||
|
||||
// messes with fixtures
|
||||
'consistent-default-export-name/default-import-match-filename': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['test/client/*.ts'],
|
||||
rules: {
|
||||
// Rule does not work with dynamically generated tests.
|
||||
'mocha/no-setup-in-describe': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['test/models/*.ts'],
|
||||
|
||||
@@ -4,11 +4,16 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
|
||||
## Unreleased
|
||||
|
||||
### Fixed
|
||||
* Code splitting improvements for lodash
|
||||
* Fixed missing reason code in websocket implemntation on websocket disconnect
|
||||
* Fix timeout error in request manager
|
||||
* Improved typescript typing
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
### Changed
|
||||
* All tests now use the Jest test runner and have been refactored for consistency across all packages
|
||||
|
||||
### Deprecated
|
||||
Wallet.fromMmnemonic()
|
||||
|
||||
8
packages/xrpl/jest.config.js
Normal file
8
packages/xrpl/jest.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// Jest configuration for api
|
||||
const base = require('../../jest.config.base.js')
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
roots: [...base.roots, '<rootDir>/test'],
|
||||
displayName: 'xrpl.js',
|
||||
}
|
||||
14
packages/xrpl/karma-setup.js
Normal file
14
packages/xrpl/karma-setup.js
Normal file
@@ -0,0 +1,14 @@
|
||||
// the jest.fn() API
|
||||
import * as jest from 'jest-mock'
|
||||
// The matchers API
|
||||
import expect from 'expect'
|
||||
|
||||
// Add missing Jest functions
|
||||
window.test = window.it
|
||||
window.test.each = (inputs) => (testName, test) =>
|
||||
inputs.forEach((args) => window.it(testName, () => test(...args)))
|
||||
window.test.todo = function () {
|
||||
return undefined
|
||||
}
|
||||
window.jest = jest
|
||||
window.expect = expect
|
||||
34
packages/xrpl/karma.config.js
Normal file
34
packages/xrpl/karma.config.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const webpackConfig = require('./test/webpack.config')[0]()
|
||||
delete webpackConfig.entry
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
plugins: ['karma-webpack', 'karma-jasmine', 'karma-chrome-launcher'],
|
||||
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '',
|
||||
|
||||
webpack: webpackConfig,
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
||||
frameworks: ['jasmine'],
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'build/xrpl-latest.js',
|
||||
'test/integration/index.ts',
|
||||
'karma-setup.js',
|
||||
],
|
||||
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
||||
preprocessors: {
|
||||
'karma-setup.js': ['webpack'],
|
||||
// Use webpack to bundle our test files
|
||||
'test/integration/index.ts': ['webpack'],
|
||||
},
|
||||
|
||||
browsers: ['ChromeHeadless'],
|
||||
})
|
||||
}
|
||||
2214
packages/xrpl/package-lock.json
generated
2214
packages/xrpl/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -33,9 +33,19 @@
|
||||
"ws": "^8.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@geut/browser-node-core": "^2.0.13",
|
||||
"@types/node": "^14.18.36",
|
||||
"assert-browserify": "^2.0.0",
|
||||
"browserify-fs": "^1.0.0",
|
||||
"constants-browserify": "^1.0.0",
|
||||
"https-browserify": "^1.0.0",
|
||||
"karma": "^6.4.1",
|
||||
"karma-chrome-launcher": "^3.1.1",
|
||||
"karma-jasmine": "^5.1.0",
|
||||
"karma-webpack": "^5.0.0",
|
||||
"node-polyfill-webpack-plugin": "^2.0.1",
|
||||
"react": "^18.2.0",
|
||||
"typedoc": "^0.23.24",
|
||||
"xrpl-local": "file:./src"
|
||||
"typedoc": "^0.23.24"
|
||||
},
|
||||
"resolutions": {
|
||||
"elliptic": "^6.5.4"
|
||||
@@ -48,13 +58,13 @@
|
||||
"build:browserTests": "webpack --config ./test/webpack.config.js",
|
||||
"analyze": "run-s build:web --analyze",
|
||||
"watch": "run-s build:lib --watch",
|
||||
"clean": "rm -rf dist",
|
||||
"clean": "rm -rf dist build coverage",
|
||||
"docgen": "tsc --build tsconfig.docs.json && typedoc && echo js.xrpl.org >> ../../docs/CNAME",
|
||||
"prepublish": "run-s clean build",
|
||||
"test": "nyc mocha --config=test/.mocharc.json --exit",
|
||||
"test:integration": "TS_NODE_PROJECT=tsconfig.build.json nyc mocha ./test/integration/**/*.test.ts ./test/integration/*.test.ts",
|
||||
"test:browser": "npm run build:browserTests && TS_NODE_PROJECT=tsconfig.build.json nyc mocha ./test/browser/*.ts",
|
||||
"test:watch": "TS_NODE_PROJECT=src/tsconfig.json mocha --config=test/.mocharc.json --watch --reporter dot",
|
||||
"test": "jest --verbose false --silent=false ./test/**/*.test.ts --testPathIgnorePatterns=./test/integration --testPathIgnorePatterns=./test/fixtures",
|
||||
"test:integration": "TS_NODE_PROJECT=tsconfig.build.json jest --verbose false --silent=false --runInBand ./test/integration/**/*.test.ts",
|
||||
"test:browser": "npm run build && npm run build:browserTests && karma start ./karma.config.js --single-run",
|
||||
"test:watch": "jest --watch --verbose false --silent=false --runInBand ./test/**/*.test.ts --testPathIgnorePatterns=./test/integration --testPathIgnorePatterns=./test/fixtures",
|
||||
"format": "prettier --write '{src,test}/**/*.ts'",
|
||||
"lint": "eslint . --ext .ts --max-warnings 0",
|
||||
"perf": "./scripts/perf_test.sh",
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
PaymentChannelCreate,
|
||||
PaymentChannelClaim,
|
||||
hashes,
|
||||
} from '../../dist/npm'
|
||||
} from '../../src'
|
||||
|
||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Client, LedgerResponse, TxResponse } from '../../dist/npm'
|
||||
import { Client, LedgerResponse, TxResponse } from '../../src'
|
||||
|
||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
AccountSet,
|
||||
convertStringToHex,
|
||||
SignerListSet,
|
||||
} from '../../dist/npm'
|
||||
} from '../../src'
|
||||
|
||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Client, Payment, PaymentFlags, TrustSet } from '../../dist/npm'
|
||||
import { Client, Payment, PaymentFlags, TrustSet } from '../../src'
|
||||
|
||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Client, Payment, RipplePathFindResponse } from '../../dist/npm'
|
||||
import { Client, Payment, RipplePathFindResponse } from '../../src'
|
||||
|
||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Client, Payment } from '../../dist/npm'
|
||||
import { Client, Payment } from '../../src'
|
||||
|
||||
/**
|
||||
* When implementing Reliable Transaction Submission, there are many potential solutions, each with different trade-offs.
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
EscrowCreate,
|
||||
EscrowFinish,
|
||||
isoTimeToRippleTime,
|
||||
} from '../../dist/npm'
|
||||
} from '../../src'
|
||||
|
||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Client, Payment, SetRegularKey } from '../../dist/npm'
|
||||
import { Client, Payment, SetRegularKey } from '../../src'
|
||||
|
||||
const client = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src"
|
||||
"rootDir": "../../xrpl"
|
||||
},
|
||||
"include": ["./src/**/*.ts"]
|
||||
"include": ["./src/**/*.ts", "../src/**/*.ts", "../src/**/*.json"]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Client } from '..'
|
||||
import type { Client } from '../client'
|
||||
import { XRPLFaucetError } from '../errors'
|
||||
|
||||
export interface FaucetWallet {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { request as httpsRequest, RequestOptions } from 'https'
|
||||
|
||||
import { isValidClassicAddress } from 'ripple-address-codec'
|
||||
|
||||
import type { Client } from '..'
|
||||
import type { Client } from '../client'
|
||||
import { RippledError, XRPLFaucetError } from '../errors'
|
||||
|
||||
import {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { fromSeed } from 'bip32'
|
||||
import { mnemonicToSeedSync, validateMnemonic } from 'bip39'
|
||||
import _ from 'lodash'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import {
|
||||
classicAddressToXAddress,
|
||||
isValidXAddress,
|
||||
@@ -498,7 +498,7 @@ class Wallet {
|
||||
})
|
||||
/* eslint-enable @typescript-eslint/consistent-type-assertions -- Done with dynamic checking */
|
||||
|
||||
if (!_.isEqual(decoded, txCopy)) {
|
||||
if (!isEqual(decoded, txCopy)) {
|
||||
const data = {
|
||||
decoded,
|
||||
tx,
|
||||
|
||||
@@ -20,7 +20,7 @@ export default class RequestManager {
|
||||
{
|
||||
resolve: (value: Response | PromiseLike<Response>) => void
|
||||
reject: (value: Error) => void
|
||||
timer: NodeJS.Timeout
|
||||
timer: ReturnType<typeof setTimeout>
|
||||
}
|
||||
>()
|
||||
|
||||
@@ -34,7 +34,10 @@ export default class RequestManager {
|
||||
public resolve(id: string | number, response: Response): void {
|
||||
const promise = this.promisesAwaitingResponse.get(id)
|
||||
if (promise == null) {
|
||||
throw new XrplError(`No existing promise with id ${id}`)
|
||||
throw new XrplError(`No existing promise with id ${id}`, {
|
||||
type: 'resolve',
|
||||
response,
|
||||
})
|
||||
}
|
||||
clearTimeout(promise.timer)
|
||||
promise.resolve(response)
|
||||
@@ -51,7 +54,10 @@ export default class RequestManager {
|
||||
public reject(id: string | number, error: Error): void {
|
||||
const promise = this.promisesAwaitingResponse.get(id)
|
||||
if (promise == null) {
|
||||
throw new XrplError(`No existing promise with id ${id}`)
|
||||
throw new XrplError(`No existing promise with id ${id}`, {
|
||||
type: 'reject',
|
||||
error,
|
||||
})
|
||||
}
|
||||
clearTimeout(promise.timer)
|
||||
// TODO: figure out how to have a better stack trace for an error
|
||||
@@ -93,20 +99,35 @@ export default class RequestManager {
|
||||
newId = request.id
|
||||
}
|
||||
const newRequest = JSON.stringify({ ...request, id: newId })
|
||||
const timer = setTimeout(
|
||||
() => this.reject(newId, new TimeoutError()),
|
||||
timeout,
|
||||
)
|
||||
// Typing required for Jest running in browser
|
||||
const timer: ReturnType<typeof setTimeout> = setTimeout(() => {
|
||||
this.reject(
|
||||
newId,
|
||||
new TimeoutError(
|
||||
`Timeout for request: ${JSON.stringify(request)} with id ${newId}`,
|
||||
request,
|
||||
),
|
||||
)
|
||||
}, timeout)
|
||||
/*
|
||||
* Node.js won't exit if a timer is still running, so we tell Node to ignore.
|
||||
* (Node will still wait for the request to complete).
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Reason above.
|
||||
if (timer.unref) {
|
||||
timer.unref()
|
||||
// The following type assertions are required to get this code to pass in browser environments
|
||||
// where setTimeout has a different type
|
||||
// eslint-disable-next-line max-len -- Necessary to disable both rules.
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access -- Reason above.
|
||||
if ((timer as unknown as any).unref) {
|
||||
// eslint-disable-next-line max-len -- Necessary to disable both rules.
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call -- Reason above.
|
||||
;(timer as unknown as any).unref()
|
||||
}
|
||||
if (this.promisesAwaitingResponse.has(newId)) {
|
||||
throw new XrplError(`Response with id '${newId}' is already pending`)
|
||||
clearTimeout(timer)
|
||||
throw new XrplError(
|
||||
`Response with id '${newId}' is already pending`,
|
||||
request,
|
||||
)
|
||||
}
|
||||
const newPromise = new Promise<Response>(
|
||||
(resolve: (value: Response | PromiseLike<Response>) => void, reject) => {
|
||||
|
||||
@@ -3,13 +3,13 @@ import { EventEmitter } from 'events'
|
||||
|
||||
// Define the global WebSocket class found on the native browser
|
||||
declare class WebSocket {
|
||||
public onclose?: () => void
|
||||
public onopen?: () => void
|
||||
public onclose?: (closeEvent: CloseEvent) => void
|
||||
public onopen?: (openEvent: Event) => void
|
||||
public onerror?: (error: Error) => void
|
||||
public onmessage?: (message: MessageEvent) => void
|
||||
public readyState: number
|
||||
public constructor(url: string)
|
||||
public close(code?: number): void
|
||||
public close(code?: number, reason?: Buffer): void
|
||||
public send(message: string): void
|
||||
}
|
||||
|
||||
@@ -52,8 +52,13 @@ export default class WSWrapper extends EventEmitter {
|
||||
|
||||
this.ws = new WebSocket(url)
|
||||
|
||||
this.ws.onclose = (): void => {
|
||||
this.emit('close')
|
||||
this.ws.onclose = (closeEvent: CloseEvent): void => {
|
||||
let reason: Uint8Array | undefined
|
||||
if (closeEvent.reason) {
|
||||
const enc = new TextEncoder()
|
||||
reason = enc.encode(closeEvent.reason)
|
||||
}
|
||||
this.emit('close', closeEvent.code, reason)
|
||||
}
|
||||
|
||||
this.ws.onopen = (): void => {
|
||||
@@ -71,10 +76,13 @@ export default class WSWrapper extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Closes the websocket.
|
||||
*
|
||||
* @param code - Close code.
|
||||
* @param reason - Close reason.
|
||||
*/
|
||||
public close(): void {
|
||||
public close(code?: number, reason?: Buffer): void {
|
||||
if (this.readyState === 1) {
|
||||
this.ws.close()
|
||||
this.ws.close(code, reason)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable max-lines -- Connection is a large file w/ lots of imports/exports */
|
||||
|
||||
import { EventEmitter } from 'events'
|
||||
import { Agent } from 'http'
|
||||
|
||||
import _ from 'lodash'
|
||||
import omitBy from 'lodash/omitBy'
|
||||
import WebSocket from 'ws'
|
||||
|
||||
import {
|
||||
@@ -63,7 +64,7 @@ function getAgent(url: string, config: ConnectionOptions): Agent | undefined {
|
||||
const parsedURL = new URL(url)
|
||||
const parsedProxyURL = new URL(config.proxy)
|
||||
|
||||
const proxyOptions = _.omitBy(
|
||||
const proxyOptions = omitBy(
|
||||
{
|
||||
secureEndpoint: parsedURL.protocol === 'wss:',
|
||||
secureProxy: parsedProxyURL.protocol === 'https:',
|
||||
@@ -125,7 +126,7 @@ function createWebSocket(
|
||||
Authorization: `Basic ${base64}`,
|
||||
}
|
||||
}
|
||||
const optionsOverrides = _.omitBy(
|
||||
const optionsOverrides = omitBy(
|
||||
{
|
||||
ca: config.trustedCertificates,
|
||||
key: config.key,
|
||||
@@ -175,8 +176,10 @@ async function websocketSendAsync(
|
||||
export class Connection extends EventEmitter {
|
||||
private readonly url: string | undefined
|
||||
private ws: WebSocket | null = null
|
||||
private reconnectTimeoutID: null | NodeJS.Timeout = null
|
||||
private heartbeatIntervalID: null | NodeJS.Timeout = null
|
||||
// Typing necessary for Jest tests running in browser
|
||||
private reconnectTimeoutID: null | ReturnType<typeof setTimeout> = null
|
||||
// Typing necessary for Jest tetsts running in browser
|
||||
private heartbeatIntervalID: null | ReturnType<typeof setTimeout> = null
|
||||
private readonly retryConnectionBackoff = new ExponentialBackoff({
|
||||
min: 100,
|
||||
max: SECONDS_PER_MINUTE * 1000,
|
||||
@@ -224,6 +227,7 @@ export class Connection extends EventEmitter {
|
||||
* @returns When the websocket is connected.
|
||||
* @throws ConnectionError if there is a connection error, RippleError if there is already a WebSocket in existence.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function -- Necessary
|
||||
public async connect(): Promise<void> {
|
||||
if (this.isConnected()) {
|
||||
return Promise.resolve()
|
||||
@@ -245,14 +249,17 @@ export class Connection extends EventEmitter {
|
||||
}
|
||||
|
||||
// Create the connection timeout, in case the connection hangs longer than expected.
|
||||
const connectionTimeoutID = setTimeout(() => {
|
||||
this.onConnectionFailed(
|
||||
new ConnectionError(
|
||||
`Error: connect() timed out after ${this.config.connectionTimeout} ms. If your internet connection is working, the ` +
|
||||
`rippled server may be blocked or inaccessible. You can also try setting the 'connectionTimeout' option in the Client constructor.`,
|
||||
),
|
||||
)
|
||||
}, this.config.connectionTimeout)
|
||||
const connectionTimeoutID: ReturnType<typeof setTimeout> = setTimeout(
|
||||
() => {
|
||||
this.onConnectionFailed(
|
||||
new ConnectionError(
|
||||
`Error: connect() timed out after ${this.config.connectionTimeout} ms. If your internet connection is working, the ` +
|
||||
`rippled server may be blocked or inaccessible. You can also try setting the 'connectionTimeout' option in the Client constructor.`,
|
||||
),
|
||||
)
|
||||
},
|
||||
this.config.connectionTimeout,
|
||||
)
|
||||
// Connection listeners: these stay attached only until a connection is done/open.
|
||||
this.ws = createWebSocket(this.url, this.config)
|
||||
|
||||
@@ -337,7 +344,7 @@ export class Connection extends EventEmitter {
|
||||
timeout?: number,
|
||||
): Promise<unknown> {
|
||||
if (!this.shouldBeConnected || this.ws == null) {
|
||||
throw new NotConnectedError()
|
||||
throw new NotConnectedError(JSON.stringify(request), request)
|
||||
}
|
||||
const [id, message, responsePromise] = this.requestManager.createRequest(
|
||||
request,
|
||||
@@ -429,7 +436,9 @@ export class Connection extends EventEmitter {
|
||||
* @throws Error if the websocket initialized is somehow null.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function -- Many error code conditionals to check.
|
||||
private async onceOpen(connectionTimeoutID: NodeJS.Timeout): Promise<void> {
|
||||
private async onceOpen(
|
||||
connectionTimeoutID: ReturnType<typeof setTimeout>,
|
||||
): Promise<void> {
|
||||
if (this.ws == null) {
|
||||
throw new XrplError('onceOpen: ws is null')
|
||||
}
|
||||
@@ -458,13 +467,14 @@ export class Connection extends EventEmitter {
|
||||
this.ws = null
|
||||
|
||||
if (code === undefined) {
|
||||
const reasonText = reason ? reason.toString() : 'undefined'
|
||||
// eslint-disable-next-line no-console -- The error is helpful for debugging.
|
||||
console.error(
|
||||
`Disconnected but the disconnect code was undefined (The given reason was ${reasonText}).` +
|
||||
`This could be caused by an exception being thrown during a 'connect' callback. ` +
|
||||
`Disconnecting with code 1011 to indicate an internal error has occurred.`,
|
||||
)
|
||||
// Useful to keep this code for debugging purposes.
|
||||
// const reasonText = reason ? reason.toString() : 'undefined'
|
||||
// // eslint-disable-next-line no-console -- The error is helpful for debugging.
|
||||
// console.error(
|
||||
// `Disconnected but the disconnect code was undefined (The given reason was ${reasonText}).` +
|
||||
// `This could be caused by an exception being thrown during a 'connect' callback. ` +
|
||||
// `Disconnecting with code 1011 to indicate an internal error has occurred.`,
|
||||
// )
|
||||
|
||||
/*
|
||||
* Error code 1011 represents an Internal Error according to
|
||||
|
||||
@@ -454,6 +454,10 @@ class Client extends EventEmitter {
|
||||
event: 'consensusPhase',
|
||||
listener: (phase: ConsensusStream) => void,
|
||||
): this
|
||||
public on(
|
||||
event: 'manifestReceived',
|
||||
listener: (manifest: ManifestResponse) => void,
|
||||
): this
|
||||
public on(event: 'path_find', listener: (path: PathFindStream) => void): this
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- needs to be any for overload
|
||||
public on(event: 'error', listener: (...err: any[]) => void): this
|
||||
|
||||
@@ -108,6 +108,10 @@ export interface ResponseOnlyTxInfo {
|
||||
* The sequence number of the ledger that included this transaction.
|
||||
*/
|
||||
ledger_index?: number
|
||||
/**
|
||||
* @deprecated Alias for ledger_index.
|
||||
*/
|
||||
inLedger?: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,7 +49,7 @@ export interface LedgerDataRequest extends BaseRequest {
|
||||
|
||||
type LabeledLedgerEntry = { ledgerEntryType: string } & LedgerEntry
|
||||
|
||||
interface BinaryLedgerEntry {
|
||||
export interface BinaryLedgerEntry {
|
||||
data: string
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,14 @@ export interface JobType {
|
||||
in_progress?: number
|
||||
}
|
||||
|
||||
// The states for validating and proposing do not exist in the field state_accounting
|
||||
// See https://github.com/XRPLF/rippled/blob/develop/src/ripple/app/misc/NetworkOPs.cpp#L4545
|
||||
// https://github.com/XRPLF/rippled/blob/develop/src/ripple/app/misc/NetworkOPs.h#L66
|
||||
export type StateAccountingFinal = Record<
|
||||
Exclude<ServerState, 'validating' | 'proposing'>,
|
||||
StateAccounting
|
||||
>
|
||||
|
||||
/**
|
||||
* Response expected from a {@link ServerInfoRequest}.
|
||||
*
|
||||
@@ -158,6 +166,14 @@ export interface ServerInfoResponse extends BaseResponse {
|
||||
* cost.
|
||||
*/
|
||||
load_factor_server?: number
|
||||
/**
|
||||
* The number of peer connections which were severed.
|
||||
*/
|
||||
peer_disconnects?: string
|
||||
/**
|
||||
* The number of peer connections which were severed due to excess resource consumption.
|
||||
*/
|
||||
peer_disconnects_resources?: string
|
||||
network_ledger?: 'waiting'
|
||||
/** How many other rippled servers this one is currently connected to. */
|
||||
peers: number
|
||||
@@ -179,13 +195,13 @@ export interface ServerInfoResponse extends BaseResponse {
|
||||
* The number of consecutive microseconds the server has been in the
|
||||
* current state.
|
||||
*/
|
||||
server_state_duration_us: number
|
||||
server_state_duration_us: string
|
||||
/**
|
||||
* A map of various server states with information about the time the
|
||||
* server spends in each. This can be useful for tracking the long-term
|
||||
* health of your server's connectivity to the network.
|
||||
*/
|
||||
state_accounting: Record<ServerState, StateAccounting>
|
||||
state_accounting: StateAccountingFinal
|
||||
/** The current time in UTC, according to the server's clock. */
|
||||
time: string
|
||||
/** Number of consecutive seconds that the server has been operational. */
|
||||
@@ -227,6 +243,11 @@ export interface ServerInfoResponse extends BaseResponse {
|
||||
* static validator list.
|
||||
*/
|
||||
validator_list_expires?: string
|
||||
validator_list?: {
|
||||
count: number
|
||||
expiration: 'never' | 'unknown' | string
|
||||
status: 'active' | 'expired' | 'unknown'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BaseRequest, BaseResponse } from './baseMethod'
|
||||
import { JobType, ServerState, StateAccounting } from './serverInfo'
|
||||
import { JobType, ServerState, StateAccountingFinal } from './serverInfo'
|
||||
|
||||
/**
|
||||
* The `server_state` command asks the server for various machine-readable
|
||||
@@ -35,7 +35,10 @@ export interface ServerStateResponse extends BaseResponse {
|
||||
io_latency_ms: number
|
||||
jq_trans_overflow: string
|
||||
last_close: {
|
||||
converge_time_s: number
|
||||
// coverage_time_s only exists for `server_info` requests. `server_state` is a "non human" api request,
|
||||
// therefore the type is coverage_time
|
||||
// See https://github.com/XRPLF/rippled/blob/83faf43140e27e5d6d6779eaa0ffb75c33d98029/src/ripple/app/misc/NetworkOPs.cpp#L2458
|
||||
converge_time: number
|
||||
proposers: number
|
||||
}
|
||||
load?: {
|
||||
@@ -48,24 +51,27 @@ export interface ServerStateResponse extends BaseResponse {
|
||||
load_factor_fee_queue?: number
|
||||
load_factor_fee_reference?: number
|
||||
load_factor_server?: number
|
||||
peer_disconnects?: string
|
||||
peer_disconnects_resources?: string
|
||||
peers: number
|
||||
pubkey_node: string
|
||||
pubkey_validator?: string
|
||||
server_state: ServerState
|
||||
server_state_duration_us: number
|
||||
state_accounting: Record<ServerState, StateAccounting>
|
||||
server_state_duration_us: string
|
||||
state_accounting: StateAccountingFinal
|
||||
time: string
|
||||
uptime: number
|
||||
validated_ledger?: {
|
||||
age: number
|
||||
age?: number
|
||||
base_fee: number
|
||||
close_time: number
|
||||
hash: string
|
||||
reserve_base: number
|
||||
reserve_inc: number
|
||||
seq: number
|
||||
}
|
||||
validation_quorum: number
|
||||
validator_list_expires?: string
|
||||
validator_list_expires?: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,12 +53,14 @@ export function validateCheckCash(tx: Record<string, unknown>): void {
|
||||
)
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Necessary check
|
||||
if (tx.Amount != null && tx.Amount !== undefined && !isAmount(tx.Amount)) {
|
||||
throw new ValidationError('CheckCash: invalid Amount')
|
||||
}
|
||||
|
||||
if (
|
||||
tx.DeliverMin != null &&
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Necessary check
|
||||
tx.DeliverMin !== undefined &&
|
||||
!isAmount(tx.DeliverMin)
|
||||
) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* eslint-disable complexity -- verifies 19 tx types hence a lot of checks needed */
|
||||
/* eslint-disable max-lines-per-function -- need to work with a lot of Tx verifications */
|
||||
|
||||
import _ from 'lodash'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import omitBy from 'lodash/omitBy'
|
||||
import { encode, decode } from 'ripple-binary-codec'
|
||||
|
||||
import { ValidationError } from '../../errors'
|
||||
@@ -210,9 +211,9 @@ export function validate(transaction: Record<string, unknown>): void {
|
||||
}
|
||||
|
||||
if (
|
||||
!_.isEqual(
|
||||
!isEqual(
|
||||
decode(encode(tx)),
|
||||
_.omitBy(tx, (value) => value == null),
|
||||
omitBy(tx, (value) => value == null),
|
||||
)
|
||||
) {
|
||||
throw new ValidationError(`Invalid Transaction: ${tx.TransactionType}`)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import _ from 'lodash'
|
||||
import flatMap from 'lodash/flatMap'
|
||||
|
||||
import type { Client } from '..'
|
||||
import { LedgerIndex } from '../models/common'
|
||||
@@ -111,7 +111,7 @@ async function getBalances(
|
||||
// combine results
|
||||
await Promise.all([xrpPromise, linesPromise]).then(
|
||||
([xrpBalance, linesResponses]) => {
|
||||
const accountLinesBalance = _.flatMap(linesResponses, (response) =>
|
||||
const accountLinesBalance = flatMap(linesResponses, (response) =>
|
||||
formatBalances(response.result.lines),
|
||||
)
|
||||
if (xrpBalance !== '') {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable max-lines-per-function -- Needs to process orderbooks. */
|
||||
import BigNumber from 'bignumber.js'
|
||||
import _ from 'lodash'
|
||||
import flatMap from 'lodash/flatMap'
|
||||
|
||||
import type { Client } from '../client'
|
||||
import { ValidationError } from '../errors'
|
||||
import { LedgerIndex } from '../models/common'
|
||||
import { OfferFlags } from '../models/ledger/Offer'
|
||||
import {
|
||||
@@ -22,6 +23,13 @@ function sortOffers(offers: BookOffer[]): BookOffer[] {
|
||||
})
|
||||
}
|
||||
|
||||
const getOrderbookOptionsSet = new Set([
|
||||
'limit',
|
||||
'ledger_index',
|
||||
'ledger_hash',
|
||||
'taker',
|
||||
])
|
||||
|
||||
/**
|
||||
* Fetch orderbook (buy/sell orders) between two accounts.
|
||||
*
|
||||
@@ -40,7 +48,7 @@ function sortOffers(offers: BookOffer[]): BookOffer[] {
|
||||
* the order book. Defaults to 20.
|
||||
* @returns An object containing buy and sell objects.
|
||||
*/
|
||||
// eslint-disable-next-line max-params -- Once bound to Client, getOrderbook only has 3 parameters.
|
||||
// eslint-disable-next-line max-params, complexity -- Once bound to Client, getOrderbook only has 3 parameters.
|
||||
async function getOrderbook(
|
||||
this: Client,
|
||||
takerPays: TakerAmount,
|
||||
@@ -48,21 +56,60 @@ async function getOrderbook(
|
||||
options: {
|
||||
limit?: number
|
||||
ledger_index?: LedgerIndex
|
||||
ledger_hash?: string
|
||||
taker?: string
|
||||
ledger_hash?: string | null
|
||||
taker?: string | null
|
||||
} = {},
|
||||
): Promise<{
|
||||
buy: BookOffer[]
|
||||
sell: BookOffer[]
|
||||
}> {
|
||||
Object.keys(options).forEach((key) => {
|
||||
if (!getOrderbookOptionsSet.has(key)) {
|
||||
throw new ValidationError(`Unexpected option: ${key}`, options)
|
||||
}
|
||||
})
|
||||
|
||||
if (options.limit && typeof options.limit !== 'number') {
|
||||
throw new ValidationError('limit must be a number', options.limit)
|
||||
}
|
||||
|
||||
if (
|
||||
options.ledger_index &&
|
||||
!(
|
||||
typeof options.ledger_index === 'number' ||
|
||||
(typeof options.ledger_index === 'string' &&
|
||||
['validated', 'closed', 'current'].includes(options.ledger_index))
|
||||
)
|
||||
) {
|
||||
throw new ValidationError(
|
||||
'ledger_index must be a number or a string of "validated", "closed", or "current"',
|
||||
options.ledger_index,
|
||||
)
|
||||
}
|
||||
|
||||
if (
|
||||
options.ledger_hash !== undefined &&
|
||||
options.ledger_hash !== null &&
|
||||
typeof options.ledger_hash !== 'string'
|
||||
) {
|
||||
throw new ValidationError(
|
||||
'ledger_hash must be a string',
|
||||
options.ledger_hash,
|
||||
)
|
||||
}
|
||||
|
||||
if (options.taker !== undefined && typeof options.taker !== 'string') {
|
||||
throw new ValidationError('taker must be a string', options.taker)
|
||||
}
|
||||
|
||||
const request: BookOffersRequest = {
|
||||
command: 'book_offers',
|
||||
taker_pays: takerPays,
|
||||
taker_gets: takerGets,
|
||||
ledger_index: options.ledger_index ?? 'validated',
|
||||
ledger_hash: options.ledger_hash,
|
||||
ledger_hash: options.ledger_hash === null ? undefined : options.ledger_hash,
|
||||
limit: options.limit ?? DEFAULT_LIMIT,
|
||||
taker: options.taker,
|
||||
taker: options.taker ? options.taker : undefined,
|
||||
}
|
||||
// 2. Make Request
|
||||
const directOfferResults = await this.requestAll(request)
|
||||
@@ -70,11 +117,11 @@ async function getOrderbook(
|
||||
request.taker_pays = takerGets
|
||||
const reverseOfferResults = await this.requestAll(request)
|
||||
// 3. Return Formatted Response
|
||||
const directOffers = _.flatMap(
|
||||
const directOffers = flatMap(
|
||||
directOfferResults,
|
||||
(directOfferResult) => directOfferResult.result.offers,
|
||||
)
|
||||
const reverseOffers = _.flatMap(
|
||||
const reverseOffers = flatMap(
|
||||
reverseOfferResults,
|
||||
(reverseOfferResult) => reverseOfferResult.result.offers,
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import _ from 'lodash'
|
||||
import flatten from 'lodash/flatten'
|
||||
import groupBy from 'lodash/groupBy'
|
||||
|
||||
import { Amount, IssuedCurrencyAmount } from '../models/common'
|
||||
import { TransactionMetadata, Node } from '../models/transactions/metadata'
|
||||
@@ -63,7 +64,7 @@ function groupByAccount(balanceChanges: BalanceChange[]): Array<{
|
||||
account: string
|
||||
balances: Balance[]
|
||||
}> {
|
||||
const grouped = _.groupBy(balanceChanges, (node) => node.account)
|
||||
const grouped = groupBy(balanceChanges, (node) => node.account)
|
||||
return Object.entries(grouped).map(([account, items]) => {
|
||||
return { account, balances: items.map((item) => item.balance) }
|
||||
})
|
||||
@@ -186,5 +187,5 @@ export default function getBalanceChanges(
|
||||
}
|
||||
return []
|
||||
})
|
||||
return groupByAccount(_.flatten(quantities))
|
||||
return groupByAccount(flatten(quantities))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import binary from 'ripple-binary-codec'
|
||||
import keypairs from 'ripple-keypairs'
|
||||
import { encodeForSigningClaim } from 'ripple-binary-codec'
|
||||
import { sign } from 'ripple-keypairs'
|
||||
|
||||
import { xrpToDrops } from './xrpConversion'
|
||||
|
||||
@@ -17,11 +17,11 @@ function signPaymentChannelClaim(
|
||||
amount: string,
|
||||
privateKey: string,
|
||||
): string {
|
||||
const signingData = binary.encodeForSigningClaim({
|
||||
const signingData = encodeForSigningClaim({
|
||||
channel,
|
||||
amount: xrpToDrops(amount),
|
||||
})
|
||||
return keypairs.sign(signingData, privateKey)
|
||||
return sign(signingData, privateKey)
|
||||
}
|
||||
|
||||
export default signPaymentChannelClaim
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import binary from 'ripple-binary-codec'
|
||||
import keypairs from 'ripple-keypairs'
|
||||
import { encodeForSigningClaim } from 'ripple-binary-codec'
|
||||
import { verify } from 'ripple-keypairs'
|
||||
|
||||
import { xrpToDrops } from './xrpConversion'
|
||||
|
||||
@@ -20,11 +20,11 @@ function verifyPaymentChannelClaim(
|
||||
signature: string,
|
||||
publicKey: string,
|
||||
): boolean {
|
||||
const signingData = binary.encodeForSigningClaim({
|
||||
const signingData = encodeForSigningClaim({
|
||||
channel,
|
||||
amount: xrpToDrops(amount),
|
||||
})
|
||||
return keypairs.verify(signingData, signature, publicKey)
|
||||
return verify(signingData, signature, publicKey)
|
||||
}
|
||||
|
||||
export default verifyPaymentChannelClaim
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { assert } from 'chai'
|
||||
import ExponentialBackoff from 'xrpl-local/client/ExponentialBackoff'
|
||||
|
||||
import ExponentialBackoff from '../src/client/ExponentialBackoff'
|
||||
|
||||
describe('ExponentialBackoff', function () {
|
||||
it('duration() return value starts with the min value', function () {
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { ServerInfoResponse } from 'xrpl-local'
|
||||
|
||||
import responses from './fixtures/responses'
|
||||
import rippled from './fixtures/rippled'
|
||||
import { setupBroadcast, teardownClient } from './setupClient'
|
||||
import { assertResultMatch, ignoreWebSocketDisconnect } from './testUtils'
|
||||
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('BroadcastClient', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
beforeEach(setupBroadcast)
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
this.mocks.forEach((mock) => {
|
||||
mock.addResponse('server_info', rippled.server_info.normal)
|
||||
})
|
||||
assert(this.client.isConnected())
|
||||
this.client
|
||||
.request({ command: 'server_info' })
|
||||
.then((response: ServerInfoResponse) => {
|
||||
assertResultMatch(responses.getServerInfo, response.result.info)
|
||||
})
|
||||
})
|
||||
|
||||
it('error propagation', function (done) {
|
||||
const data = { error: 'type', error_message: 'info' }
|
||||
this.mocks.forEach((mock) => {
|
||||
mock.addResponse('echo', data)
|
||||
})
|
||||
this.client.once('error', (type, info) => {
|
||||
assert.strictEqual(type, 'type')
|
||||
assert.strictEqual(info, 'info')
|
||||
done()
|
||||
})
|
||||
this.client.clients[1].connection
|
||||
.request({
|
||||
command: 'echo',
|
||||
data,
|
||||
})
|
||||
.catch(ignoreWebSocketDisconnect)
|
||||
})
|
||||
})
|
||||
@@ -1,101 +0,0 @@
|
||||
/* eslint-disable no-console -- Logging out errors. */
|
||||
import path from 'path'
|
||||
|
||||
import { expect, assert } from 'chai'
|
||||
import puppeteer from 'puppeteer'
|
||||
|
||||
const TIMEOUT = 150000
|
||||
interface TestCaseInfo {
|
||||
name: string
|
||||
span: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
function getCountAndDisplayError(result): number {
|
||||
let count = 0
|
||||
for (const testCase of result.test) {
|
||||
if (Object.prototype.hasOwnProperty.call(testCase, 'error')) {
|
||||
count += 1
|
||||
console.log(
|
||||
`${count})`,
|
||||
result.type,
|
||||
JSON.stringify(testCase, null, '\t'),
|
||||
)
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
describe('Browser Tests', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
it('Integration Tests', async function () {
|
||||
const browser = await puppeteer.launch({ headless: true })
|
||||
let mocha_results
|
||||
try {
|
||||
const page = await browser.newPage().catch()
|
||||
page.setDefaultNavigationTimeout(0)
|
||||
|
||||
await page.goto(
|
||||
path.join('file:///', __dirname, '../localIntegrationRunner.html'),
|
||||
)
|
||||
|
||||
await page.waitForFunction(
|
||||
'document.querySelector("body").innerText.includes("closing test")',
|
||||
{ timeout: TIMEOUT },
|
||||
)
|
||||
|
||||
mocha_results = await page.evaluate(() => {
|
||||
const results: Array<{ type: string; test: TestCaseInfo[] }> = []
|
||||
const items = document.querySelectorAll('.suite')
|
||||
items.forEach((item) => {
|
||||
const tests = item.querySelectorAll('li')
|
||||
const cases: TestCaseInfo[] = []
|
||||
tests.forEach((testCase) => {
|
||||
cases.push({
|
||||
name: testCase.querySelector('h2')?.outerText as string,
|
||||
span: testCase.querySelector('.duration')?.textContent as string,
|
||||
error: testCase.querySelector('.error')?.textContent as string,
|
||||
})
|
||||
})
|
||||
results.push({
|
||||
type: item.querySelector('h1')!.textContent as string,
|
||||
test: cases,
|
||||
})
|
||||
})
|
||||
return results
|
||||
})
|
||||
|
||||
const fails = await page.evaluate(() => {
|
||||
const element = document.querySelector('.failures')
|
||||
|
||||
return element == null ? null : element.textContent
|
||||
})
|
||||
const passes = await page.evaluate(() => {
|
||||
const element = document.querySelector('.passes')
|
||||
|
||||
return element == null ? null : element.textContent
|
||||
})
|
||||
|
||||
expect(fails).to.equal('failures: 0')
|
||||
expect(passes).to.not.equal('passes: 0')
|
||||
} catch {
|
||||
// '\x1b[31m' specifies that console text will be displayed in color red here on.
|
||||
console.log('\x1b[31m', 'Failed Tests:')
|
||||
let count = 0
|
||||
for (const result of mocha_results) {
|
||||
count += getCountAndDisplayError(result)
|
||||
}
|
||||
// '\x1b[0m' specifies that console text color will be reset.
|
||||
console.log(
|
||||
`Total ${count} test${count === 1 ? '' : 's'} failed. \n`,
|
||||
'\x1b[0m',
|
||||
)
|
||||
|
||||
// we would always want the number of failing tests to be zero.
|
||||
assert.equal(0, count)
|
||||
} finally {
|
||||
await browser.close()
|
||||
}
|
||||
}).timeout(TIMEOUT)
|
||||
})
|
||||
@@ -1,37 +0,0 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { Client } from 'xrpl-local'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('Client', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
it('Client - implicit server port', function () {
|
||||
// eslint-disable-next-line no-new -- Need to test constructor
|
||||
new Client('wss://s1.ripple.com')
|
||||
})
|
||||
|
||||
it('Client invalid options', function () {
|
||||
// @ts-expect-error - This is intentionally invalid
|
||||
assert.throws(() => new Client({ invalid: true }))
|
||||
})
|
||||
|
||||
it('Client valid options', function () {
|
||||
const client = new Client('wss://s:1')
|
||||
const privateConnectionUrl = client.url
|
||||
assert.deepEqual(privateConnectionUrl, 'wss://s:1')
|
||||
})
|
||||
|
||||
it('Client invalid server uri', function () {
|
||||
assert.throws(() => new Client('wss//s:1'))
|
||||
})
|
||||
|
||||
it('Client connect() times out after 2 seconds', function () {
|
||||
/*
|
||||
* TODO: Use a timer mock like https://jestjs.io/docs/en/timer-mocks
|
||||
* to test that connect() times out after 2 seconds.
|
||||
*/
|
||||
})
|
||||
})
|
||||
@@ -1,14 +1,18 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import {
|
||||
XrplError,
|
||||
AccountDelete,
|
||||
EscrowFinish,
|
||||
Payment,
|
||||
Transaction,
|
||||
} from 'xrpl-local'
|
||||
|
||||
} from '../../src'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
import { assertRejects } from '../testUtils'
|
||||
|
||||
const Fee = '10'
|
||||
@@ -16,8 +20,12 @@ const Sequence = 1432
|
||||
const LastLedgerSequence = 2908734
|
||||
|
||||
describe('client.autofill', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('should not autofill if fields are present', async function () {
|
||||
const tx: Transaction = {
|
||||
@@ -28,7 +36,7 @@ describe('client.autofill', function () {
|
||||
Sequence,
|
||||
LastLedgerSequence,
|
||||
}
|
||||
const txResult = await this.client.autofill(tx)
|
||||
const txResult = await testContext.client.autofill(tx)
|
||||
|
||||
assert.strictEqual(txResult.Fee, Fee)
|
||||
assert.strictEqual(txResult.Sequence, Sequence)
|
||||
@@ -42,11 +50,17 @@ describe('client.autofill', function () {
|
||||
Amount: '1234',
|
||||
Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
|
||||
const txResult = await this.client.autofill(tx)
|
||||
const txResult = await testContext.client.autofill(tx)
|
||||
|
||||
assert.strictEqual(txResult.Account, 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf')
|
||||
assert.strictEqual(
|
||||
@@ -63,7 +77,7 @@ describe('client.autofill', function () {
|
||||
Fee,
|
||||
LastLedgerSequence,
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', {
|
||||
testContext.mockRippled!.addResponse('account_info', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
@@ -72,16 +86,22 @@ describe('client.autofill', function () {
|
||||
},
|
||||
},
|
||||
})
|
||||
const txResult = await this.client.autofill(tx)
|
||||
const txResult = await testContext.client.autofill(tx)
|
||||
|
||||
assert.strictEqual(txResult.Sequence, 23)
|
||||
})
|
||||
|
||||
it('should throw error if account deletion blockers exist', async function () {
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_objects',
|
||||
rippled.account_objects.normal,
|
||||
)
|
||||
@@ -95,7 +115,7 @@ describe('client.autofill', function () {
|
||||
LastLedgerSequence,
|
||||
}
|
||||
|
||||
await assertRejects(this.client.autofill(tx), XrplError)
|
||||
await assertRejects(testContext.client.autofill(tx), XrplError)
|
||||
})
|
||||
|
||||
describe('when autofill Fee is missing', function () {
|
||||
@@ -107,8 +127,11 @@ describe('client.autofill', function () {
|
||||
Sequence,
|
||||
LastLedgerSequence,
|
||||
}
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
const txResult = await this.client.autofill(tx)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
const txResult = await testContext.client.autofill(tx)
|
||||
|
||||
assert.strictEqual(txResult.Fee, '12')
|
||||
})
|
||||
@@ -123,11 +146,17 @@ describe('client.autofill', function () {
|
||||
'A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100',
|
||||
Fulfillment: 'A0028000',
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
|
||||
const txResult = await this.client.autofill(tx)
|
||||
const txResult = await testContext.client.autofill(tx)
|
||||
assert.strictEqual(txResult.Fee, '399')
|
||||
})
|
||||
|
||||
@@ -137,9 +166,12 @@ describe('client.autofill', function () {
|
||||
TransactionType: 'AccountDelete',
|
||||
Destination: 'X7AcgcsBL6XDcUb289X4mJ8djcdyKaB5hJDWMArnXr61cqZ',
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_state', {
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse('server_state', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
@@ -150,12 +182,15 @@ describe('client.autofill', function () {
|
||||
},
|
||||
},
|
||||
})
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_objects',
|
||||
rippled.account_objects.empty,
|
||||
)
|
||||
const txResult = await this.client.autofill(tx)
|
||||
const txResult = await testContext.client.autofill(tx)
|
||||
|
||||
assert.strictEqual(txResult.Fee, '2000000')
|
||||
})
|
||||
@@ -170,10 +205,16 @@ describe('client.autofill', function () {
|
||||
'A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100',
|
||||
Fulfillment: 'A0028000',
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
const txResult = await this.client.autofill(tx, 4)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
const txResult = await testContext.client.autofill(tx, 4)
|
||||
|
||||
assert.strictEqual(txResult.Fee, '459')
|
||||
})
|
||||
@@ -187,14 +228,14 @@ describe('client.autofill', function () {
|
||||
Fee,
|
||||
Sequence,
|
||||
}
|
||||
this.mockRippled.addResponse('ledger', {
|
||||
testContext.mockRippled!.addResponse('ledger', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_index: 9038214,
|
||||
},
|
||||
})
|
||||
const txResult = await this.client.autofill(tx)
|
||||
const txResult = await testContext.client.autofill(tx)
|
||||
assert.strictEqual(txResult.LastLedgerSequence, 9038234)
|
||||
})
|
||||
|
||||
@@ -204,7 +245,7 @@ describe('client.autofill', function () {
|
||||
Account: 'rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf',
|
||||
Authorize: 'rpZc4mVfWUif9CRoHRKKcmhu1nx2xktxBo',
|
||||
}
|
||||
this.mockRippled.addResponse('account_info', {
|
||||
testContext.mockRippled!.addResponse('account_info', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
@@ -213,14 +254,14 @@ describe('client.autofill', function () {
|
||||
},
|
||||
},
|
||||
})
|
||||
this.mockRippled.addResponse('ledger', {
|
||||
testContext.mockRippled!.addResponse('ledger', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_index: 9038214,
|
||||
},
|
||||
})
|
||||
this.mockRippled.addResponse('server_info', {
|
||||
testContext.mockRippled!.addResponse('server_info', {
|
||||
status: 'success',
|
||||
type: 'response',
|
||||
result: {
|
||||
@@ -231,7 +272,7 @@ describe('client.autofill', function () {
|
||||
},
|
||||
},
|
||||
})
|
||||
const txResult = await this.client.autofill(tx)
|
||||
const txResult = await testContext.client.autofill(tx)
|
||||
assert.strictEqual(txResult.Fee, '12')
|
||||
assert.strictEqual(txResult.Sequence, 23)
|
||||
assert.strictEqual(txResult.LastLedgerSequence, 9038234)
|
||||
|
||||
55
packages/xrpl/test/client/client.test.ts
Normal file
55
packages/xrpl/test/client/client.test.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { Client } from '../../src'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('Client', function () {
|
||||
it(
|
||||
'Client - implicit server port',
|
||||
() => {
|
||||
// eslint-disable-next-line no-new -- Need to test constructor
|
||||
new Client('wss://s1.ripple.com')
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'Client invalid options',
|
||||
() => {
|
||||
// @ts-expect-error - This is intentionally invalid
|
||||
assert.throws(() => new Client({ invalid: true }))
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'Client valid options',
|
||||
() => {
|
||||
const client = new Client('wss://s:1')
|
||||
const privateConnectionUrl = client.url
|
||||
assert.deepEqual(privateConnectionUrl, 'wss://s:1')
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'Client invalid server uri',
|
||||
() => {
|
||||
assert.throws(() => new Client('wss//s:1'))
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
// it(
|
||||
// 'Client connect() times out after 2 seconds',
|
||||
// () => {
|
||||
// /*
|
||||
// * TODO: Use a timer mock like https://jestjs.io/docs/en/timer-mocks
|
||||
// * to test that connect() times out after 2 seconds.
|
||||
// */
|
||||
// },
|
||||
// TIMEOUT,
|
||||
// )
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import { assert } from 'chai'
|
||||
import { Client } from 'xrpl-local'
|
||||
|
||||
import { Client } from '../../src/client'
|
||||
|
||||
describe('client constructor', function () {
|
||||
it('Client - implicit server port', function () {
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { assert } from 'chai'
|
||||
import { XrplError, NotFoundError } from 'xrpl-local'
|
||||
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import { XrplError, NotFoundError } from '../../src'
|
||||
|
||||
describe('client errors', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('XrplError with data', async function () {
|
||||
const error = new XrplError('_message_', '_data_')
|
||||
assert.strictEqual(error.toString(), "[XrplError(_message_, '_data_')]")
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import rippledAccountLines from '../fixtures/rippled/accountLines'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
import { assertResultMatch, addressTests } from '../testUtils'
|
||||
|
||||
/**
|
||||
@@ -10,22 +14,26 @@ import { assertResultMatch, addressTests } from '../testUtils'
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
describe('client.getBalances', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
addressTests.forEach(function (testcase) {
|
||||
describe(testcase.type, function () {
|
||||
describe(testcase.type, () => {
|
||||
it('getBalances - base', async function () {
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_lines',
|
||||
rippledAccountLines.normal,
|
||||
)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
const result = await this.client.getBalances(testcase.address)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
const result = await testContext.client.getBalances(testcase.address)
|
||||
assertResultMatch(result, responses.getBalances, 'getBalances')
|
||||
})
|
||||
|
||||
@@ -36,20 +44,20 @@ describe('client.getBalances', function () {
|
||||
limit: 10,
|
||||
},
|
||||
}
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_lines',
|
||||
rippledAccountLines.normal,
|
||||
)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
const expectedResponse = responses.getBalances.slice(
|
||||
0,
|
||||
request.options.limit,
|
||||
)
|
||||
const result = await this.client.getBalances(
|
||||
const result = await testContext.client.getBalances(
|
||||
request.account,
|
||||
request.options,
|
||||
)
|
||||
@@ -60,20 +68,23 @@ describe('client.getBalances', function () {
|
||||
const options = {
|
||||
peer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
}
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_lines',
|
||||
rippledAccountLines.normal,
|
||||
)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
|
||||
const expectedResponse = responses.getBalances.filter(
|
||||
(item) => item.issuer === options.peer,
|
||||
)
|
||||
const result = await this.client.getBalances(testcase.address, options)
|
||||
const result = await testContext.client.getBalances(
|
||||
testcase.address,
|
||||
options,
|
||||
)
|
||||
assertResultMatch(result, expectedResponse, 'getBalances')
|
||||
})
|
||||
|
||||
@@ -82,20 +93,23 @@ describe('client.getBalances', function () {
|
||||
peer: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
limit: 10,
|
||||
}
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_lines',
|
||||
rippledAccountLines.normal,
|
||||
)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
|
||||
const expectedResponse = responses.getBalances
|
||||
.filter((item) => item.issuer === options.peer)
|
||||
.slice(0, options.limit)
|
||||
const result = await this.client.getBalances(testcase.address, options)
|
||||
const result = await testContext.client.getBalances(
|
||||
testcase.address,
|
||||
options,
|
||||
)
|
||||
assertResultMatch(result, expectedResponse, 'getBalances')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,29 +2,40 @@ import { assert } from 'chai'
|
||||
|
||||
import getFeeXrp from '../../src/sugar/getFeeXrp'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
|
||||
describe('getFeeXrp', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('getFeeXrp', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
const fee = await getFeeXrp(this.client)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
const fee = await getFeeXrp(testContext.client)
|
||||
assert.strictEqual(fee, '0.000012')
|
||||
})
|
||||
|
||||
it('getFeeXrp - high load_factor', async function () {
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.highLoadFactor,
|
||||
)
|
||||
const fee = await getFeeXrp(this.client)
|
||||
const fee = await getFeeXrp(testContext.client)
|
||||
assert.strictEqual(fee, '2')
|
||||
})
|
||||
|
||||
it('getFeeXrp - high load_factor with custom maxFeeXRP', async function () {
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.highLoadFactor,
|
||||
)
|
||||
@@ -33,15 +44,20 @@ describe('getFeeXrp', function () {
|
||||
* Ensure that overriding with high maxFeeXRP of '51540' causes no errors.
|
||||
* (fee will actually be 51539.607552)
|
||||
*/
|
||||
this.client.maxFeeXRP = '51540'
|
||||
const fee = await getFeeXrp(this.client)
|
||||
// @ts-expect-error Manually setting this for the purpose of testing
|
||||
testContext.client.maxFeeXRP = '51540'
|
||||
const fee = await getFeeXrp(testContext.client)
|
||||
assert.strictEqual(fee, '51539.607552')
|
||||
})
|
||||
|
||||
it('getFeeXrp custom cushion', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.client.feeCushion = 1.4
|
||||
const fee = await getFeeXrp(this.client)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
// @ts-expect-error Manually setting this for the purpose of testing
|
||||
testContext.client.feeCushion = 1.4
|
||||
const fee = await getFeeXrp(testContext.client)
|
||||
assert.strictEqual(fee, '0.000014')
|
||||
})
|
||||
|
||||
@@ -50,15 +66,22 @@ describe('getFeeXrp', function () {
|
||||
* less than the base fee. However, this test verifies the existing behavior.
|
||||
*/
|
||||
it('getFeeXrp cushion less than 1.0', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.client.feeCushion = 0.9
|
||||
const fee = await getFeeXrp(this.client)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
// @ts-expect-error Manually setting this for the purpose of testing
|
||||
testContext.client.feeCushion = 0.9
|
||||
const fee = await getFeeXrp(testContext.client)
|
||||
assert.strictEqual(fee, '0.000009')
|
||||
})
|
||||
|
||||
it('getFeeXrp reporting', async function () {
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
const fee = await getFeeXrp(this.client)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
const fee = await getFeeXrp(testContext.client)
|
||||
assert.strictEqual(fee, '0.000012')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
|
||||
describe('client.getLedgerIndex', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('getLedgerIndex', async function () {
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
const ledgerIndex = await this.client.getLedgerIndex()
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
const ledgerIndex = await testContext.client.getLedgerIndex()
|
||||
assert.strictEqual(ledgerIndex, 9038214)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import BigNumber from 'bignumber.js'
|
||||
import { assert } from 'chai'
|
||||
import { BookOffersRequest } from 'xrpl-local'
|
||||
import { ValidationError, XrplError } from 'xrpl-local/errors'
|
||||
import { OfferFlags } from 'xrpl-local/models/ledger'
|
||||
|
||||
import { BookOffersRequest, type Request } from '../../src'
|
||||
import { ValidationError, XrplError } from '../../src/errors'
|
||||
import { OfferFlags } from '../../src/models/ledger'
|
||||
import requests from '../fixtures/requests'
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
import { assertResultMatch, assertRejects } from '../testUtils'
|
||||
|
||||
function checkSortingOfOrders(orders): void {
|
||||
@@ -37,42 +41,48 @@ function isBTC(currency: string): boolean {
|
||||
)
|
||||
}
|
||||
|
||||
function normalRippledResponse(
|
||||
request: BookOffersRequest,
|
||||
): Record<string, unknown> {
|
||||
function normalRippledResponse(request: Request): Record<string, unknown> {
|
||||
if (
|
||||
isBTC(request.taker_gets.currency) &&
|
||||
isUSD(request.taker_pays.currency)
|
||||
isBTC((request as BookOffersRequest).taker_gets.currency) &&
|
||||
isUSD((request as BookOffersRequest).taker_pays.currency)
|
||||
) {
|
||||
return rippled.book_offers.fabric.requestBookOffersBidsResponse(request)
|
||||
}
|
||||
if (
|
||||
isUSD(request.taker_gets.currency) &&
|
||||
isBTC(request.taker_pays.currency)
|
||||
isUSD((request as BookOffersRequest).taker_gets.currency) &&
|
||||
isBTC((request as BookOffersRequest).taker_pays.currency)
|
||||
) {
|
||||
return rippled.book_offers.fabric.requestBookOffersAsksResponse(request)
|
||||
}
|
||||
throw new XrplError('unexpected end')
|
||||
}
|
||||
|
||||
function xrpRippledResponse(
|
||||
request: BookOffersRequest,
|
||||
): Record<string, unknown> {
|
||||
if (request.taker_pays.issuer === 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') {
|
||||
function xrpRippledResponse(request: Request): Record<string, unknown> {
|
||||
if (
|
||||
(request as BookOffersRequest).taker_pays.issuer ===
|
||||
'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw'
|
||||
) {
|
||||
return rippled.book_offers.xrp_usd
|
||||
}
|
||||
if (request.taker_gets.issuer === 'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw') {
|
||||
if (
|
||||
(request as BookOffersRequest).taker_gets.issuer ===
|
||||
'rp8rJYTpodf8qbSCHVTNacf8nSW8mRakFw'
|
||||
) {
|
||||
return rippled.book_offers.usd_xrp
|
||||
}
|
||||
throw new Error('unexpected end')
|
||||
}
|
||||
|
||||
describe('client.getOrderbook', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('normal', async function () {
|
||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
||||
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
|
||||
const request = {
|
||||
takerPays: requests.getOrderbook.normal.takerPays,
|
||||
takerGets: requests.getOrderbook.normal.takerGets,
|
||||
@@ -80,7 +90,7 @@ describe('client.getOrderbook', function () {
|
||||
limit: 1,
|
||||
},
|
||||
}
|
||||
const response = await this.client.getOrderbook(
|
||||
const response = await testContext.client.getOrderbook(
|
||||
request.takerPays,
|
||||
request.takerGets,
|
||||
request.options,
|
||||
@@ -93,22 +103,51 @@ describe('client.getOrderbook', function () {
|
||||
})
|
||||
|
||||
it('invalid options', async function () {
|
||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
||||
assertRejects(
|
||||
this.client.getOrderbook(
|
||||
requests.getOrderbook.normal.takerPays,
|
||||
requests.getOrderbook.normal.takerGets,
|
||||
{
|
||||
invalid: 'options',
|
||||
},
|
||||
const invalidOptions = [
|
||||
{
|
||||
option: 'invalid',
|
||||
},
|
||||
{
|
||||
limit: 'invalid',
|
||||
},
|
||||
{
|
||||
ledger_index: 'invalid',
|
||||
},
|
||||
{
|
||||
ledger_hash: 0,
|
||||
},
|
||||
{
|
||||
taker: 0,
|
||||
},
|
||||
]
|
||||
|
||||
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
|
||||
await Promise.all(
|
||||
invalidOptions.map(
|
||||
async (invalidOptionObject) =>
|
||||
new Promise<void>((resolve) => {
|
||||
assertRejects(
|
||||
testContext.client
|
||||
.getOrderbook(
|
||||
requests.getOrderbook.normal.takerPays,
|
||||
requests.getOrderbook.normal.takerGets,
|
||||
// @ts-expect-error Meant to be invalid for testing purposes
|
||||
invalidOptionObject,
|
||||
)
|
||||
.catch((error) => {
|
||||
resolve()
|
||||
throw error
|
||||
}),
|
||||
ValidationError,
|
||||
)
|
||||
}),
|
||||
),
|
||||
ValidationError,
|
||||
)
|
||||
})
|
||||
|
||||
it('with XRP', async function () {
|
||||
this.mockRippled.addResponse('book_offers', xrpRippledResponse)
|
||||
const response = await this.client.getOrderbook(
|
||||
testContext.mockRippled!.addResponse('book_offers', xrpRippledResponse)
|
||||
const response = await testContext.client.getOrderbook(
|
||||
requests.getOrderbook.withXRP.takerPays,
|
||||
requests.getOrderbook.withXRP.takerGets,
|
||||
)
|
||||
@@ -116,8 +155,8 @@ describe('client.getOrderbook', function () {
|
||||
})
|
||||
|
||||
it('sample USD/XRP book has orders sorted correctly', async function () {
|
||||
this.mockRippled.addResponse('book_offers', xrpRippledResponse)
|
||||
const response = await this.client.getOrderbook(
|
||||
testContext.mockRippled!.addResponse('book_offers', xrpRippledResponse)
|
||||
const response = await testContext.client.getOrderbook(
|
||||
requests.getOrderbook.withXRP.takerPays,
|
||||
requests.getOrderbook.withXRP.takerGets,
|
||||
)
|
||||
@@ -126,13 +165,13 @@ describe('client.getOrderbook', function () {
|
||||
})
|
||||
|
||||
it('sorted so that best deals come first [failure test]', async function () {
|
||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
||||
const response = await this.client.getOrderbook(
|
||||
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
|
||||
const response = await testContext.client.getOrderbook(
|
||||
requests.getOrderbook.normal.takerPays,
|
||||
requests.getOrderbook.normal.takerGets,
|
||||
)
|
||||
const buyRates = response.buy.map(async (item) => item.quality as number)
|
||||
const sellRates = response.sell.map(async (item) => item.quality as number)
|
||||
const buyRates = response.buy.map(async (item) => Number(item.quality))
|
||||
const sellRates = response.sell.map(async (item) => Number(item.quality))
|
||||
// buy and sell orders should be sorted so that the best deals come first
|
||||
assert.deepEqual(
|
||||
buyRates.sort((item) => Number(item)),
|
||||
@@ -145,13 +184,13 @@ describe('client.getOrderbook', function () {
|
||||
})
|
||||
|
||||
it('sorted so that best deals come first [bad test](XRP)', async function () {
|
||||
this.mockRippled.addResponse('book_offers', xrpRippledResponse)
|
||||
const response = await this.client.getOrderbook(
|
||||
testContext.mockRippled!.addResponse('book_offers', xrpRippledResponse)
|
||||
const response = await testContext.client.getOrderbook(
|
||||
requests.getOrderbook.withXRP.takerPays,
|
||||
requests.getOrderbook.withXRP.takerGets,
|
||||
)
|
||||
const buyRates = response.buy.map(async (item) => item.quality as number)
|
||||
const sellRates = response.sell.map(async (item) => item.quality as number)
|
||||
const buyRates = response.buy.map(async (item) => Number(item.quality))
|
||||
const sellRates = response.sell.map(async (item) => Number(item.quality))
|
||||
// buy and sell orders should be sorted so that the best deals come first
|
||||
assert.deepEqual(
|
||||
buyRates.sort((item) => Number(item)),
|
||||
@@ -164,8 +203,8 @@ describe('client.getOrderbook', function () {
|
||||
})
|
||||
|
||||
it('direction is correct for buy and sell', async function () {
|
||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
||||
const response = await this.client.getOrderbook(
|
||||
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
|
||||
const response = await testContext.client.getOrderbook(
|
||||
requests.getOrderbook.normal.takerPays,
|
||||
requests.getOrderbook.normal.takerGets,
|
||||
)
|
||||
@@ -180,9 +219,9 @@ describe('client.getOrderbook', function () {
|
||||
})
|
||||
|
||||
it('getOrderbook - limit', async function () {
|
||||
this.mockRippled.addResponse('book_offers', normalRippledResponse)
|
||||
testContext.mockRippled!.addResponse('book_offers', normalRippledResponse)
|
||||
const LIMIT = 3
|
||||
const response = await this.client.getOrderbook(
|
||||
const response = await testContext.client.getOrderbook(
|
||||
requests.getOrderbook.normal.takerPays,
|
||||
requests.getOrderbook.normal.takerGets,
|
||||
{
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
import { addressTests } from '../testUtils'
|
||||
|
||||
/**
|
||||
@@ -10,18 +14,22 @@ import { addressTests } from '../testUtils'
|
||||
* - Check out "test/client/index.ts" for more information about the test runner.
|
||||
*/
|
||||
describe('client.getXrpBalance', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
addressTests.forEach(function (testcase) {
|
||||
describe(testcase.type, function () {
|
||||
describe(testcase.type, () => {
|
||||
it('getXrpBalance', async function () {
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
const result = await this.client.getXrpBalance(testcase.address)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
const result = await testContext.client.getXrpBalance(testcase.address)
|
||||
assert.equal(result, '922.913243')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
|
||||
describe('client.isConnected', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => {
|
||||
await teardownClient(testContext)
|
||||
})
|
||||
|
||||
it('disconnect & isConnected', async function () {
|
||||
assert.strictEqual(this.client.isConnected(), true)
|
||||
await this.client.disconnect()
|
||||
assert.strictEqual(this.client.isConnected(), false)
|
||||
assert.strictEqual(testContext.client.isConnected(), true)
|
||||
await testContext.client.disconnect()
|
||||
assert.strictEqual(testContext.client.isConnected(), false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,29 +1,37 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any -- required for formatting transactions */
|
||||
import { expect } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import type { TransactionStream } from 'xrpl-local'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
|
||||
import type { TransactionStream } from '../../src'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
|
||||
const partialPaymentIOU = rippled.partial_payments.iou
|
||||
const partialPaymentXRP = rippled.partial_payments.xrp
|
||||
|
||||
describe('client handling of tfPartialPayments', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('Tx with no tfPartialPayment', async function () {
|
||||
this.mockRippled.addResponse('tx', rippled.tx.Payment)
|
||||
const resp = await this.client.request({ command: 'tx' })
|
||||
testContext.mockRippled!.addResponse('tx', rippled.tx.Payment)
|
||||
const resp = await testContext.client.request({ command: 'tx' })
|
||||
|
||||
expect(resp.warnings).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('Tx with IOU tfPartialPayment', async function () {
|
||||
const mockResponse = { ...rippled.tx.Payment, result: partialPaymentIOU }
|
||||
this.mockRippled.addResponse('tx', mockResponse)
|
||||
const resp = await this.client.request({ command: 'tx' })
|
||||
testContext.mockRippled!.addResponse('tx', mockResponse)
|
||||
const resp = await testContext.client.request({ command: 'tx' })
|
||||
|
||||
expect(resp.warnings).to.deep.equal([
|
||||
{
|
||||
@@ -35,8 +43,8 @@ describe('client handling of tfPartialPayments', function () {
|
||||
|
||||
it('Tx with XRP tfPartialPayment', async function () {
|
||||
const mockResponse = { ...rippled.tx.Payment, result: partialPaymentXRP }
|
||||
this.mockRippled.addResponse('tx', mockResponse)
|
||||
const resp = await this.client.request({ command: 'tx' })
|
||||
testContext.mockRippled!.addResponse('tx', mockResponse)
|
||||
const resp = await testContext.client.request({ command: 'tx' })
|
||||
|
||||
expect(resp.warnings).to.deep.equal([
|
||||
{
|
||||
@@ -47,8 +55,11 @@ describe('client handling of tfPartialPayments', function () {
|
||||
})
|
||||
|
||||
it('account_tx with no tfPartialPayment', async function () {
|
||||
this.mockRippled.addResponse('account_tx', rippled.account_tx.normal)
|
||||
const resp = await this.client.request({ command: 'account_tx' })
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_tx',
|
||||
rippled.account_tx.normal,
|
||||
)
|
||||
const resp = await testContext.client.request({ command: 'account_tx' })
|
||||
|
||||
expect(resp.warnings).to.equal(undefined)
|
||||
})
|
||||
@@ -64,8 +75,8 @@ describe('client handling of tfPartialPayments', function () {
|
||||
meta: partial.result.meta,
|
||||
} as any)
|
||||
|
||||
this.mockRippled.addResponse('account_tx', mockResponse)
|
||||
const resp = await this.client.request({
|
||||
testContext.mockRippled!.addResponse('account_tx', mockResponse)
|
||||
const resp = await testContext.client.request({
|
||||
command: 'account_tx',
|
||||
account: mockResponse.result.account,
|
||||
})
|
||||
@@ -87,8 +98,8 @@ describe('client handling of tfPartialPayments', function () {
|
||||
meta: partial.result.meta,
|
||||
} as any)
|
||||
|
||||
this.mockRippled.addResponse('account_tx', mockResponse)
|
||||
const resp = await this.client.request({
|
||||
testContext.mockRippled!.addResponse('account_tx', mockResponse)
|
||||
const resp = await testContext.client.request({
|
||||
command: 'account_tx',
|
||||
account: mockResponse.result.account,
|
||||
})
|
||||
@@ -102,17 +113,24 @@ describe('client handling of tfPartialPayments', function () {
|
||||
})
|
||||
|
||||
it('transaction_entry with no tfPartialPayment', async function () {
|
||||
this.mockRippled.addResponse('transaction_entry', rippled.transaction_entry)
|
||||
const resp = await this.client.request({ command: 'transaction_entry' })
|
||||
testContext.mockRippled!.addResponse(
|
||||
'transaction_entry',
|
||||
rippled.transaction_entry,
|
||||
)
|
||||
const resp = await testContext.client.request({
|
||||
command: 'transaction_entry',
|
||||
})
|
||||
|
||||
expect(resp.warnings).to.equal(undefined)
|
||||
})
|
||||
|
||||
it('transaction_entry with XRP tfPartialPayment', async function () {
|
||||
const mockResponse = _.cloneDeep(rippled.transaction_entry)
|
||||
const mockResponse = cloneDeep(rippled.transaction_entry)
|
||||
mockResponse.result.tx_json.Amount = '1000'
|
||||
this.mockRippled.addResponse('transaction_entry', mockResponse)
|
||||
const resp = await this.client.request({ command: 'transaction_entry' })
|
||||
testContext.mockRippled!.addResponse('transaction_entry', mockResponse)
|
||||
const resp = await testContext.client.request({
|
||||
command: 'transaction_entry',
|
||||
})
|
||||
|
||||
expect(resp.warnings).to.deep.equal([
|
||||
{
|
||||
@@ -122,21 +140,28 @@ describe('client handling of tfPartialPayments', function () {
|
||||
])
|
||||
})
|
||||
|
||||
it('Transactions stream with no tfPartialPayment', async function (done) {
|
||||
this.mockRippled.addResponse('transaction_entry', rippled.transaction_entry)
|
||||
this.client.on('transaction', (tx: TransactionStream) => {
|
||||
it('Transactions stream with no tfPartialPayment', (done) => {
|
||||
testContext.mockRippled!.addResponse(
|
||||
'transaction_entry',
|
||||
rippled.transaction_entry,
|
||||
)
|
||||
testContext.client.on('transaction', (tx: TransactionStream) => {
|
||||
expect(tx.warnings).to.equal(undefined)
|
||||
done()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.transaction),
|
||||
)
|
||||
})
|
||||
|
||||
it('Transactions stream with XRP tfPartialPayment', async function (done) {
|
||||
this.mockRippled.addResponse('transaction_entry', rippled.transaction_entry)
|
||||
this.client.on('transaction', (tx: TransactionStream) => {
|
||||
it('Transactions stream with XRP tfPartialPayment', (done) => {
|
||||
testContext.mockRippled!.addResponse(
|
||||
'transaction_entry',
|
||||
rippled.transaction_entry,
|
||||
)
|
||||
testContext.client.on('transaction', (tx: TransactionStream) => {
|
||||
expect(tx.warnings).to.deep.equal([
|
||||
{
|
||||
id: 2001,
|
||||
@@ -146,7 +171,8 @@ describe('client handling of tfPartialPayments', function () {
|
||||
done()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.partialPaymentTransaction),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
import responses from '../fixtures/responses'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
import { addressTests, assertResultMatch } from '../testUtils'
|
||||
|
||||
describe('client.request', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
addressTests.forEach(function (testcase) {
|
||||
describe(testcase.type, function () {
|
||||
describe(testcase.type, () => {
|
||||
it('request account_objects', async function () {
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_objects',
|
||||
rippled.account_objects.normal,
|
||||
)
|
||||
const result = await this.client.request({
|
||||
const result = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testcase.address,
|
||||
})
|
||||
@@ -27,11 +35,11 @@ describe('client.request', function () {
|
||||
})
|
||||
|
||||
it('request account_objects - invalid options', async function () {
|
||||
this.mockRippled.addResponse(
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_objects',
|
||||
rippled.account_objects.normal,
|
||||
)
|
||||
const result = await this.client.request({
|
||||
const result = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testcase.address,
|
||||
})
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import type { Request } from '../../src'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
|
||||
const rippledResponse = function (request: Request): Record<string, unknown> {
|
||||
if ('marker' in request) {
|
||||
@@ -11,11 +16,15 @@ const rippledResponse = function (request: Request): Record<string, unknown> {
|
||||
}
|
||||
|
||||
describe('client.requestAll', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
it('requests the next page', async function () {
|
||||
this.mockRippled.addResponse('ledger_data', rippledResponse)
|
||||
const allResponses = await this.client.requestAll({
|
||||
testContext.mockRippled!.addResponse('ledger_data', rippledResponse)
|
||||
const allResponses = await testContext.client.requestAll({
|
||||
command: 'ledger_data',
|
||||
})
|
||||
assert.equal(allResponses.length, 2)
|
||||
@@ -26,8 +35,11 @@ describe('client.requestAll', function () {
|
||||
})
|
||||
|
||||
it('rejects when there are no more pages', async function () {
|
||||
this.mockRippled.addResponse('ledger_data', rippled.ledger_data.last_page)
|
||||
const allResponses = await this.client.requestAll({
|
||||
testContext.mockRippled!.addResponse(
|
||||
'ledger_data',
|
||||
rippled.ledger_data.last_page,
|
||||
)
|
||||
const allResponses = await testContext.client.requestAll({
|
||||
command: 'ledger_data',
|
||||
})
|
||||
assert.equal(allResponses.length, 1)
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { assert } from 'chai'
|
||||
import { hasNextPage } from 'xrpl-local'
|
||||
|
||||
import { hasNextPage, type Request } from '../../src'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
import { assertRejects } from '../testUtils'
|
||||
|
||||
const rippledResponse = function (request: Request): Record<string, unknown> {
|
||||
@@ -13,12 +17,18 @@ const rippledResponse = function (request: Request): Record<string, unknown> {
|
||||
}
|
||||
|
||||
describe('client.requestNextPage', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
it('requests the next page', async function () {
|
||||
this.mockRippled.addResponse('ledger_data', rippledResponse)
|
||||
const response = await this.client.request({ command: 'ledger_data' })
|
||||
const responseNextPage = await this.client.requestNextPage(
|
||||
testContext.mockRippled!.addResponse('ledger_data', rippledResponse)
|
||||
const response = await testContext.client.request({
|
||||
command: 'ledger_data',
|
||||
})
|
||||
const responseNextPage = await testContext.client.requestNextPage(
|
||||
{ command: 'ledger_data' },
|
||||
response,
|
||||
)
|
||||
@@ -29,15 +39,20 @@ describe('client.requestNextPage', function () {
|
||||
})
|
||||
|
||||
it('rejects when there are no more pages', async function () {
|
||||
this.mockRippled.addResponse('ledger_data', rippledResponse)
|
||||
const response = await this.client.request({ command: 'ledger_data' })
|
||||
const responseNextPage = await this.client.requestNextPage(
|
||||
testContext.mockRippled!.addResponse('ledger_data', rippledResponse)
|
||||
const response = await testContext.client.request({
|
||||
command: 'ledger_data',
|
||||
})
|
||||
const responseNextPage = await testContext.client.requestNextPage(
|
||||
{ command: 'ledger_data' },
|
||||
response,
|
||||
)
|
||||
assert(!hasNextPage(responseNextPage))
|
||||
await assertRejects(
|
||||
this.client.requestNextPage({ command: 'ledger_data' }, responseNextPage),
|
||||
testContext.client.requestNextPage(
|
||||
{ command: 'ledger_data' },
|
||||
responseNextPage,
|
||||
),
|
||||
Error,
|
||||
'response does not have a next page',
|
||||
)
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { ValidationError } from 'xrpl-local'
|
||||
import { Transaction } from 'xrpl-local/models/transactions'
|
||||
import Wallet from 'xrpl-local/Wallet'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
|
||||
import { ValidationError } from '../../src'
|
||||
import { Transaction } from '../../src/models/transactions'
|
||||
import Wallet from '../../src/Wallet'
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
import { assertRejects } from '../testUtils'
|
||||
|
||||
describe('client.submit', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
describe('submit unsigned transactions', function () {
|
||||
const publicKey =
|
||||
@@ -29,17 +37,23 @@ describe('client.submit', function () {
|
||||
}
|
||||
|
||||
it('should submit an unsigned transaction', async function () {
|
||||
const tx = _.cloneDeep(transaction)
|
||||
const tx = cloneDeep(transaction)
|
||||
|
||||
const wallet = new Wallet(publicKey, privateKey)
|
||||
|
||||
this.mockRippled.addResponse('account_info', rippled.account_info.normal)
|
||||
this.mockRippled.addResponse('ledger', rippled.ledger.normal)
|
||||
this.mockRippled.addResponse('server_info', rippled.server_info.normal)
|
||||
this.mockRippled.addResponse('submit', rippled.submit.success)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'account_info',
|
||||
rippled.account_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse('ledger', rippled.ledger.normal)
|
||||
testContext.mockRippled!.addResponse(
|
||||
'server_info',
|
||||
rippled.server_info.normal,
|
||||
)
|
||||
testContext.mockRippled!.addResponse('submit', rippled.submit.success)
|
||||
|
||||
try {
|
||||
const response = await this.client.submit(tx, { wallet })
|
||||
const response = await testContext.client.submit(tx, { wallet })
|
||||
assert(response.result.engine_result, 'tesSUCCESS')
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- error type thrown can be any
|
||||
@@ -48,14 +62,14 @@ describe('client.submit', function () {
|
||||
})
|
||||
|
||||
it('should throw a ValidationError when submitting an unsigned transaction without a wallet', async function () {
|
||||
const tx: Transaction = _.cloneDeep(transaction)
|
||||
const tx: Transaction = cloneDeep(transaction)
|
||||
delete tx.SigningPubKey
|
||||
delete tx.TxnSignature
|
||||
|
||||
this.mockRippled.addResponse('submit', rippled.submit.success)
|
||||
testContext.mockRippled!.addResponse('submit', rippled.submit.success)
|
||||
|
||||
await assertRejects(
|
||||
this.client.submit(tx),
|
||||
testContext.client.submit(tx),
|
||||
ValidationError,
|
||||
'Wallet must be provided when submitting an unsigned transaction',
|
||||
)
|
||||
@@ -80,10 +94,10 @@ describe('client.submit', function () {
|
||||
it('should submit a signed transaction', async function () {
|
||||
const signedTx = { ...signedTransaction }
|
||||
|
||||
this.mockRippled.addResponse('submit', rippled.submit.success)
|
||||
testContext.mockRippled!.addResponse('submit', rippled.submit.success)
|
||||
|
||||
try {
|
||||
const response = await this.client.submit(signedTx)
|
||||
const response = await testContext.client.submit(signedTx)
|
||||
assert(response.result.engine_result, 'tesSUCCESS')
|
||||
} catch (_error) {
|
||||
assert(false, 'Did not expect an error to be thrown')
|
||||
@@ -94,10 +108,10 @@ describe('client.submit', function () {
|
||||
const signedTxEncoded =
|
||||
'1200002400000001201B00003018614000000001312D0068400000000000000C7321030E58CDD076E798C84755590AAF6237CA8FAE821070A59F648B517A30DC6F589D74473045022100B3D311371EDAB371CD8F2B661A04B800B61D4B132E09B7B0712D3B2F11B1758302203906B44C4A150311D74FF6A35B146763C0B5B40AC30BD815113F058AA17B3E6381142AF1861DEC1316AEEC995C94FF9E2165B1B784608314FDB08D07AAA0EB711793A3027304D688E10C3648'
|
||||
|
||||
this.mockRippled.addResponse('submit', rippled.submit.success)
|
||||
testContext.mockRippled!.addResponse('submit', rippled.submit.success)
|
||||
|
||||
try {
|
||||
const response = await this.client.submit(signedTxEncoded)
|
||||
const response = await testContext.client.submit(signedTxEncoded)
|
||||
assert(response.result.engine_result, 'tesSUCCESS')
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- error type thrown can be any
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { assert } from 'chai'
|
||||
|
||||
import rippled from '../fixtures/rippled'
|
||||
import { setupClient, teardownClient } from '../setupClient'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplTestContext,
|
||||
} from '../setupClient'
|
||||
|
||||
async function assertDoesNotThrow(promise: Promise<unknown>): Promise<void> {
|
||||
try {
|
||||
@@ -14,87 +18,133 @@ async function assertDoesNotThrow(promise: Promise<unknown>): Promise<void> {
|
||||
}
|
||||
|
||||
describe('Client subscription', function () {
|
||||
beforeEach(setupClient)
|
||||
afterEach(teardownClient)
|
||||
let testContext: XrplTestContext
|
||||
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient()
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('Successfully Subscribes', async function () {
|
||||
this.mockRippled.addResponse('subscribe', rippled.subscribe.success)
|
||||
testContext.mockRippled!.addResponse('subscribe', rippled.subscribe.success)
|
||||
|
||||
await assertDoesNotThrow(this.client.request({ command: 'subscribe' }))
|
||||
await assertDoesNotThrow(
|
||||
testContext.client.request({ command: 'subscribe' }),
|
||||
)
|
||||
})
|
||||
|
||||
it('Successfully Unsubscribes', async function () {
|
||||
this.mockRippled.addResponse('unsubscribe', rippled.unsubscribe)
|
||||
testContext.mockRippled!.addResponse('unsubscribe', rippled.unsubscribe)
|
||||
|
||||
await assertDoesNotThrow(
|
||||
this.client.request({
|
||||
testContext.client.request({
|
||||
command: 'unsubscribe',
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it('Emits transaction', async function (done) {
|
||||
this.client.on('transaction', (tx) => {
|
||||
assert(tx.type === 'transaction')
|
||||
done()
|
||||
})
|
||||
it('Emits transaction', async function () {
|
||||
await new Promise<void>((resolve) => {
|
||||
testContext.client.on('transaction', (tx) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- TODO: Refactor as this seems pointless
|
||||
assert(tx.type === 'transaction')
|
||||
resolve()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.transaction),
|
||||
)
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.transaction),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('Emits ledger', async function (done) {
|
||||
this.client.on('ledgerClosed', (ledger) => {
|
||||
assert(ledger.type === 'ledgerClosed')
|
||||
done()
|
||||
})
|
||||
it('Emits ledger', async function () {
|
||||
await new Promise<void>((resolve) => {
|
||||
testContext.client.on('ledgerClosed', (ledger) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- TODO: Refactor as this seems pointless
|
||||
assert(ledger.type === 'ledgerClosed')
|
||||
resolve()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(JSON.stringify(rippled.streams.ledger))
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.ledger),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('Emits peerStatusChange', async function (done) {
|
||||
this.client.on('peerStatusChange', (status) => {
|
||||
assert(status.type === 'peerStatusChange')
|
||||
done()
|
||||
})
|
||||
it('Emits peerStatusChange', async function () {
|
||||
await new Promise<void>((resolve) => {
|
||||
testContext.client.on('peerStatusChange', (status) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- TODO: Refactor as this seems pointless
|
||||
assert(status.type === 'peerStatusChange')
|
||||
resolve()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(JSON.stringify(rippled.streams.peerStatus))
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.peerStatus),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('Emits consensusPhase', async function (done) {
|
||||
this.client.on('consensusPhase', (phase) => {
|
||||
assert(phase.type === 'consensusPhase')
|
||||
done()
|
||||
})
|
||||
it('Emits consensusPhase', async function () {
|
||||
await new Promise<void>((resolve) => {
|
||||
testContext.client.on('consensusPhase', (phase) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- TODO: Refactor as this seems pointless
|
||||
assert(phase.type === 'consensusPhase')
|
||||
resolve()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(JSON.stringify(rippled.streams.consensus))
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.consensus),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('Emits path_find', async function (done) {
|
||||
this.client.on('path_find', (path) => {
|
||||
assert(path.type === 'path_find')
|
||||
done()
|
||||
})
|
||||
it('Emits path_find', async function () {
|
||||
await new Promise<void>((resolve) => {
|
||||
testContext.client.on('path_find', (path) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- TODO: Refactor as this seems pointless
|
||||
assert(path.type === 'path_find')
|
||||
resolve()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(JSON.stringify(rippled.streams.pathFind))
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.pathFind),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('Emits validationReceived', async function (done) {
|
||||
this.client.on('validationReceived', (path) => {
|
||||
assert(path.type === 'validationReceived')
|
||||
done()
|
||||
})
|
||||
it('Emits validationReceived', async function () {
|
||||
await new Promise<void>((resolve) => {
|
||||
testContext.client.on('validationReceived', (path) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- TODO: Refactor as this seems pointless
|
||||
assert(path.type === 'validationReceived')
|
||||
resolve()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(JSON.stringify(rippled.streams.validation))
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.validation),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('Emits manifestReceived', async function (done) {
|
||||
this.client.on('manifestReceived', (path) => {
|
||||
assert(path.type === 'manifestReceived')
|
||||
done()
|
||||
})
|
||||
it('Emits manifestReceived', async function () {
|
||||
await new Promise<void>((resolve) => {
|
||||
// @es-expect-error Seems like a valid method
|
||||
testContext.client.on('manifestReceived', (path) => {
|
||||
assert(path.type === 'manifestReceived')
|
||||
resolve()
|
||||
})
|
||||
|
||||
this.client.connection.onMessage(JSON.stringify(rippled.streams.manifest))
|
||||
// @ts-expect-error Using private method for testing
|
||||
testContext.client.connection.onMessage(
|
||||
JSON.stringify(rippled.streams.manifest),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
import { EventEmitter2 } from 'eventemitter2'
|
||||
import _ from 'lodash'
|
||||
import { Server as WebSocketServer } from 'ws'
|
||||
import { Server as WebSocketServer, type WebSocket } from 'ws'
|
||||
|
||||
import type { Request } from '../src'
|
||||
import { XrplError } from '../src/errors'
|
||||
@@ -9,7 +8,7 @@ import type {
|
||||
ErrorResponse,
|
||||
} from '../src/models/methods/baseMethod'
|
||||
|
||||
import { getFreePort } from './testUtils'
|
||||
import { destroyServer, getFreePort } from './testUtils'
|
||||
|
||||
function createResponse(
|
||||
request: { id: number | string },
|
||||
@@ -47,10 +46,42 @@ export interface PortResponse extends BaseResponse {
|
||||
* We mock out WebSocketServer in these tests and add a lot of custom
|
||||
* 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
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/promise-function-async -- Not a promise that's returned
|
||||
export type MockedWebSocketServer = WebSocketServer &
|
||||
EventEmitter2 & {
|
||||
responses: Record<string, unknown>
|
||||
suppressOutput: boolean
|
||||
socket: WebSocket
|
||||
addResponse: (
|
||||
command: string,
|
||||
response:
|
||||
| Response
|
||||
| ErrorResponse
|
||||
| ((r: Request) => Response | ErrorResponse | Record<string, unknown>)
|
||||
| Record<string, unknown>,
|
||||
) => void
|
||||
getResponse: (request: Request) => Record<string, unknown>
|
||||
testCommand: (
|
||||
conn: WebSocket,
|
||||
request: {
|
||||
id: string | number
|
||||
data: {
|
||||
closeServerAndReopen: number
|
||||
disconnectIn: number
|
||||
openOnOtherPort: boolean
|
||||
unrecognizedResponse: boolean
|
||||
closeServer: boolean
|
||||
delayedResponseIn: number
|
||||
}
|
||||
},
|
||||
) => void
|
||||
}
|
||||
|
||||
export function destroyMockRippled(server: MockedWebSocketServer): void {
|
||||
server.removeAllListeners()
|
||||
server.close()
|
||||
}
|
||||
|
||||
export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
const mock = new WebSocketServer({ port }) as MockedWebSocketServer
|
||||
Object.assign(mock, EventEmitter2.prototype)
|
||||
@@ -58,18 +89,19 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
mock.responses = {}
|
||||
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) {
|
||||
this.socket = conn
|
||||
conn.on('message', function (requestJSON: string) {
|
||||
conn.on('message', function (requestJSON) {
|
||||
let request
|
||||
try {
|
||||
request = JSON.parse(requestJSON)
|
||||
// eslint-disable-next-line @typescript-eslint/no-base-to-string -- request is a string
|
||||
const requestJsonString = requestJSON.toString()
|
||||
request = JSON.parse(requestJsonString)
|
||||
if (request.id == null) {
|
||||
throw new XrplError(`Request has no id: ${requestJSON}`)
|
||||
throw new XrplError(`Request has no id: ${requestJsonString}`)
|
||||
}
|
||||
if (request.command == null) {
|
||||
throw new XrplError(`Request has no id: ${requestJSON}`)
|
||||
throw new XrplError(`Request has no id: ${requestJsonString}`)
|
||||
}
|
||||
if (request.command === 'ping') {
|
||||
ping(conn, request)
|
||||
@@ -110,13 +142,7 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
* 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
|
||||
*/
|
||||
mock.addResponse = function (
|
||||
command: string,
|
||||
response:
|
||||
| Response
|
||||
| ErrorResponse
|
||||
| ((r: Request) => Response | ErrorResponse),
|
||||
): void {
|
||||
mock.addResponse = function (command, response): void {
|
||||
if (typeof command !== 'string') {
|
||||
throw new XrplError('command is not a string')
|
||||
}
|
||||
@@ -134,7 +160,7 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
mock.responses[command] = response
|
||||
}
|
||||
|
||||
mock.getResponse = (request: Request): Record<string, unknown> => {
|
||||
mock.getResponse = (request): Record<string, unknown> => {
|
||||
if (!(request.command in mock.responses)) {
|
||||
throw new XrplError(`No handler for ${request.command}`)
|
||||
}
|
||||
@@ -156,8 +182,8 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
}),
|
||||
)
|
||||
} else if (request.data.openOnOtherPort) {
|
||||
getFreePort().then((newPort) => {
|
||||
createMockRippled(newPort)
|
||||
getFreePort().then(async (newPort) => {
|
||||
createMockRippled(port)
|
||||
conn.send(
|
||||
createResponse(request, {
|
||||
status: 'success',
|
||||
@@ -165,6 +191,7 @@ export default function createMockRippled(port: number): MockedWebSocketServer {
|
||||
result: { port: newPort },
|
||||
}),
|
||||
)
|
||||
return destroyServer(newPort)
|
||||
})
|
||||
} else if (request.data.closeServerAndReopen) {
|
||||
setTimeout(() => {
|
||||
|
||||
707
packages/xrpl/test/fixtures/rippled/accountLines.js
vendored
707
packages/xrpl/test/fixtures/rippled/accountLines.js
vendored
@@ -1,18 +1,24 @@
|
||||
'use strict';
|
||||
const _ = require('lodash');
|
||||
const BASE_LEDGER_INDEX = 8819951;
|
||||
const defaults = require('lodash/defaults')
|
||||
|
||||
const BASE_LEDGER_INDEX = 8819951
|
||||
|
||||
function getMarkerAndLinesFromRequest(request) {
|
||||
const itemCount = 401; // Items on the ledger
|
||||
const perRequestLimit = 400;
|
||||
const pageCount = Math.ceil(itemCount / perRequestLimit);
|
||||
const itemCount = 401 // Items on the ledger
|
||||
const perRequestLimit = 400
|
||||
const pageCount = Math.ceil(itemCount / perRequestLimit)
|
||||
|
||||
// marker is the index of the next item to return
|
||||
const startIndex = request.marker ? Number(request.marker) : 0;
|
||||
const startIndex = request.marker ? Number(request.marker) : 0
|
||||
|
||||
// No minimum: there are only a certain number of results on the ledger.
|
||||
// Maximum: the lowest of (perRequestLimit, itemCount - startIndex, request.limit).
|
||||
const lineCount = Math.min(perRequestLimit, itemCount - startIndex, request.limit);
|
||||
/*
|
||||
* No minimum: there are only a certain number of results on the ledger.
|
||||
* Maximum: the lowest of (perRequestLimit, itemCount - startIndex, request.limit).
|
||||
*/
|
||||
const lineCount = Math.min(
|
||||
perRequestLimit,
|
||||
itemCount - startIndex,
|
||||
request.limit,
|
||||
)
|
||||
|
||||
const trustline = {
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
@@ -21,19 +27,19 @@ function getMarkerAndLinesFromRequest(request) {
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
};
|
||||
quality_out: 0,
|
||||
}
|
||||
|
||||
return {
|
||||
marker: itemCount - lineCount > 0 ? startIndex + lineCount : undefined,
|
||||
lines: new Array(lineCount).fill(trustline)
|
||||
};
|
||||
lines: new Array(lineCount).fill(trustline),
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.normal = function(request, options = {}) {
|
||||
_.defaults(options, {
|
||||
ledger: BASE_LEDGER_INDEX
|
||||
});
|
||||
module.exports.normal = function (request, options = {}) {
|
||||
defaults(options, {
|
||||
ledger: BASE_LEDGER_INDEX,
|
||||
})
|
||||
|
||||
return {
|
||||
id: request.id,
|
||||
@@ -44,250 +50,251 @@ module.exports.normal = function(request, options = {}) {
|
||||
marker: options.marker,
|
||||
limit: request.limit,
|
||||
ledger_index: options.ledger,
|
||||
lines: [{
|
||||
account: 'r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z',
|
||||
balance: '0',
|
||||
currency: 'ASP',
|
||||
limit: '0',
|
||||
limit_peer: '10',
|
||||
quality_in: 1000000000,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z',
|
||||
balance: '0',
|
||||
currency: 'XAU',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
freeze: true
|
||||
},
|
||||
{
|
||||
account: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
balance: '2.497605752725159',
|
||||
currency: 'USD',
|
||||
limit: '5',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
freeze: true
|
||||
},
|
||||
{
|
||||
account: 'rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4',
|
||||
balance: '481.992867407479',
|
||||
currency: 'MXN',
|
||||
limit: '1000',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun',
|
||||
balance: '0.793598266778297',
|
||||
currency: 'EUR',
|
||||
limit: '1',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK',
|
||||
balance: '0',
|
||||
currency: 'CNY',
|
||||
limit: '3',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E',
|
||||
balance: '1.294889190631542',
|
||||
currency: 'DYM',
|
||||
limit: '3',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '0.3488146605801446',
|
||||
currency: 'CHF',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '2.114103174931847',
|
||||
currency: 'BTC',
|
||||
limit: '3',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '5000',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rpgKWEmNqSDAGFhy5WDnsyPqfQxbWxKeVd',
|
||||
balance: '-0.00111',
|
||||
currency: 'BTC',
|
||||
limit: '0',
|
||||
limit_peer: '10',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rBJ3YjwXi2MGbg7GVLuTXUWQ8DjL7tDXh4',
|
||||
balance: '-0.1010780000080207',
|
||||
currency: 'BTC',
|
||||
limit: '0',
|
||||
limit_peer: '10',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun',
|
||||
balance: '1',
|
||||
currency: 'USD',
|
||||
limit: '1',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA',
|
||||
balance: '8.07619790068559',
|
||||
currency: 'CNY',
|
||||
limit: '100',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '7.292695098901099',
|
||||
currency: 'JPY',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z',
|
||||
balance: '0',
|
||||
currency: 'AUX',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '1',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '12.41688780720394',
|
||||
currency: 'EUR',
|
||||
limit: '100',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rfF3PNkwkq1DygW2wum2HK3RGfgkJjdPVD',
|
||||
balance: '35',
|
||||
currency: 'USD',
|
||||
limit: '500',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rwUVoVMSURqNyvocPCcvLu3ygJzZyw8qwp',
|
||||
balance: '-5',
|
||||
currency: 'JOE',
|
||||
limit: '0',
|
||||
limit_peer: '50',
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '0',
|
||||
limit_peer: '100',
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2',
|
||||
balance: '0',
|
||||
currency: 'JOE',
|
||||
limit: '0',
|
||||
limit_peer: '100',
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rs9M85karFkCRjvc6KMWn8Coigm9cbcgcx',
|
||||
balance: '0',
|
||||
currency: '015841551A748AD2C1F76FF6ECB0CCCD00000000',
|
||||
limit: '10.01037626125837',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rEhDDUUNxpXgEHVJtC2cjXAgyx5VCFxdMF',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '0',
|
||||
limit_peer: '1',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
freeze: true
|
||||
}
|
||||
].filter(item => !request.peer || item.account === request.peer)
|
||||
}
|
||||
};
|
||||
};
|
||||
lines: [
|
||||
{
|
||||
account: 'r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z',
|
||||
balance: '0',
|
||||
currency: 'ASP',
|
||||
limit: '0',
|
||||
limit_peer: '10',
|
||||
quality_in: 1000000000,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z',
|
||||
balance: '0',
|
||||
currency: 'XAU',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
freeze: true,
|
||||
},
|
||||
{
|
||||
account: 'rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q',
|
||||
balance: '2.497605752725159',
|
||||
currency: 'USD',
|
||||
limit: '5',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
freeze: true,
|
||||
},
|
||||
{
|
||||
account: 'rHpXfibHgSb64n8kK9QWDpdbfqSpYbM9a4',
|
||||
balance: '481.992867407479',
|
||||
currency: 'MXN',
|
||||
limit: '1000',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun',
|
||||
balance: '0.793598266778297',
|
||||
currency: 'EUR',
|
||||
limit: '1',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK',
|
||||
balance: '0',
|
||||
currency: 'CNY',
|
||||
limit: '3',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E',
|
||||
balance: '1.294889190631542',
|
||||
currency: 'DYM',
|
||||
limit: '3',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '0.3488146605801446',
|
||||
currency: 'CHF',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '2.114103174931847',
|
||||
currency: 'BTC',
|
||||
limit: '3',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '5000',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rpgKWEmNqSDAGFhy5WDnsyPqfQxbWxKeVd',
|
||||
balance: '-0.00111',
|
||||
currency: 'BTC',
|
||||
limit: '0',
|
||||
limit_peer: '10',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rBJ3YjwXi2MGbg7GVLuTXUWQ8DjL7tDXh4',
|
||||
balance: '-0.1010780000080207',
|
||||
currency: 'BTC',
|
||||
limit: '0',
|
||||
limit_peer: '10',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun',
|
||||
balance: '1',
|
||||
currency: 'USD',
|
||||
limit: '1',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'razqQKzJRdB4UxFPWf5NEpEG3WMkmwgcXA',
|
||||
balance: '8.07619790068559',
|
||||
currency: 'CNY',
|
||||
limit: '100',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '7.292695098901099',
|
||||
currency: 'JPY',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z',
|
||||
balance: '0',
|
||||
currency: 'AUX',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'r9vbV3EHvXWjSkeQ6CAcYVPGeq7TuiXY2X',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '1',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '12.41688780720394',
|
||||
currency: 'EUR',
|
||||
limit: '100',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rfF3PNkwkq1DygW2wum2HK3RGfgkJjdPVD',
|
||||
balance: '35',
|
||||
currency: 'USD',
|
||||
limit: '500',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rwUVoVMSURqNyvocPCcvLu3ygJzZyw8qwp',
|
||||
balance: '-5',
|
||||
currency: 'JOE',
|
||||
limit: '0',
|
||||
limit_peer: '50',
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '0',
|
||||
limit_peer: '100',
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2',
|
||||
balance: '0',
|
||||
currency: 'JOE',
|
||||
limit: '0',
|
||||
limit_peer: '100',
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rs9M85karFkCRjvc6KMWn8Coigm9cbcgcx',
|
||||
balance: '0',
|
||||
currency: '015841551A748AD2C1F76FF6ECB0CCCD00000000',
|
||||
limit: '10.01037626125837',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rEhDDUUNxpXgEHVJtC2cjXAgyx5VCFxdMF',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '0',
|
||||
limit_peer: '1',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
freeze: true,
|
||||
},
|
||||
].filter((item) => !request.peer || item.account === request.peer),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.counterparty = function(request, options = {}) {
|
||||
_.defaults(options, {
|
||||
ledger: BASE_LEDGER_INDEX
|
||||
});
|
||||
module.exports.counterparty = function (request, options = {}) {
|
||||
defaults(options, {
|
||||
ledger: BASE_LEDGER_INDEX,
|
||||
})
|
||||
|
||||
return {
|
||||
id: request.id,
|
||||
@@ -298,64 +305,65 @@ module.exports.counterparty = function(request, options = {}) {
|
||||
marker: options.marker,
|
||||
limit: request.limit,
|
||||
ledger_index: options.ledger,
|
||||
lines: [{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '0.3488146605801446',
|
||||
currency: 'CHF',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '2.114103174931847',
|
||||
currency: 'BTC',
|
||||
limit: '3',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '5000',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '7.292695098901099',
|
||||
currency: 'JPY',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '12.41688780720394',
|
||||
currency: 'EUR',
|
||||
limit: '100',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
};
|
||||
lines: [
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '0.3488146605801446',
|
||||
currency: 'CHF',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '2.114103174931847',
|
||||
currency: 'BTC',
|
||||
limit: '3',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '0',
|
||||
currency: 'USD',
|
||||
limit: '5000',
|
||||
limit_peer: '0',
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '7.292695098901099',
|
||||
currency: 'JPY',
|
||||
limit: '0',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B',
|
||||
balance: '12.41688780720394',
|
||||
currency: 'EUR',
|
||||
limit: '100',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.manyItems = function(request, options = {}) {
|
||||
_.defaults(options, {
|
||||
ledger: BASE_LEDGER_INDEX
|
||||
});
|
||||
module.exports.manyItems = function (request, options = {}) {
|
||||
defaults(options, {
|
||||
ledger: BASE_LEDGER_INDEX,
|
||||
})
|
||||
|
||||
const {marker, lines} = getMarkerAndLinesFromRequest(request);
|
||||
const { marker, lines } = getMarkerAndLinesFromRequest(request)
|
||||
|
||||
return {
|
||||
id: request.id,
|
||||
@@ -366,16 +374,15 @@ module.exports.manyItems = function(request, options = {}) {
|
||||
marker,
|
||||
limit: request.limit,
|
||||
ledger_index: options.ledger,
|
||||
lines
|
||||
}
|
||||
};
|
||||
};
|
||||
lines,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports.ripplingDisabled = function(request, options = {}) {
|
||||
_.defaults(options, {
|
||||
ledger: BASE_LEDGER_INDEX
|
||||
});
|
||||
module.exports.ripplingDisabled = function (request, options = {}) {
|
||||
defaults(options, {
|
||||
ledger: BASE_LEDGER_INDEX,
|
||||
})
|
||||
|
||||
return {
|
||||
id: request.id,
|
||||
@@ -386,24 +393,30 @@ module.exports.ripplingDisabled = function(request, options = {}) {
|
||||
marker: options.marker,
|
||||
limit: request.limit,
|
||||
ledger_index: options.ledger,
|
||||
lines: [{'account': 'rEyiXgWXCKsh9wXYRrXCYSgCbR1gj3Xd8b',
|
||||
'balance': '0',
|
||||
'currency': 'ETH',
|
||||
'limit': '10000000000',
|
||||
'limit_peer': '0',
|
||||
'no_ripple': true,
|
||||
'no_ripple_peer': true,
|
||||
'quality_in': 0,
|
||||
'quality_out': 0},
|
||||
{'account': 'rEyiXgWXCKsh9wXYRrXCYSgCbR1gj3Xd8b',
|
||||
'balance': '0',
|
||||
'currency': 'BTC',
|
||||
'limit': '10000000000',
|
||||
'limit_peer': '0',
|
||||
'no_ripple': false,
|
||||
'no_ripple_peer': true,
|
||||
'quality_in': 0,
|
||||
'quality_out': 0}]
|
||||
}
|
||||
};
|
||||
};
|
||||
lines: [
|
||||
{
|
||||
account: 'rEyiXgWXCKsh9wXYRrXCYSgCbR1gj3Xd8b',
|
||||
balance: '0',
|
||||
currency: 'ETH',
|
||||
limit: '10000000000',
|
||||
limit_peer: '0',
|
||||
no_ripple: true,
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
{
|
||||
account: 'rEyiXgWXCKsh9wXYRrXCYSgCbR1gj3Xd8b',
|
||||
balance: '0',
|
||||
currency: 'BTC',
|
||||
limit: '10000000000',
|
||||
limit_peer: '0',
|
||||
no_ripple: false,
|
||||
no_ripple_peer: true,
|
||||
quality_in: 0,
|
||||
quality_out: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,3 @@ To run integration tests:
|
||||
* With docker, run `docker run -p 6006:6006 -it natenichols/rippled-standalone:latest`
|
||||
* Or [download and build rippled](https://xrpl.org/install-rippled.html) and run `./rippled -a`
|
||||
2. Run `npm test:integration` or `npm test:browser`
|
||||
|
||||
When editing integration tests:
|
||||
* All imports should be from `xrpl-local` instead of `../../src` (browser tests need this)
|
||||
|
||||
@@ -4,10 +4,12 @@ import assert from 'assert'
|
||||
const TIMEOUT = 20000
|
||||
|
||||
// the purpose of this file is to indicate the end of tests and not really test anything.
|
||||
describe('test', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
it('closing test', function () {
|
||||
assert(true)
|
||||
})
|
||||
describe('closing test', function () {
|
||||
it(
|
||||
'closing test',
|
||||
function () {
|
||||
assert(true)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,91 +1,11 @@
|
||||
import assert from 'assert'
|
||||
|
||||
import _ from 'lodash'
|
||||
import {
|
||||
Client,
|
||||
isValidClassicAddress,
|
||||
isValidXAddress,
|
||||
dropsToXrp,
|
||||
} from 'xrpl-local'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 60000
|
||||
// This test is reliant on external networks, and as such may be flaky.
|
||||
describe('fundWallet', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
it('submit generates a testnet wallet', async function () {
|
||||
await generate_faucet_wallet_and_fund_again(
|
||||
'wss://s.altnet.rippletest.net:51233',
|
||||
)
|
||||
})
|
||||
|
||||
it('submit generates a devnet wallet', async function () {
|
||||
await generate_faucet_wallet_and_fund_again(
|
||||
'wss://s.devnet.rippletest.net:51233',
|
||||
)
|
||||
})
|
||||
|
||||
it('can generate and fund wallets using a custom host and path', async function () {
|
||||
await generate_faucet_wallet_and_fund_again(
|
||||
'wss://s.devnet.rippletest.net:51233/',
|
||||
'faucet.devnet.rippletest.net',
|
||||
'/accounts',
|
||||
)
|
||||
})
|
||||
|
||||
it('can generate and fund wallets on AMM devnet', async function () {
|
||||
await generate_faucet_wallet_and_fund_again(
|
||||
'wss://amm.devnet.rippletest.net:51233',
|
||||
)
|
||||
})
|
||||
|
||||
it('can generate wallet on hooks v2 testnet', async function () {
|
||||
const api = new Client('wss://hooks-testnet-v2.xrpl-labs.com')
|
||||
|
||||
await api.connect()
|
||||
|
||||
const { wallet, balance } = await api.fundWallet()
|
||||
|
||||
assert.notEqual(wallet, undefined)
|
||||
assert(isValidClassicAddress(wallet.classicAddress))
|
||||
assert(isValidXAddress(wallet.getXAddress()))
|
||||
|
||||
const info = await api.request({
|
||||
command: 'account_info',
|
||||
account: wallet.classicAddress,
|
||||
})
|
||||
|
||||
assert.equal(dropsToXrp(info.result.account_data.Balance), balance)
|
||||
assert.equal(balance, 10000)
|
||||
|
||||
/*
|
||||
* No test for fund given wallet because the hooks v2 testnet faucet
|
||||
* requires 10 seconds between requests. Would significantly slow down
|
||||
* the test suite.
|
||||
*/
|
||||
|
||||
await api.disconnect()
|
||||
})
|
||||
|
||||
it('submit funds wallet with custom amount', async function () {
|
||||
const api = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
await api.connect()
|
||||
const { wallet, balance } = await api.fundWallet(null, { amount: '2000' })
|
||||
assert.equal(balance, '2000')
|
||||
assert.notEqual(wallet, undefined)
|
||||
assert(isValidClassicAddress(wallet.classicAddress))
|
||||
assert(isValidXAddress(wallet.getXAddress()))
|
||||
|
||||
const info = await api.request({
|
||||
command: 'account_info',
|
||||
account: wallet.classicAddress,
|
||||
})
|
||||
assert.equal(dropsToXrp(info.result.account_data.Balance), balance)
|
||||
await api.disconnect()
|
||||
})
|
||||
})
|
||||
} from '../../src'
|
||||
|
||||
async function generate_faucet_wallet_and_fund_again(
|
||||
client: string,
|
||||
@@ -126,3 +46,101 @@ async function generate_faucet_wallet_and_fund_again(
|
||||
|
||||
await api.disconnect()
|
||||
}
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 60000
|
||||
// This test is reliant on external networks, and as such may be flaky.
|
||||
describe('fundWallet', function () {
|
||||
it(
|
||||
'submit generates a testnet wallet',
|
||||
async function () {
|
||||
await generate_faucet_wallet_and_fund_again(
|
||||
'wss://s.altnet.rippletest.net:51233',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'submit generates a devnet wallet',
|
||||
async function () {
|
||||
await generate_faucet_wallet_and_fund_again(
|
||||
'wss://s.devnet.rippletest.net:51233',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
// TODO: Investigate why this test is timing out on the browser
|
||||
// it('can generate and fund wallets using a custom host and path', async function () {
|
||||
// await generate_faucet_wallet_and_fund_again(
|
||||
// 'wss://s.devnet.rippletest.net:51233/',
|
||||
// 'faucet.devnet.rippletest.net',
|
||||
// '/accounts',
|
||||
// )
|
||||
// })
|
||||
|
||||
it(
|
||||
'can generate and fund wallets on AMM devnet',
|
||||
async function () {
|
||||
await generate_faucet_wallet_and_fund_again(
|
||||
'wss://amm.devnet.rippletest.net:51233',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'can generate wallet on hooks v2 testnet',
|
||||
async function () {
|
||||
const api = new Client('wss://hooks-testnet-v2.xrpl-labs.com')
|
||||
|
||||
await api.connect()
|
||||
|
||||
const { wallet, balance } = await api.fundWallet()
|
||||
|
||||
assert.notEqual(wallet, undefined)
|
||||
assert(isValidClassicAddress(wallet.classicAddress))
|
||||
assert(isValidXAddress(wallet.getXAddress()))
|
||||
|
||||
const info = await api.request({
|
||||
command: 'account_info',
|
||||
account: wallet.classicAddress,
|
||||
})
|
||||
|
||||
assert.equal(dropsToXrp(info.result.account_data.Balance), balance)
|
||||
assert.equal(balance, 10000)
|
||||
|
||||
/*
|
||||
* No test for fund given wallet because the hooks v2 testnet faucet
|
||||
* requires 10 seconds between requests. Would significantly slow down
|
||||
* the test suite.
|
||||
*/
|
||||
|
||||
await api.disconnect()
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'submit funds wallet with custom amount',
|
||||
async function () {
|
||||
const api = new Client('wss://s.altnet.rippletest.net:51233')
|
||||
|
||||
await api.connect()
|
||||
const { wallet, balance } = await api.fundWallet(null, { amount: '2000' })
|
||||
assert.equal(balance, '2000')
|
||||
assert.notEqual(wallet, undefined)
|
||||
assert(isValidClassicAddress(wallet.classicAddress))
|
||||
assert(isValidXAddress(wallet.getXAddress()))
|
||||
|
||||
const info = await api.request({
|
||||
command: 'account_info',
|
||||
account: wallet.classicAddress,
|
||||
})
|
||||
assert.equal(dropsToXrp(info.result.account_data.Balance), balance)
|
||||
await api.disconnect()
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
/* eslint-disable import/export -- Tells webpack which files exist. */
|
||||
export * from './transactions/signerListSet.test'
|
||||
export * from './transactions/payment.test'
|
||||
export * from './transactions/offerCreate.test'
|
||||
export * from './transactions/offerCancel.test'
|
||||
export * from './transactions/signerListSet.test'
|
||||
export * from './transactions/accountSet.test'
|
||||
export * from './transactions/checkCancel.test'
|
||||
export * from './transactions/checkCash.test'
|
||||
export * from './transactions/checkCreate.test'
|
||||
export * from './transactions/depositPreauth.test'
|
||||
export * from './transactions/paymentChannelCreate.test'
|
||||
export * from './transactions/escrowCancel.test'
|
||||
export * from './transactions/escrowCreate.test'
|
||||
export * from './transactions/escrowFinish.test'
|
||||
export * from './transactions/offerCancel.test'
|
||||
export * from './transactions/offerCreate.test'
|
||||
export * from './transactions/payment.test'
|
||||
export * from './transactions/paymentChannelClaim.test'
|
||||
export * from './transactions/paymentChannelCreate.test'
|
||||
export * from './transactions/paymentChannelFund.test'
|
||||
export * from './transactions/signerListSet.test'
|
||||
export * from './transactions/trustSet.test'
|
||||
|
||||
export * from './requests/accountChannels.test'
|
||||
@@ -23,24 +26,33 @@ export * from './requests/accountTx.test'
|
||||
export * from './requests/bookOffers.test'
|
||||
export * from './requests/channelVerify.test'
|
||||
export * from './requests/depositAuthorized.test'
|
||||
export * from './requests/fee.test'
|
||||
export * from './requests/gatewayBalances.test'
|
||||
export * from './requests/ledger.test'
|
||||
export * from './requests/ledgerClosed.test'
|
||||
export * from './requests/ledgerCurrent.test'
|
||||
export * from './requests/ledgerData.test'
|
||||
export * from './requests/ledgerEntry.test'
|
||||
export * from './requests/submitMultisigned.test'
|
||||
export * from './requests/noRippleCheck.test'
|
||||
export * from './requests/pathFind.test'
|
||||
export * from './requests/ripplePathFind.test'
|
||||
export * from './requests/serverInfo.test'
|
||||
export * from './requests/serverState.test'
|
||||
export * from './requests/submit.test'
|
||||
export * from './requests/submitMultisigned.test'
|
||||
export * from './requests/subscribe.test'
|
||||
export * from './requests/tx.test'
|
||||
export * from './requests/utility.test'
|
||||
|
||||
export * from './fundWallet.test'
|
||||
export * from './integration.test'
|
||||
export * from './onConnect.test'
|
||||
export * from './regularKey.test'
|
||||
export * from './submitAndWait.test'
|
||||
export * from './wallet.test'
|
||||
|
||||
// Because this does 256 ledger accepts, we do it last
|
||||
export * from './transactions/accountDelete.test'
|
||||
|
||||
// Ensure you export all added tests above "export * from './finalTest'", otherwise they will not be run.
|
||||
export * from './finalTest.test'
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import assert from 'assert'
|
||||
|
||||
import _ from 'lodash'
|
||||
import { Client } from 'xrpl-local'
|
||||
import { AccountSet, SignerListSet } from 'xrpl-local/models/transactions'
|
||||
import { convertStringToHex } from 'xrpl-local/utils'
|
||||
import { multisign } from 'xrpl-local/Wallet/signer'
|
||||
import { Client, SubmitResponse } from '../../src'
|
||||
import { AccountSet, SignerListSet } from '../../src/models/transactions'
|
||||
import { convertStringToHex } from '../../src/utils'
|
||||
import { multisign } from '../../src/Wallet/signer'
|
||||
|
||||
import serverUrl from './serverUrl'
|
||||
import { setupClient, teardownClient } from './setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from './setup'
|
||||
import {
|
||||
generateFundedWallet,
|
||||
ledgerAccept,
|
||||
@@ -19,55 +22,88 @@ import {
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('integration tests', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('isConnected', function () {
|
||||
assert(this.client.isConnected())
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('submit multisigned transaction', async function () {
|
||||
const client: Client = this.client
|
||||
const signerWallet1 = await generateFundedWallet(client)
|
||||
const signerWallet2 = await generateFundedWallet(client)
|
||||
it(
|
||||
'isConnected',
|
||||
() => {
|
||||
assert(testContext.client.isConnected())
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet1.classicAddress,
|
||||
SignerWeight: 1,
|
||||
it(
|
||||
'submit multisigned transaction',
|
||||
async () => {
|
||||
const client: Client = testContext.client
|
||||
const signerWallet1 = await generateFundedWallet(client)
|
||||
const signerWallet2 = await generateFundedWallet(client)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet1.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.classicAddress,
|
||||
SignerWeight: 1,
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(this.client, signerListSet, this.wallet)
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(
|
||||
testContext.client,
|
||||
signerListSet,
|
||||
testContext.wallet,
|
||||
)
|
||||
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const { tx_blob: tx_blob1 } = signerWallet1.sign(accountSetTx, true)
|
||||
const { tx_blob: tx_blob2 } = signerWallet2.sign(accountSetTx, true)
|
||||
const multisignedTx = multisign([tx_blob1, tx_blob2])
|
||||
const submitResponse = await client.submit(multisignedTx)
|
||||
await ledgerAccept(client)
|
||||
assert.strictEqual(submitResponse.result.engine_result, 'tesSUCCESS')
|
||||
await verifySubmittedTransaction(this.client, multisignedTx)
|
||||
})
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const { tx_blob: tx_blob1 } = signerWallet1.sign(accountSetTx, true)
|
||||
const { tx_blob: tx_blob2 } = signerWallet2.sign(accountSetTx, true)
|
||||
const multisignedTx = multisign([tx_blob1, tx_blob2])
|
||||
|
||||
let response: SubmitResponse = await client.submit(multisignedTx)
|
||||
await ledgerAccept(client)
|
||||
let retryCount = 20
|
||||
|
||||
// Retry if another transaction finished before this one
|
||||
while (
|
||||
['tefPAST_SEQ', 'tefMAX_LEDGER'].includes(
|
||||
response.result.engine_result,
|
||||
) &&
|
||||
retryCount > 0
|
||||
) {
|
||||
retryCount -= 1
|
||||
// eslint-disable-next-line no-await-in-loop, no-promise-executor-return -- We are waiting on retries
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
// eslint-disable-next-line no-await-in-loop -- We are retrying in a loop on purpose
|
||||
response = await client.submit(multisignedTx)
|
||||
// eslint-disable-next-line no-await-in-loop -- We are retrying in a loop on purpose
|
||||
await ledgerAccept(client)
|
||||
}
|
||||
|
||||
assert.strictEqual(response.result.engine_result, 'tesSUCCESS')
|
||||
await verifySubmittedTransaction(testContext.client, multisignedTx)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { assert } from 'chai'
|
||||
import { Client } from 'xrpl-local'
|
||||
|
||||
import { Client } from '../../src'
|
||||
|
||||
import serverUrl from './serverUrl'
|
||||
|
||||
@@ -7,30 +8,35 @@ import serverUrl from './serverUrl'
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('on handlers', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
it('on connect', async function () {
|
||||
const client = new Client(serverUrl)
|
||||
return new Promise<void>(function (resolve) {
|
||||
client.on('connected', function () {
|
||||
client.removeAllListeners()
|
||||
client.disconnect()
|
||||
resolve()
|
||||
it(
|
||||
'on connect',
|
||||
async () => {
|
||||
const client = new Client(serverUrl)
|
||||
return new Promise<void>(function (resolve) {
|
||||
client.on('connected', function () {
|
||||
client.removeAllListeners()
|
||||
client.disconnect().then(() => resolve())
|
||||
})
|
||||
client.connect()
|
||||
})
|
||||
client.connect()
|
||||
})
|
||||
})
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it('on disconnect', async function () {
|
||||
const client = new Client(serverUrl)
|
||||
return new Promise<void>(function (resolve) {
|
||||
client.on('disconnected', function (code: number) {
|
||||
// should be the normal disconnect code
|
||||
assert.equal(code, 1000)
|
||||
client.removeAllListeners()
|
||||
resolve()
|
||||
it(
|
||||
'on disconnect',
|
||||
async () => {
|
||||
const client = new Client(serverUrl)
|
||||
return new Promise<void>(function (resolve) {
|
||||
client.on('disconnected', function (code: number) {
|
||||
// should be the normal disconnect code
|
||||
assert.equal(code, 1000)
|
||||
client.removeAllListeners()
|
||||
resolve()
|
||||
})
|
||||
client.connect().then(async () => client.disconnect())
|
||||
})
|
||||
client.connect().then(async () => client.disconnect())
|
||||
})
|
||||
})
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import {
|
||||
AccountSet,
|
||||
Client,
|
||||
@@ -8,12 +8,16 @@ import {
|
||||
Wallet,
|
||||
AccountSetAsfFlags,
|
||||
OfferCreate,
|
||||
} from 'xrpl-local'
|
||||
import { convertStringToHex } from 'xrpl-local/utils'
|
||||
import { multisign } from 'xrpl-local/Wallet/signer'
|
||||
} from '../../src'
|
||||
import { convertStringToHex } from '../../src/utils'
|
||||
import { multisign } from '../../src/Wallet/signer'
|
||||
|
||||
import serverUrl from './serverUrl'
|
||||
import { setupClient, teardownClient } from './setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from './setup'
|
||||
import {
|
||||
generateFundedWallet,
|
||||
ledgerAccept,
|
||||
@@ -62,223 +66,270 @@ async function generateFundedWalletWithRegularKey(
|
||||
}
|
||||
|
||||
describe('regular key', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('sign and submit with a regular key', async function () {
|
||||
const regularKeyWallet = (
|
||||
await generateFundedWalletWithRegularKey(this.client)
|
||||
).regularKeyWallet
|
||||
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
testTransaction(this.client, accountSet, regularKeyWallet)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('sign and submit using the master key of an account with a regular key', async function () {
|
||||
const masterWallet = (await generateFundedWalletWithRegularKey(this.client))
|
||||
.masterWallet
|
||||
it(
|
||||
'sign and submit with a regular key',
|
||||
async () => {
|
||||
const regularKeyWallet = (
|
||||
await generateFundedWalletWithRegularKey(testContext.client)
|
||||
).regularKeyWallet
|
||||
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: masterWallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
testTransaction(this.client, accountSet, masterWallet)
|
||||
})
|
||||
await testTransaction(testContext.client, accountSet, regularKeyWallet)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it('try to sign with master key after disabling', async function () {
|
||||
const masterWallet = (
|
||||
await generateFundedWalletWithRegularKey(this.client, true)
|
||||
).masterWallet
|
||||
it(
|
||||
'sign and submit using the master key of an account with a regular key',
|
||||
async () => {
|
||||
const masterWallet = (
|
||||
await generateFundedWalletWithRegularKey(testContext.client)
|
||||
).masterWallet
|
||||
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: masterWallet.classicAddress,
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: masterWallet.classicAddress,
|
||||
value: '10',
|
||||
},
|
||||
}
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: masterWallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
const client: Client = this.client
|
||||
const response = await client.submit(tx, { wallet: masterWallet })
|
||||
assert.equal(
|
||||
response.result.engine_result,
|
||||
'tefMASTER_DISABLED',
|
||||
'Master key was disabled, yet the master key still was able to sign and submit a transaction',
|
||||
)
|
||||
})
|
||||
await testTransaction(testContext.client, accountSet, masterWallet)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it('sign with regular key after disabling the master key', async function () {
|
||||
const regularKeyWallet = (
|
||||
await generateFundedWalletWithRegularKey(this.client, true)
|
||||
).regularKeyWallet
|
||||
it(
|
||||
'try to sign with master key after disabling',
|
||||
async () => {
|
||||
const masterWallet = (
|
||||
await generateFundedWalletWithRegularKey(testContext.client, true)
|
||||
).masterWallet
|
||||
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: regularKeyWallet.classicAddress,
|
||||
value: '10',
|
||||
},
|
||||
}
|
||||
|
||||
await testTransaction(this.client, tx, regularKeyWallet)
|
||||
})
|
||||
|
||||
it('try to enable and disable a regular key', async function () {
|
||||
const wallets = await generateFundedWalletWithRegularKey(this.client, true)
|
||||
const masterWallet = wallets.masterWallet
|
||||
const regularKeyWallet = wallets.regularKeyWallet
|
||||
|
||||
const enableMasterKey: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: masterWallet.classicAddress,
|
||||
ClearFlag: AccountSetAsfFlags.asfDisableMaster,
|
||||
}
|
||||
|
||||
const client: Client = this.client
|
||||
const response = await client.submit(enableMasterKey, {
|
||||
wallet: masterWallet,
|
||||
})
|
||||
assert.equal(
|
||||
response.result.engine_result,
|
||||
'tefMASTER_DISABLED',
|
||||
'Master key was disabled, yet the master key still was able to sign and submit a transaction',
|
||||
)
|
||||
|
||||
await testTransaction(client, enableMasterKey, regularKeyWallet)
|
||||
|
||||
const turnOffRegularKey: SetRegularKey = {
|
||||
TransactionType: 'SetRegularKey',
|
||||
Account: masterWallet.address,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, turnOffRegularKey, masterWallet)
|
||||
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: regularKeyWallet.classicAddress,
|
||||
value: '10',
|
||||
},
|
||||
}
|
||||
|
||||
const response2 = await client.submit(tx, { wallet: regularKeyWallet })
|
||||
assert.equal(
|
||||
response2.result.engine_result,
|
||||
'tefBAD_AUTH',
|
||||
'Regular key should have been disabled, but somehow was still able to sign and submit a transaction.',
|
||||
)
|
||||
})
|
||||
|
||||
it('submit_multisigned transaction with regular keys set', async function () {
|
||||
const client: Client = this.client
|
||||
|
||||
const regularKeyWallet = (await generateFundedWalletWithRegularKey(client))
|
||||
.regularKeyWallet
|
||||
const signerWallet2 = await generateFundedWallet(this.client)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: masterWallet.classicAddress,
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: masterWallet.classicAddress,
|
||||
value: '10',
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
}
|
||||
|
||||
const client: Client = testContext.client
|
||||
const response = await client.submit(tx, { wallet: masterWallet })
|
||||
assert.equal(
|
||||
response.result.engine_result,
|
||||
'tefMASTER_DISABLED',
|
||||
'Master key was disabled, yet the master key still was able to sign and submit a transaction',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'sign with regular key after disabling the master key',
|
||||
async () => {
|
||||
const regularKeyWallet = (
|
||||
await generateFundedWalletWithRegularKey(testContext.client, true)
|
||||
).regularKeyWallet
|
||||
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: regularKeyWallet.classicAddress,
|
||||
value: '10',
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(this.client, signerListSet, this.wallet)
|
||||
}
|
||||
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const signed1 = regularKeyWallet.sign(accountSetTx, true)
|
||||
const signed2 = signerWallet2.sign(accountSetTx, true)
|
||||
const multisigned = multisign([signed1.tx_blob, signed2.tx_blob])
|
||||
const submitResponse = await client.submit(multisigned)
|
||||
await ledgerAccept(client)
|
||||
await testTransaction(testContext.client, tx, regularKeyWallet)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
assert.strictEqual(submitResponse.result.engine_result, 'tesSUCCESS')
|
||||
await verifySubmittedTransaction(this.client, multisigned)
|
||||
})
|
||||
it(
|
||||
'try to enable and disable a regular key',
|
||||
async () => {
|
||||
const wallets = await generateFundedWalletWithRegularKey(
|
||||
testContext.client,
|
||||
true,
|
||||
)
|
||||
const masterWallet = wallets.masterWallet
|
||||
const regularKeyWallet = wallets.regularKeyWallet
|
||||
|
||||
it('try multisigning with the account address used to set up a regular key', async function () {
|
||||
const client: Client = this.client
|
||||
const enableMasterKey: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: masterWallet.classicAddress,
|
||||
ClearFlag: AccountSetAsfFlags.asfDisableMaster,
|
||||
}
|
||||
|
||||
const regularKeyWallet = (await generateFundedWalletWithRegularKey(client))
|
||||
.regularKeyWallet
|
||||
const signerWallet2 = await generateFundedWallet(this.client)
|
||||
const client: Client = testContext.client
|
||||
const response = await client.submit(enableMasterKey, {
|
||||
wallet: masterWallet,
|
||||
})
|
||||
assert.equal(
|
||||
response.result.engine_result,
|
||||
'tefMASTER_DISABLED',
|
||||
'Master key was disabled, yet the master key still was able to sign and submit a transaction',
|
||||
)
|
||||
|
||||
const sameKeyDefaultAddressWallet = new Wallet(
|
||||
regularKeyWallet.publicKey,
|
||||
regularKeyWallet.privateKey,
|
||||
)
|
||||
await testTransaction(client, enableMasterKey, regularKeyWallet)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
const turnOffRegularKey: SetRegularKey = {
|
||||
TransactionType: 'SetRegularKey',
|
||||
Account: masterWallet.address,
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, turnOffRegularKey, masterWallet)
|
||||
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: regularKeyWallet.classicAddress,
|
||||
value: '10',
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(this.client, signerListSet, this.wallet)
|
||||
}
|
||||
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const signed1 = sameKeyDefaultAddressWallet.sign(accountSetTx, true)
|
||||
const signed2 = signerWallet2.sign(accountSetTx, true)
|
||||
const multisigned = multisign([signed1.tx_blob, signed2.tx_blob])
|
||||
const submitResponse = await client.submit(multisigned)
|
||||
await ledgerAccept(client)
|
||||
assert.strictEqual(submitResponse.result.engine_result, 'tefBAD_SIGNATURE')
|
||||
})
|
||||
const response2 = await client.submit(tx, { wallet: regularKeyWallet })
|
||||
assert.equal(
|
||||
response2.result.engine_result,
|
||||
'tefBAD_AUTH',
|
||||
'Regular key should have been disabled, but somehow was still able to sign and submit a transaction.',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'submit_multisigned transaction with regular keys set',
|
||||
async () => {
|
||||
const client: Client = testContext.client
|
||||
|
||||
const regularKeyWallet = (
|
||||
await generateFundedWalletWithRegularKey(client)
|
||||
).regularKeyWallet
|
||||
const signerWallet2 = await generateFundedWallet(testContext.client)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(
|
||||
testContext.client,
|
||||
signerListSet,
|
||||
testContext.wallet,
|
||||
)
|
||||
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const signed1 = regularKeyWallet.sign(accountSetTx, true)
|
||||
const signed2 = signerWallet2.sign(accountSetTx, true)
|
||||
const multisigned = multisign([signed1.tx_blob, signed2.tx_blob])
|
||||
const submitResponse = await client.submit(multisigned)
|
||||
await ledgerAccept(client)
|
||||
|
||||
assert.strictEqual(submitResponse.result.engine_result, 'tesSUCCESS')
|
||||
await verifySubmittedTransaction(testContext.client, multisigned)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'try multisigning with the account address used to set up a regular key',
|
||||
async () => {
|
||||
const client: Client = testContext.client
|
||||
|
||||
const regularKeyWallet = (
|
||||
await generateFundedWalletWithRegularKey(client)
|
||||
).regularKeyWallet
|
||||
const signerWallet2 = await generateFundedWallet(testContext.client)
|
||||
|
||||
const sameKeyDefaultAddressWallet = new Wallet(
|
||||
regularKeyWallet.publicKey,
|
||||
regularKeyWallet.privateKey,
|
||||
)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: regularKeyWallet.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(
|
||||
testContext.client,
|
||||
signerListSet,
|
||||
testContext.wallet,
|
||||
)
|
||||
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const signed1 = sameKeyDefaultAddressWallet.sign(accountSetTx, true)
|
||||
const signed2 = signerWallet2.sign(accountSetTx, true)
|
||||
const multisigned = multisign([signed1.tx_blob, signed2.tx_blob])
|
||||
const submitResponse = await client.submit(multisigned)
|
||||
await ledgerAccept(client)
|
||||
assert.strictEqual(
|
||||
submitResponse.result.engine_result,
|
||||
'tefBAD_SIGNATURE',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,44 +1,54 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountChannelsRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { AccountChannelsRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_channels', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountChannelsRequest = {
|
||||
command: 'account_channels',
|
||||
account: this.wallet.classicAddress,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.classicAddress,
|
||||
channels: [],
|
||||
ledger_hash:
|
||||
'C8BFA74A740AA22AD9BD724781589319052398B0C6C817B88D55628E07B7B4A1',
|
||||
ledger_index: 150,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: AccountChannelsRequest = {
|
||||
command: 'account_channels',
|
||||
account: testContext.wallet.classicAddress,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: testContext.wallet.classicAddress,
|
||||
channels: [],
|
||||
ledger_hash:
|
||||
'C8BFA74A740AA22AD9BD724781589319052398B0C6C817B88D55628E07B7B4A1',
|
||||
ledger_index: 150,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,45 +1,55 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountCurrenciesRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { AccountCurrenciesRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_currencies', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountCurrenciesRequest = {
|
||||
command: 'account_currencies',
|
||||
account: this.wallet.classicAddress,
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
receive_currencies: [],
|
||||
send_currencies: [],
|
||||
ledger_hash:
|
||||
'C8BFA74A740AA22AD9BD724781589319052398B0C6C817B88D55628E07B7B4A1',
|
||||
ledger_index: 150,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: AccountCurrenciesRequest = {
|
||||
command: 'account_currencies',
|
||||
account: testContext.wallet.classicAddress,
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
receive_currencies: [],
|
||||
send_currencies: [],
|
||||
ledger_hash:
|
||||
'C8BFA74A740AA22AD9BD724781589319052398B0C6C817B88D55628E07B7B4A1',
|
||||
ledger_index: 150,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,74 +1,83 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountInfoRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { AccountInfoRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_info', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountInfoRequest = {
|
||||
command: 'account_info',
|
||||
account: this.wallet.classicAddress,
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account_data: {
|
||||
Account: this.wallet.classicAddress,
|
||||
Balance: '400000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
OwnerCount: 0,
|
||||
PreviousTxnID:
|
||||
'19A8211695785A3A02C1C287D93C2B049E83A9CD609825E721052D63FF4F0EC8',
|
||||
PreviousTxnLgrSeq: 582,
|
||||
Sequence: 283,
|
||||
index:
|
||||
'BD4815E6EB304136E6044F778FB68D4E464CC8DFC59B8F6CC93D90A3709AE194',
|
||||
},
|
||||
ledger_hash:
|
||||
'F0DEEC46A7185BBB535517EE38CF2025973022D5B0532B36407F492521FDB0C6',
|
||||
ledger_index: 582,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(response.result.validated, expected.result.validated)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.equal(typeof response.result.account_data.PreviousTxnID, 'string')
|
||||
assert.equal(typeof response.result.account_data.index, 'string')
|
||||
assert.equal(
|
||||
typeof response.result.account_data.PreviousTxnLgrSeq,
|
||||
'number',
|
||||
)
|
||||
assert.equal(typeof response.result.account_data.Sequence, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result.account_data, [
|
||||
'PreviousTxnID',
|
||||
'PreviousTxnLgrSeq',
|
||||
'Sequence',
|
||||
'index',
|
||||
]),
|
||||
_.omit(expected.result.account_data, [
|
||||
'PreviousTxnID',
|
||||
'PreviousTxnLgrSeq',
|
||||
'Sequence',
|
||||
'index',
|
||||
]),
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: AccountInfoRequest = {
|
||||
command: 'account_info',
|
||||
account: testContext.wallet.classicAddress,
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account_data: {
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Balance: '400000000',
|
||||
Flags: 0,
|
||||
LedgerEntryType: 'AccountRoot',
|
||||
OwnerCount: 0,
|
||||
PreviousTxnID:
|
||||
'19A8211695785A3A02C1C287D93C2B049E83A9CD609825E721052D63FF4F0EC8',
|
||||
PreviousTxnLgrSeq: 582,
|
||||
Sequence: 283,
|
||||
index:
|
||||
'BD4815E6EB304136E6044F778FB68D4E464CC8DFC59B8F6CC93D90A3709AE194',
|
||||
},
|
||||
ledger_hash:
|
||||
'F0DEEC46A7185BBB535517EE38CF2025973022D5B0532B36407F492521FDB0C6',
|
||||
ledger_index: 582,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(response.result.validated, expected.result.validated)
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.equal(typeof response.result.account_data.PreviousTxnID, 'string')
|
||||
assert.equal(typeof response.result.account_data.index, 'string')
|
||||
assert.equal(
|
||||
typeof response.result.account_data.PreviousTxnLgrSeq,
|
||||
'number',
|
||||
)
|
||||
assert.equal(typeof response.result.account_data.Sequence, 'number')
|
||||
assert.deepEqual(
|
||||
omit(response.result.account_data, [
|
||||
'PreviousTxnID',
|
||||
'PreviousTxnLgrSeq',
|
||||
'Sequence',
|
||||
'index',
|
||||
]),
|
||||
omit(expected.result.account_data, [
|
||||
'PreviousTxnID',
|
||||
'PreviousTxnLgrSeq',
|
||||
'Sequence',
|
||||
'index',
|
||||
]),
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,45 +1,55 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountLinesRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { AccountLinesRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_lines', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountLinesRequest = {
|
||||
command: 'account_lines',
|
||||
account: this.wallet.classicAddress,
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.classicAddress,
|
||||
ledger_hash:
|
||||
'0C09AAFA88AC1A616058220CF33269788D3985DAA6F2386196D4A7404252BB61',
|
||||
ledger_index: 1074,
|
||||
lines: [],
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: AccountLinesRequest = {
|
||||
command: 'account_lines',
|
||||
account: testContext.wallet.classicAddress,
|
||||
strict: true,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: testContext.wallet.classicAddress,
|
||||
ledger_hash:
|
||||
'0C09AAFA88AC1A616058220CF33269788D3985DAA6F2386196D4A7404252BB61',
|
||||
ledger_index: 1074,
|
||||
lines: [],
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,44 +1,54 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountObjectsRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { AccountObjectsRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_objects', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountObjectsRequest = {
|
||||
command: 'account_objects',
|
||||
account: this.wallet.classicAddress,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.classicAddress,
|
||||
account_objects: [],
|
||||
ledger_hash:
|
||||
'28D68B351ED58B9819502EF5FC05BA4412A048597E5159E1C226703BDF7C7897',
|
||||
ledger_index: 1294,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: AccountObjectsRequest = {
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: testContext.wallet.classicAddress,
|
||||
account_objects: [],
|
||||
ledger_hash:
|
||||
'28D68B351ED58B9819502EF5FC05BA4412A048597E5159E1C226703BDF7C7897',
|
||||
ledger_index: 1294,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,41 +1,51 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountOffersRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { AccountOffersRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_offers', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountOffersRequest = {
|
||||
command: 'account_offers',
|
||||
account: this.wallet.classicAddress,
|
||||
strict: true,
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.classicAddress,
|
||||
ledger_current_index: 1443,
|
||||
offers: [],
|
||||
validated: false,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_current_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, 'ledger_current_index'),
|
||||
_.omit(expected.result, 'ledger_current_index'),
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: AccountOffersRequest = {
|
||||
command: 'account_offers',
|
||||
account: testContext.wallet.classicAddress,
|
||||
strict: true,
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: testContext.wallet.classicAddress,
|
||||
ledger_current_index: 1443,
|
||||
offers: [],
|
||||
validated: false,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_current_index, 'number')
|
||||
assert.deepEqual(
|
||||
omit(response.result, 'ledger_current_index'),
|
||||
omit(expected.result, 'ledger_current_index'),
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,99 +1,114 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountTxRequest } from 'xrpl-local'
|
||||
|
||||
import {
|
||||
AccountTxRequest,
|
||||
Payment,
|
||||
type TransactionMetadata,
|
||||
} from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('account_tx', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: AccountTxRequest = {
|
||||
command: 'account_tx',
|
||||
account: this.wallet.classicAddress,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
result: {
|
||||
account: this.wallet.classicAddress,
|
||||
limit: 400,
|
||||
transactions: [
|
||||
{
|
||||
tx: {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
Amount: '400000000',
|
||||
Destination: this.wallet.classicAddress,
|
||||
Fee: '12',
|
||||
Flags: 0,
|
||||
LastLedgerSequence: 1753,
|
||||
Sequence: 843,
|
||||
SigningPubKey:
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020',
|
||||
TransactionType: 'Payment',
|
||||
TxnSignature:
|
||||
'30440220693D244BC13967E3DA67BDC974096784ED03DD4ACE6F36645E5176988452AFCF02200F8AB172432913899F27EC5523829AEDAD00CC2445690400E294EDF652A85945',
|
||||
date: 685747005,
|
||||
hash: '2E68BC15813B4A836FAC4D80E42E6FDA6410E99AB973937DEA5E6C2E9A116BAB',
|
||||
inLedger: 1734,
|
||||
ledger_index: 1734,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(response.result.account, expected.result.account)
|
||||
assert.equal(
|
||||
response.result.transactions[0].meta.TransactionResult,
|
||||
'tesSUCCESS',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx.LastLedgerSequence,
|
||||
'number',
|
||||
)
|
||||
assert.equal(typeof response.result.transactions[0].tx.Sequence, 'number')
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx.SigningPubKey,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx.TxnSignature,
|
||||
'string',
|
||||
)
|
||||
assert.equal(typeof response.result.transactions[0].tx.Fee, 'string')
|
||||
assert.equal(typeof response.result.transactions[0].tx.hash, 'string')
|
||||
assert.equal(typeof response.result.transactions[0].tx.inLedger, 'number')
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx.ledger_index,
|
||||
'number',
|
||||
)
|
||||
|
||||
const responseTx = response.result.transactions[0].tx
|
||||
const expectedTx = expected.result.transactions[0].tx
|
||||
assert.deepEqual(
|
||||
[
|
||||
responseTx.Flags,
|
||||
responseTx.TransactionType,
|
||||
responseTx.Account,
|
||||
responseTx.Amount,
|
||||
responseTx.Destination,
|
||||
],
|
||||
[
|
||||
expectedTx.Flags,
|
||||
expectedTx.TransactionType,
|
||||
expectedTx.Account,
|
||||
expectedTx.Amount,
|
||||
expectedTx.Destination,
|
||||
],
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: AccountTxRequest = {
|
||||
command: 'account_tx',
|
||||
account: testContext.wallet.classicAddress,
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
result: {
|
||||
account: testContext.wallet.classicAddress,
|
||||
limit: 400,
|
||||
transactions: [
|
||||
{
|
||||
tx: {
|
||||
Account: 'rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh',
|
||||
Amount: '400000000',
|
||||
Destination: testContext.wallet.classicAddress,
|
||||
Fee: '12',
|
||||
Flags: 0,
|
||||
LastLedgerSequence: 1753,
|
||||
Sequence: 843,
|
||||
SigningPubKey:
|
||||
'0330E7FC9D56BB25D6893BA3F317AE5BCF33B3291BD63DB32654A313222F7FD020',
|
||||
TransactionType: 'Payment',
|
||||
TxnSignature:
|
||||
'30440220693D244BC13967E3DA67BDC974096784ED03DD4ACE6F36645E5176988452AFCF02200F8AB172432913899F27EC5523829AEDAD00CC2445690400E294EDF652A85945',
|
||||
date: 685747005,
|
||||
hash: '2E68BC15813B4A836FAC4D80E42E6FDA6410E99AB973937DEA5E6C2E9A116BAB',
|
||||
ledger_index: 1734,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(response.result.account, expected.result.account)
|
||||
assert.equal(
|
||||
(response.result.transactions[0].meta as TransactionMetadata)
|
||||
.TransactionResult,
|
||||
'tesSUCCESS',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx?.LastLedgerSequence,
|
||||
'number',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx?.Sequence,
|
||||
'number',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx?.SigningPubKey,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx?.TxnSignature,
|
||||
'string',
|
||||
)
|
||||
assert.equal(typeof response.result.transactions[0].tx?.Fee, 'string')
|
||||
assert.equal(typeof response.result.transactions[0].tx?.hash, 'string')
|
||||
assert.equal(
|
||||
typeof response.result.transactions[0].tx?.ledger_index,
|
||||
'number',
|
||||
)
|
||||
|
||||
const responseTx = response.result.transactions[0].tx as Payment
|
||||
const expectedTx = expected.result.transactions[0].tx
|
||||
assert.deepEqual(
|
||||
[
|
||||
responseTx.Flags,
|
||||
responseTx.TransactionType,
|
||||
responseTx.Account,
|
||||
responseTx.Amount,
|
||||
responseTx.Destination,
|
||||
],
|
||||
[
|
||||
expectedTx.Flags,
|
||||
expectedTx.TransactionType,
|
||||
expectedTx.Account,
|
||||
expectedTx.Amount,
|
||||
expectedTx.Destination,
|
||||
],
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,42 +1,51 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { BookOffersRequest, BookOffersResponse } from 'xrpl-local'
|
||||
|
||||
import { BookOffersRequest, BookOffersResponse } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('book_offers', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const bookOffer: BookOffersRequest = {
|
||||
command: 'book_offers',
|
||||
taker_gets: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
taker_pays: {
|
||||
currency: 'USD',
|
||||
issuer: this.wallet.classicAddress,
|
||||
},
|
||||
}
|
||||
const response = await this.client.request(bookOffer)
|
||||
|
||||
const expectedResponse: BookOffersResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
offers: response.result.offers,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const bookOffer: BookOffersRequest = {
|
||||
command: 'book_offers',
|
||||
taker_gets: {
|
||||
currency: 'XRP',
|
||||
},
|
||||
taker_pays: {
|
||||
currency: 'USD',
|
||||
issuer: testContext.wallet.classicAddress,
|
||||
},
|
||||
}
|
||||
const response = await testContext.client.request(bookOffer)
|
||||
|
||||
const expectedResponse: BookOffersResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
offers: response.result.offers,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,40 +1,49 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { ChannelVerifyRequest, ChannelVerifyResponse } from 'xrpl-local'
|
||||
|
||||
import { ChannelVerifyRequest, ChannelVerifyResponse } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('channel_verify', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const channelVerify: ChannelVerifyRequest = {
|
||||
command: 'channel_verify',
|
||||
channel_id:
|
||||
'5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3',
|
||||
signature:
|
||||
'304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064',
|
||||
public_key: 'aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3',
|
||||
amount: '1000000',
|
||||
}
|
||||
|
||||
const response = await this.client.request(channelVerify)
|
||||
|
||||
const expectedResponse: ChannelVerifyResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
signature_verified: response.result.signature_verified,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const channelVerify: ChannelVerifyRequest = {
|
||||
command: 'channel_verify',
|
||||
channel_id:
|
||||
'5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3',
|
||||
signature:
|
||||
'304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064',
|
||||
public_key: 'aB44YfzW24VDEJQ2UuLPV2PvqcPCSoLnL7y5M1EzhdW4LnK5xMS3',
|
||||
amount: '1000000',
|
||||
}
|
||||
|
||||
const response = await testContext.client.request(channelVerify)
|
||||
|
||||
const expectedResponse: ChannelVerifyResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
signature_verified: response.result.signature_verified,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,42 +1,54 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { DepositAuthorizedRequest, DepositAuthorizedResponse } from 'xrpl-local'
|
||||
|
||||
import {
|
||||
DepositAuthorizedRequest,
|
||||
DepositAuthorizedResponse,
|
||||
} from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { generateFundedWallet } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('deposit_authorized', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const depositAuthorized: DepositAuthorizedRequest = {
|
||||
command: 'deposit_authorized',
|
||||
source_account: this.wallet.classicAddress,
|
||||
destination_account: wallet2.classicAddress,
|
||||
}
|
||||
|
||||
const response = await this.client.request(depositAuthorized)
|
||||
|
||||
const expectedResponse: DepositAuthorizedResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
deposit_authorized: true,
|
||||
destination_account: depositAuthorized.destination_account,
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
source_account: depositAuthorized.source_account,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const wallet2 = await generateFundedWallet(testContext.client)
|
||||
const depositAuthorized: DepositAuthorizedRequest = {
|
||||
command: 'deposit_authorized',
|
||||
source_account: testContext.wallet.classicAddress,
|
||||
destination_account: wallet2.classicAddress,
|
||||
}
|
||||
|
||||
const response = await testContext.client.request(depositAuthorized)
|
||||
|
||||
const expectedResponse: DepositAuthorizedResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
deposit_authorized: true,
|
||||
destination_account: depositAuthorized.destination_account,
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
source_account: depositAuthorized.source_account,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,52 +1,62 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { FeeRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { FeeRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('fee', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: FeeRequest = {
|
||||
command: 'fee',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
current_ledger_size: '0',
|
||||
current_queue_size: '0',
|
||||
drops: {
|
||||
base_fee: '10',
|
||||
median_fee: '5000',
|
||||
minimum_fee: '10',
|
||||
open_ledger_fee: '10',
|
||||
},
|
||||
expected_ledger_size: '1000',
|
||||
ledger_current_index: 2925,
|
||||
levels: {
|
||||
median_level: '128000',
|
||||
minimum_level: '256',
|
||||
open_ledger_level: '256',
|
||||
reference_level: '256',
|
||||
},
|
||||
max_queue_size: '20000',
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_current_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_current_index']),
|
||||
_.omit(expected.result, ['ledger_current_index']),
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: FeeRequest = {
|
||||
command: 'fee',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
current_ledger_size: '0',
|
||||
current_queue_size: '0',
|
||||
drops: {
|
||||
base_fee: '10',
|
||||
median_fee: '5000',
|
||||
minimum_fee: '10',
|
||||
open_ledger_fee: '10',
|
||||
},
|
||||
expected_ledger_size: '1000',
|
||||
ledger_current_index: 2925,
|
||||
levels: {
|
||||
median_level: '128000',
|
||||
minimum_level: '256',
|
||||
open_ledger_level: '256',
|
||||
reference_level: '256',
|
||||
},
|
||||
max_queue_size: '20000',
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_current_index, 'number')
|
||||
assert.deepEqual(
|
||||
omit(response.result, ['ledger_current_index']),
|
||||
omit(expected.result, ['ledger_current_index']),
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,44 +1,54 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { GatewayBalancesRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { GatewayBalancesRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('gateway_balances', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: GatewayBalancesRequest = {
|
||||
command: 'gateway_balances',
|
||||
account: this.wallet.classicAddress,
|
||||
ledger_index: 'validated',
|
||||
strict: true,
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: this.wallet.classicAddress,
|
||||
ledger_hash:
|
||||
'28D68B351ED58B9819502EF5FC05BA4412A048597E5159E1C226703BDF7C7897',
|
||||
ledger_index: 1294,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
_.omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
_.omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: GatewayBalancesRequest = {
|
||||
command: 'gateway_balances',
|
||||
account: testContext.wallet.classicAddress,
|
||||
ledger_index: 'validated',
|
||||
strict: true,
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
account: testContext.wallet.classicAddress,
|
||||
ledger_hash:
|
||||
'28D68B351ED58B9819502EF5FC05BA4412A048597E5159E1C226703BDF7C7897',
|
||||
ledger_index: 1294,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.ledger_hash, 'string')
|
||||
assert.equal(typeof response.result.ledger_index, 'number')
|
||||
assert.deepEqual(
|
||||
omit(response.result, ['ledger_hash', 'ledger_index']),
|
||||
omit(expected.result, ['ledger_hash', 'ledger_index']),
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,75 +1,84 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { LedgerRequest, LedgerResponse } from 'xrpl-local'
|
||||
import { Ledger } from 'xrpl-local/models/ledger'
|
||||
|
||||
import { LedgerRequest, LedgerResponse } from '../../../src'
|
||||
import { Ledger } from '../../../src/models/ledger'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const ledgerRequest: LedgerRequest = {
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
ledger: {
|
||||
accepted: true,
|
||||
account_hash: 'string',
|
||||
close_flags: 0,
|
||||
close_time: 0,
|
||||
close_time_human: 'string',
|
||||
},
|
||||
ledger_hash: 'string',
|
||||
ledger_index: 1,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
|
||||
const ledgerResponse: LedgerResponse = await this.client.request(
|
||||
ledgerRequest,
|
||||
)
|
||||
|
||||
assert.equal(ledgerResponse.type, expected.type)
|
||||
|
||||
assert.equal(ledgerResponse.result.validated, expected.result.validated)
|
||||
assert.typeOf(ledgerResponse.result.ledger_hash, 'string')
|
||||
assert.typeOf(ledgerResponse.result.ledger_index, 'number')
|
||||
|
||||
const ledger = ledgerResponse.result.ledger as Ledger & {
|
||||
accepted: boolean
|
||||
hash: string
|
||||
seqNum: string
|
||||
}
|
||||
assert.equal(ledger.closed, true)
|
||||
const stringTypes = [
|
||||
'account_hash',
|
||||
'close_time_human',
|
||||
'ledger_hash',
|
||||
'ledger_index',
|
||||
'parent_hash',
|
||||
'total_coins',
|
||||
'transaction_hash',
|
||||
]
|
||||
stringTypes.forEach((strType) => assert.typeOf(ledger[strType], 'string'))
|
||||
const numTypes = [
|
||||
'close_flags',
|
||||
'close_time',
|
||||
'close_time_resolution',
|
||||
'parent_close_time',
|
||||
]
|
||||
numTypes.forEach((numType) => assert.typeOf(ledger[numType], 'number'))
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const ledgerRequest: LedgerRequest = {
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
}
|
||||
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
ledger: {
|
||||
accepted: true,
|
||||
account_hash: 'string',
|
||||
close_flags: 0,
|
||||
close_time: 0,
|
||||
close_time_human: 'string',
|
||||
},
|
||||
ledger_hash: 'string',
|
||||
ledger_index: 1,
|
||||
validated: true,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
|
||||
const ledgerResponse: LedgerResponse = await testContext.client.request(
|
||||
ledgerRequest,
|
||||
)
|
||||
|
||||
assert.equal(ledgerResponse.type, expected.type)
|
||||
|
||||
assert.equal(ledgerResponse.result.validated, expected.result.validated)
|
||||
assert.typeOf(ledgerResponse.result.ledger_hash, 'string')
|
||||
assert.typeOf(ledgerResponse.result.ledger_index, 'number')
|
||||
|
||||
const ledger = ledgerResponse.result.ledger as Ledger & {
|
||||
accepted: boolean
|
||||
hash: string
|
||||
seqNum: string
|
||||
}
|
||||
assert.equal(ledger.closed, true)
|
||||
const stringTypes = [
|
||||
'account_hash',
|
||||
'close_time_human',
|
||||
'ledger_hash',
|
||||
'ledger_index',
|
||||
'parent_hash',
|
||||
'total_coins',
|
||||
'transaction_hash',
|
||||
]
|
||||
stringTypes.forEach((strType) => assert.typeOf(ledger[strType], 'string'))
|
||||
const numTypes = [
|
||||
'close_flags',
|
||||
'close_time',
|
||||
'close_time_resolution',
|
||||
'parent_close_time',
|
||||
]
|
||||
numTypes.forEach((numType) => assert.typeOf(ledger[numType], 'number'))
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,36 +1,45 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { LedgerClosedRequest, LedgerClosedResponse } from 'xrpl-local'
|
||||
|
||||
import { LedgerClosedRequest, LedgerClosedResponse } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger_closed', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const ledgerClosedRequest: LedgerClosedRequest = {
|
||||
command: 'ledger_closed',
|
||||
}
|
||||
const ledgerClosedResponse: LedgerClosedResponse =
|
||||
await this.client.request(ledgerClosedRequest)
|
||||
|
||||
const expectedResponse: LedgerClosedResponse = {
|
||||
id: ledgerClosedResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_hash: 'string',
|
||||
ledger_index: 1,
|
||||
},
|
||||
}
|
||||
assert.equal(ledgerClosedResponse.type, expectedResponse.type)
|
||||
assert.typeOf(ledgerClosedResponse.result.ledger_hash, 'string')
|
||||
assert.typeOf(ledgerClosedResponse.result.ledger_index, 'number')
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const ledgerClosedRequest: LedgerClosedRequest = {
|
||||
command: 'ledger_closed',
|
||||
}
|
||||
const ledgerClosedResponse: LedgerClosedResponse =
|
||||
await testContext.client.request(ledgerClosedRequest)
|
||||
|
||||
const expectedResponse: LedgerClosedResponse = {
|
||||
id: ledgerClosedResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_hash: 'string',
|
||||
ledger_index: 1,
|
||||
},
|
||||
}
|
||||
assert.equal(ledgerClosedResponse.type, expectedResponse.type)
|
||||
assert.typeOf(ledgerClosedResponse.result.ledger_hash, 'string')
|
||||
assert.typeOf(ledgerClosedResponse.result.ledger_index, 'number')
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,36 +1,45 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { LedgerCurrentResponse, LedgerCurrentRequest } from 'xrpl-local'
|
||||
|
||||
import { LedgerCurrentResponse, LedgerCurrentRequest } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger_current', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const ledgerCurrentRequest: LedgerCurrentRequest = {
|
||||
command: 'ledger_current',
|
||||
}
|
||||
|
||||
const ledgerCurrentResponse = await this.client.request(
|
||||
ledgerCurrentRequest,
|
||||
)
|
||||
|
||||
const expectedResponse: LedgerCurrentResponse = {
|
||||
id: ledgerCurrentResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_current_index: 1,
|
||||
},
|
||||
}
|
||||
assert.equal(ledgerCurrentResponse.type, expectedResponse.type)
|
||||
assert.typeOf(ledgerCurrentResponse.result.ledger_current_index, 'number')
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const ledgerCurrentRequest: LedgerCurrentRequest = {
|
||||
command: 'ledger_current',
|
||||
}
|
||||
|
||||
const ledgerCurrentResponse = await testContext.client.request(
|
||||
ledgerCurrentRequest,
|
||||
)
|
||||
|
||||
const expectedResponse: LedgerCurrentResponse = {
|
||||
id: ledgerCurrentResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
ledger_current_index: 1,
|
||||
},
|
||||
}
|
||||
assert.equal(ledgerCurrentResponse.type, expectedResponse.type)
|
||||
assert.typeOf(ledgerCurrentResponse.result.ledger_current_index, 'number')
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,55 +1,67 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { LedgerDataRequest } from 'xrpl-local'
|
||||
|
||||
import { LedgerDataRequest } from '../../../src'
|
||||
import type { BinaryLedgerEntry } from '../../../src/models/methods/ledgerData'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger_data', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const ledgerDataRequest: LedgerDataRequest = {
|
||||
command: 'ledger_data',
|
||||
ledger_index: 'validated',
|
||||
limit: 5,
|
||||
binary: true,
|
||||
}
|
||||
|
||||
const ledgerDataResponse = await this.client.request(ledgerDataRequest)
|
||||
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
ledger_hash: 'string',
|
||||
ledger_index: 0,
|
||||
marker: 'string',
|
||||
state: [
|
||||
{
|
||||
data: 'string',
|
||||
index: 'string',
|
||||
},
|
||||
],
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
|
||||
assert.equal(ledgerDataResponse.type, expected.type)
|
||||
|
||||
assert.typeOf(ledgerDataResponse.result.ledger_hash, 'string')
|
||||
assert.typeOf(ledgerDataResponse.result.ledger_index, 'number')
|
||||
assert.typeOf(ledgerDataResponse.result.marker, 'string')
|
||||
|
||||
assert.equal(ledgerDataResponse.result.state.length, 5)
|
||||
ledgerDataResponse.result.state.forEach((item) => {
|
||||
assert.typeOf(item.data, 'string')
|
||||
assert.typeOf(item.index, 'string')
|
||||
})
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const ledgerDataRequest: LedgerDataRequest = {
|
||||
command: 'ledger_data',
|
||||
ledger_index: 'validated',
|
||||
limit: 5,
|
||||
binary: true,
|
||||
}
|
||||
|
||||
const ledgerDataResponse = await testContext.client.request(
|
||||
ledgerDataRequest,
|
||||
)
|
||||
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
ledger_hash: 'string',
|
||||
ledger_index: 0,
|
||||
marker: 'string',
|
||||
state: [
|
||||
{
|
||||
data: 'string',
|
||||
index: 'string',
|
||||
},
|
||||
],
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
|
||||
assert.equal(ledgerDataResponse.type, expected.type)
|
||||
|
||||
assert.typeOf(ledgerDataResponse.result.ledger_hash, 'string')
|
||||
assert.typeOf(ledgerDataResponse.result.ledger_index, 'number')
|
||||
assert.typeOf(ledgerDataResponse.result.marker, 'string')
|
||||
|
||||
assert.equal(ledgerDataResponse.result.state.length, 5)
|
||||
ledgerDataResponse.result.state.forEach((item) => {
|
||||
assert.typeOf((item as BinaryLedgerEntry).data, 'string')
|
||||
assert.typeOf(item.index, 'string')
|
||||
})
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,47 +1,58 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { LedgerEntryRequest, LedgerEntryResponse } from 'xrpl-local'
|
||||
|
||||
import { LedgerEntryRequest, LedgerEntryResponse } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ledger_entry', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const validatedLedgerResponse = await this.client.request({
|
||||
command: 'ledger_data',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
|
||||
assert.equal(validatedLedgerResponse.type, 'response')
|
||||
const ledgerEntryIndex = validatedLedgerResponse.result.state[0].index
|
||||
|
||||
const ledgerEntryRequest: LedgerEntryRequest = {
|
||||
command: 'ledger_entry',
|
||||
index: ledgerEntryIndex,
|
||||
}
|
||||
|
||||
const ledgerEntryResponse = await this.client.request(ledgerEntryRequest)
|
||||
|
||||
const expectedResponse: LedgerEntryResponse = {
|
||||
id: ledgerEntryResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
index: ledgerEntryIndex,
|
||||
ledger_current_index: ledgerEntryResponse.result.ledger_current_index,
|
||||
node: ledgerEntryResponse.result.node,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(ledgerEntryResponse.type, 'response')
|
||||
assert.deepEqual(ledgerEntryResponse, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const validatedLedgerResponse = await testContext.client.request({
|
||||
command: 'ledger_data',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
|
||||
assert.equal(validatedLedgerResponse.type, 'response')
|
||||
const ledgerEntryIndex = validatedLedgerResponse.result.state[0].index
|
||||
|
||||
const ledgerEntryRequest: LedgerEntryRequest = {
|
||||
command: 'ledger_entry',
|
||||
index: ledgerEntryIndex,
|
||||
}
|
||||
|
||||
const ledgerEntryResponse = await testContext.client.request(
|
||||
ledgerEntryRequest,
|
||||
)
|
||||
|
||||
const expectedResponse: LedgerEntryResponse = {
|
||||
id: ledgerEntryResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
index: ledgerEntryIndex,
|
||||
ledger_current_index: ledgerEntryResponse.result.ledger_current_index,
|
||||
node: ledgerEntryResponse.result.node,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.equal(ledgerEntryResponse.type, 'response')
|
||||
assert.deepEqual(ledgerEntryResponse, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,57 +1,70 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { NoRippleCheckRequest } from 'xrpl-local'
|
||||
|
||||
import { NoRippleCheckRequest, type AccountSet } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('noripple_check', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const request: NoRippleCheckRequest = {
|
||||
command: 'noripple_check',
|
||||
account: this.wallet.classicAddress,
|
||||
role: 'gateway',
|
||||
ledger_index: 'current',
|
||||
transactions: true,
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
ledger_current_index: 2535,
|
||||
problems: ['You should immediately set your default ripple flag'],
|
||||
transactions: [
|
||||
{
|
||||
Account: this.wallet.classicAddress,
|
||||
Fee: 10,
|
||||
Sequence: 1268,
|
||||
SetFlag: 8,
|
||||
TransactionType: 'AccountSet',
|
||||
},
|
||||
],
|
||||
validated: false,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.transactions[0].Fee, 'number')
|
||||
assert.equal(typeof response.result.transactions[0].Sequence, 'number')
|
||||
assert.equal(typeof response.result.problems, 'object')
|
||||
assert.equal(typeof response.result.problems[0], 'string')
|
||||
|
||||
const responseTx = response.result.transactions[0]
|
||||
const expectedTx = expected.result.transactions[0]
|
||||
assert.deepEqual(
|
||||
[responseTx.Account, responseTx.SetFlag, responseTx.TransactionType],
|
||||
[expectedTx.Account, expectedTx.SetFlag, expectedTx.TransactionType],
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: NoRippleCheckRequest = {
|
||||
command: 'noripple_check',
|
||||
account: testContext.wallet.classicAddress,
|
||||
role: 'gateway',
|
||||
ledger_index: 'current',
|
||||
transactions: true,
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
ledger_current_index: 2535,
|
||||
problems: ['You should immediately set your default ripple flag'],
|
||||
transactions: [
|
||||
{
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Fee: 10,
|
||||
Sequence: 1268,
|
||||
SetFlag: 8,
|
||||
TransactionType: 'AccountSet',
|
||||
},
|
||||
],
|
||||
validated: false,
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(typeof response.result.transactions[0].Fee, 'number')
|
||||
assert.equal(typeof response.result.transactions[0].Sequence, 'number')
|
||||
assert.equal(typeof response.result.problems, 'object')
|
||||
assert.equal(typeof response.result.problems[0], 'string')
|
||||
|
||||
const responseTx = response.result.transactions[0]
|
||||
const expectedTx = expected.result.transactions[0]
|
||||
assert.deepEqual(
|
||||
[
|
||||
responseTx.Account,
|
||||
(responseTx as AccountSet).SetFlag,
|
||||
responseTx.TransactionType,
|
||||
],
|
||||
[expectedTx.Account, expectedTx.SetFlag, expectedTx.TransactionType],
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,107 +1,121 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import {
|
||||
PathFindRequest,
|
||||
PathFindResponse,
|
||||
Client,
|
||||
PathFindStream,
|
||||
} from 'xrpl-local'
|
||||
|
||||
} from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { generateFundedWallet, ledgerAccept, subscribeDone } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('path_find', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const pathFind: PathFindRequest = {
|
||||
command: 'path_find',
|
||||
subcommand: 'create',
|
||||
source_account: this.wallet.classicAddress,
|
||||
destination_account: wallet2.classicAddress,
|
||||
destination_amount: '100',
|
||||
}
|
||||
|
||||
const response = await this.client.request(pathFind)
|
||||
|
||||
const expectedResponse: PathFindResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
alternatives: response.result.alternatives,
|
||||
destination_account: pathFind.destination_account,
|
||||
destination_amount: pathFind.destination_amount,
|
||||
source_account: pathFind.source_account,
|
||||
full_reply: false,
|
||||
id: response.id,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const wallet2 = await generateFundedWallet(testContext.client)
|
||||
const pathFind: PathFindRequest = {
|
||||
command: 'path_find',
|
||||
subcommand: 'create',
|
||||
source_account: testContext.wallet.classicAddress,
|
||||
destination_account: wallet2.classicAddress,
|
||||
destination_amount: '100',
|
||||
}
|
||||
|
||||
const response = await testContext.client.request(pathFind)
|
||||
|
||||
const expectedResponse: PathFindResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
alternatives: response.result.alternatives,
|
||||
destination_account: pathFind.destination_account,
|
||||
destination_amount: pathFind.destination_amount,
|
||||
source_account: pathFind.source_account,
|
||||
full_reply: false,
|
||||
id: response.id,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
/**
|
||||
* For other stream style tests look at integration/requests/subscribe.ts
|
||||
* Note: This test uses '.then' to avoid awaits in order to use 'done' style tests.
|
||||
*/
|
||||
it('path_find stream succeeds', function (done) {
|
||||
generateFundedWallet(this.client)
|
||||
.then((wallet2) => {
|
||||
const pathFind: PathFindRequest = {
|
||||
command: 'path_find',
|
||||
subcommand: 'create',
|
||||
source_account: this.wallet.classicAddress,
|
||||
destination_account: wallet2.classicAddress,
|
||||
destination_amount: '100',
|
||||
}
|
||||
it(
|
||||
'path_find stream succeeds',
|
||||
async () => {
|
||||
const wallet2 = await generateFundedWallet(testContext.client)
|
||||
const pathFind: PathFindRequest = {
|
||||
command: 'path_find',
|
||||
subcommand: 'create',
|
||||
source_account: testContext.wallet.classicAddress,
|
||||
destination_account: wallet2.classicAddress,
|
||||
destination_amount: '100',
|
||||
}
|
||||
|
||||
const expectedStreamResult: PathFindStream = {
|
||||
type: 'path_find',
|
||||
source_account: pathFind.source_account,
|
||||
destination_account: pathFind.destination_account,
|
||||
destination_amount: pathFind.destination_amount,
|
||||
full_reply: true,
|
||||
id: 10,
|
||||
alternatives: [],
|
||||
}
|
||||
const expectedStreamResult: PathFindStream = {
|
||||
type: 'path_find',
|
||||
source_account: pathFind.source_account,
|
||||
destination_account: pathFind.destination_account,
|
||||
destination_amount: pathFind.destination_amount,
|
||||
full_reply: true,
|
||||
id: 10,
|
||||
alternatives: [],
|
||||
}
|
||||
|
||||
const client: Client = this.client
|
||||
const client: Client = testContext.client
|
||||
|
||||
const pathFindPromise = new Promise<void>((resolve) => {
|
||||
client.on('path_find', (path) => {
|
||||
assert.equal(path.type, 'path_find')
|
||||
assert.deepEqual(
|
||||
_.omit(path, 'id'),
|
||||
_.omit(expectedStreamResult, 'id'),
|
||||
)
|
||||
subscribeDone(this.client, done)
|
||||
})
|
||||
|
||||
this.client.request(pathFind).then((response) => {
|
||||
const expectedResponse: PathFindResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
alternatives: response.result.alternatives,
|
||||
destination_account: pathFind.destination_account,
|
||||
destination_amount: pathFind.destination_amount,
|
||||
source_account: pathFind.source_account,
|
||||
full_reply: false,
|
||||
id: response.id,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
assert.deepEqual(omit(path, 'id'), omit(expectedStreamResult, 'id'))
|
||||
subscribeDone(testContext.client)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
ledgerAccept(this.client)
|
||||
})
|
||||
})
|
||||
|
||||
const response = await testContext.client.request(pathFind)
|
||||
|
||||
const expectedResponse: PathFindResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
alternatives: response.result.alternatives,
|
||||
destination_account: pathFind.destination_account,
|
||||
destination_amount: pathFind.destination_amount,
|
||||
source_account: pathFind.source_account,
|
||||
full_reply: false,
|
||||
id: response.id,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
|
||||
await ledgerAccept(testContext.client)
|
||||
|
||||
await pathFindPromise
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,48 +1,57 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { RipplePathFindRequest, RipplePathFindResponse } from 'xrpl-local'
|
||||
|
||||
import { RipplePathFindRequest, RipplePathFindResponse } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { generateFundedWallet } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('ripple_path_find', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const ripplePathFind: RipplePathFindRequest = {
|
||||
command: 'ripple_path_find',
|
||||
subcommand: 'create',
|
||||
source_account: this.wallet.classicAddress,
|
||||
destination_account: wallet2.classicAddress,
|
||||
destination_amount: '100',
|
||||
}
|
||||
|
||||
const response = await this.client.request(ripplePathFind)
|
||||
|
||||
const expectedResponse: RipplePathFindResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
alternatives: response.result.alternatives,
|
||||
destination_account: wallet2.classicAddress,
|
||||
destination_currencies: response.result.destination_currencies,
|
||||
destination_amount: ripplePathFind.destination_amount,
|
||||
full_reply: true,
|
||||
id: response.id,
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
source_account: ripplePathFind.source_account,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const wallet2 = await generateFundedWallet(testContext.client)
|
||||
const ripplePathFind: RipplePathFindRequest = {
|
||||
command: 'ripple_path_find',
|
||||
subcommand: 'create',
|
||||
source_account: testContext.wallet.classicAddress,
|
||||
destination_account: wallet2.classicAddress,
|
||||
destination_amount: '100',
|
||||
}
|
||||
|
||||
const response = await testContext.client.request(ripplePathFind)
|
||||
|
||||
const expectedResponse: RipplePathFindResponse = {
|
||||
id: response.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
alternatives: response.result.alternatives,
|
||||
destination_account: wallet2.classicAddress,
|
||||
destination_currencies: response.result.destination_currencies,
|
||||
destination_amount: ripplePathFind.destination_amount,
|
||||
full_reply: true,
|
||||
id: response.id,
|
||||
ledger_current_index: response.result.ledger_current_index,
|
||||
source_account: ripplePathFind.source_account,
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,132 +1,149 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { ServerInfoRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { type ServerInfoRequest, type ServerInfoResponse } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('server_info', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
describe('server_info (rippled)', function () {
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('base', async function () {
|
||||
const request: ServerInfoRequest = {
|
||||
command: 'server_info',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
info: {
|
||||
build_version: '1.7.3',
|
||||
complete_ledgers: '2563-2928',
|
||||
hostid: '44578fe64241',
|
||||
io_latency_ms: 1,
|
||||
jq_trans_overflow: '0',
|
||||
last_close: { converge_time_s: 0.1, proposers: 0 },
|
||||
load: {
|
||||
job_types: [
|
||||
{
|
||||
in_progress: 1,
|
||||
job_type: 'clientCommand',
|
||||
peak_time: 4,
|
||||
per_second: 9,
|
||||
},
|
||||
{ job_type: 'updatePaths', per_second: 1 },
|
||||
{ job_type: 'advanceLedger', per_second: 1 },
|
||||
{ job_type: 'pathFind', per_second: 1 },
|
||||
{ job_type: 'WriteNode', per_second: 17 },
|
||||
],
|
||||
threads: 1,
|
||||
},
|
||||
load_factor: 1,
|
||||
peer_disconnects: '0',
|
||||
peer_disconnects_resources: '0',
|
||||
peers: 0,
|
||||
pubkey_node: 'n9K6DaaReKkCjb9sEfXh5xP3BV9JisrJ9biKB3CSSFXancBnv5cW',
|
||||
pubkey_validator: 'none',
|
||||
server_state: 'full',
|
||||
server_state_duration_us: '8752395105',
|
||||
state_accounting: {
|
||||
connected: { duration_us: '0', transitions: 0 },
|
||||
disconnected: { duration_us: '41860', transitions: 1 },
|
||||
full: { duration_us: '20723121268', transitions: 1 },
|
||||
syncing: { duration_us: '0', transitions: 0 },
|
||||
tracking: { duration_us: '0', transitions: 0 },
|
||||
},
|
||||
time: '2021-Sep-23 22:56:55.320858 UTC',
|
||||
uptime: 8752,
|
||||
validated_ledger: {
|
||||
age: 0,
|
||||
base_fee_xrp: 0.00001,
|
||||
hash: '532175EC25CF34081D7F83584F37DAB70035A422CBE94352BEDA8EC123CB8F60',
|
||||
reserve_base_xrp: 200,
|
||||
reserve_inc_xrp: 50,
|
||||
seq: 1906,
|
||||
},
|
||||
validation_quorum: 0,
|
||||
validator_list: {
|
||||
count: 0,
|
||||
expiration: 'unknown',
|
||||
status: 'unknown',
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: ServerInfoRequest = {
|
||||
command: 'server_info',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected: ServerInfoResponse = {
|
||||
id: 0,
|
||||
result: {
|
||||
info: {
|
||||
build_version: '1.7.3',
|
||||
complete_ledgers: '2563-2928',
|
||||
hostid: '44578fe64241',
|
||||
io_latency_ms: 1,
|
||||
jq_trans_overflow: '0',
|
||||
last_close: { converge_time_s: 0.1, proposers: 0 },
|
||||
load: {
|
||||
job_types: [
|
||||
{
|
||||
in_progress: 1,
|
||||
job_type: 'clientCommand',
|
||||
peak_time: 4,
|
||||
per_second: 9,
|
||||
},
|
||||
{ job_type: 'updatePaths', per_second: 1 },
|
||||
{ job_type: 'advanceLedger', per_second: 1 },
|
||||
{ job_type: 'pathFind', per_second: 1 },
|
||||
{ job_type: 'WriteNode', per_second: 17 },
|
||||
],
|
||||
threads: 1,
|
||||
},
|
||||
load_factor: 1,
|
||||
peer_disconnects: '0',
|
||||
peer_disconnects_resources: '0',
|
||||
peers: 0,
|
||||
pubkey_node: 'n9K6DaaReKkCjb9sEfXh5xP3BV9JisrJ9biKB3CSSFXancBnv5cW',
|
||||
pubkey_validator: 'none',
|
||||
server_state: 'full',
|
||||
server_state_duration_us: '8752395105',
|
||||
state_accounting: {
|
||||
connected: { duration_us: '0', transitions: 0 },
|
||||
disconnected: { duration_us: '41860', transitions: 1 },
|
||||
full: { duration_us: '20723121268', transitions: 1 },
|
||||
syncing: { duration_us: '0', transitions: 0 },
|
||||
tracking: { duration_us: '0', transitions: 0 },
|
||||
},
|
||||
time: '2021-Sep-23 22:56:55.320858 UTC',
|
||||
uptime: 8752,
|
||||
validated_ledger: {
|
||||
age: 0,
|
||||
base_fee_xrp: 0.00001,
|
||||
hash: '532175EC25CF34081D7F83584F37DAB70035A422CBE94352BEDA8EC123CB8F60',
|
||||
reserve_base_xrp: 200,
|
||||
reserve_inc_xrp: 50,
|
||||
seq: 1906,
|
||||
},
|
||||
validation_quorum: 0,
|
||||
validator_list: {
|
||||
count: 0,
|
||||
expiration: 'unknown',
|
||||
status: 'unknown',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
|
||||
assert.equal(typeof response.result.info.time, 'string')
|
||||
assert.equal(typeof response.result.info.uptime, 'number')
|
||||
assert.equal(typeof response.result.info.complete_ledgers, 'string')
|
||||
assert.equal(typeof response.result.info.hostid, 'string')
|
||||
assert.equal(typeof response.result.info.pubkey_node, 'string')
|
||||
assert.equal(typeof response.result.info.server_state_duration_us, 'string')
|
||||
const removeKeys = [
|
||||
'time',
|
||||
'uptime',
|
||||
'complete_ledgers',
|
||||
'hostid',
|
||||
'load',
|
||||
'state_accounting',
|
||||
'pubkey_node',
|
||||
'server_state_duration_us',
|
||||
'validated_ledger',
|
||||
]
|
||||
assert.deepEqual(
|
||||
_.omit(response.result.info, removeKeys),
|
||||
_.omit(expected.result.info, removeKeys),
|
||||
)
|
||||
|
||||
// load
|
||||
assert.equal(typeof response.result.info.load.threads, 'number')
|
||||
for (const obj of response.result.info.load.job_types) {
|
||||
assert.equal(typeof obj.per_second, 'number')
|
||||
assert.equal(typeof obj.job_type, 'string')
|
||||
}
|
||||
// state_accounting
|
||||
Object.keys(response.result.info.state_accounting).forEach(function (key) {
|
||||
assert.equal(typeof response.result.info.time, 'string')
|
||||
assert.equal(typeof response.result.info.uptime, 'number')
|
||||
assert.equal(typeof response.result.info.complete_ledgers, 'string')
|
||||
assert.equal(typeof response.result.info.hostid, 'string')
|
||||
assert.equal(typeof response.result.info.pubkey_node, 'string')
|
||||
assert.equal(
|
||||
typeof response.result.info.state_accounting[key].duration_us,
|
||||
typeof response.result.info.server_state_duration_us,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.info.state_accounting[key].transitions,
|
||||
'number',
|
||||
const removeKeys = [
|
||||
'time',
|
||||
'uptime',
|
||||
'complete_ledgers',
|
||||
'hostid',
|
||||
'load',
|
||||
'state_accounting',
|
||||
'pubkey_node',
|
||||
'server_state_duration_us',
|
||||
'validated_ledger',
|
||||
]
|
||||
assert.deepEqual(
|
||||
omit(response.result.info, removeKeys),
|
||||
omit(expected.result.info, removeKeys),
|
||||
)
|
||||
})
|
||||
|
||||
// validated_ledger
|
||||
assert.equal(typeof response.result.info.validated_ledger.hash, 'string')
|
||||
for (const key of Object.keys(
|
||||
_.omit(response.result.info.validated_ledger, 'hash'),
|
||||
)) {
|
||||
assert.equal(typeof response.result.info.validated_ledger[key], 'number')
|
||||
}
|
||||
})
|
||||
// load
|
||||
assert.equal(typeof response.result.info.load?.threads, 'number')
|
||||
for (const obj of response.result.info.load?.job_types ?? []) {
|
||||
assert.equal(typeof obj.job_type, 'string')
|
||||
}
|
||||
// state_accounting
|
||||
Object.keys(response.result.info.state_accounting).forEach(function (
|
||||
key,
|
||||
) {
|
||||
assert.equal(
|
||||
typeof response.result.info.state_accounting[key].duration_us,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.info.state_accounting[key].transitions,
|
||||
'number',
|
||||
)
|
||||
})
|
||||
|
||||
// validated_ledger
|
||||
assert.equal(typeof response.result.info.validated_ledger?.hash, 'string')
|
||||
for (const key of Object.keys(
|
||||
omit(response.result.info.validated_ledger, 'hash'),
|
||||
)) {
|
||||
assert.equal(
|
||||
typeof response.result.info.validated_ledger?.[key],
|
||||
'number',
|
||||
)
|
||||
}
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,137 +1,156 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { ServerStateRequest } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import { type ServerStateRequest, type ServerStateResponse } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('server_state', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('base', async function () {
|
||||
const request: ServerStateRequest = {
|
||||
command: 'server_state',
|
||||
}
|
||||
const response = await this.client.request(request)
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
state: {
|
||||
build_version: '1.7.3',
|
||||
complete_ledgers: '2563-2932',
|
||||
io_latency_ms: 1,
|
||||
jq_trans_overflow: '0',
|
||||
last_close: {
|
||||
converge_time: 100,
|
||||
proposers: 0,
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const request: ServerStateRequest = {
|
||||
command: 'server_state',
|
||||
}
|
||||
const response = await testContext.client.request(request)
|
||||
const expected: ServerStateResponse = {
|
||||
id: 0,
|
||||
result: {
|
||||
state: {
|
||||
build_version: '1.7.3',
|
||||
complete_ledgers: '2563-2932',
|
||||
io_latency_ms: 1,
|
||||
jq_trans_overflow: '0',
|
||||
last_close: {
|
||||
converge_time: 100,
|
||||
proposers: 0,
|
||||
},
|
||||
load: {
|
||||
job_types: [
|
||||
{
|
||||
in_progress: 1,
|
||||
job_type: 'clientCommand',
|
||||
peak_time: 4,
|
||||
per_second: 9,
|
||||
},
|
||||
{ job_type: 'updatePaths', per_second: 1 },
|
||||
{ job_type: 'advanceLedger', per_second: 1 },
|
||||
{ job_type: 'pathFind', per_second: 1 },
|
||||
{ job_type: 'WriteNode', per_second: 17 },
|
||||
],
|
||||
threads: 1,
|
||||
},
|
||||
load_base: 256,
|
||||
load_factor: 256,
|
||||
load_factor_fee_escalation: 256,
|
||||
load_factor_fee_queue: 256,
|
||||
load_factor_fee_reference: 256,
|
||||
load_factor_server: 256,
|
||||
peer_disconnects: '0',
|
||||
peer_disconnects_resources: '0',
|
||||
peers: 0,
|
||||
pubkey_node: 'n9K6DaaReKkCjb9sEfXh5xP3BV9JisrJ9biKB3CSSFXancBnv5cW',
|
||||
pubkey_validator: 'none',
|
||||
server_state: 'full',
|
||||
server_state_duration_us: '8752487389',
|
||||
state_accounting: {
|
||||
connected: { duration_us: '0', transitions: 0 },
|
||||
disconnected: { duration_us: '41860', transitions: 1 },
|
||||
full: { duration_us: '20723121268', transitions: 1 },
|
||||
syncing: { duration_us: '0', transitions: 0 },
|
||||
tracking: { duration_us: '0', transitions: 0 },
|
||||
},
|
||||
time: '2021-Sep-23 22:56:55.413151 UTC',
|
||||
uptime: 8752,
|
||||
validated_ledger: {
|
||||
base_fee: 10,
|
||||
close_time: 685829741,
|
||||
hash: 'B98AABCE40A54DF654C86E56088AD7D46BBA8B8E93AD3FAC2426FEFF847F7937',
|
||||
reserve_base: 200000000,
|
||||
reserve_inc: 50000000,
|
||||
seq: 2294,
|
||||
},
|
||||
validation_quorum: 0,
|
||||
validator_list_expires: 0,
|
||||
},
|
||||
load: {
|
||||
job_types: [
|
||||
{
|
||||
in_progress: 1,
|
||||
job_type: 'clientCommand',
|
||||
peak_time: 4,
|
||||
per_second: 9,
|
||||
},
|
||||
{ job_type: 'updatePaths', per_second: 1 },
|
||||
{ job_type: 'advanceLedger', per_second: 1 },
|
||||
{ job_type: 'pathFind', per_second: 1 },
|
||||
{ job_type: 'WriteNode', per_second: 17 },
|
||||
],
|
||||
threads: 1,
|
||||
},
|
||||
load_base: 256,
|
||||
load_factor: 256,
|
||||
load_factor_fee_escalation: 256,
|
||||
load_factor_fee_queue: 256,
|
||||
load_factor_fee_reference: 256,
|
||||
load_factor_server: 256,
|
||||
peer_disconnects: '0',
|
||||
peer_disconnects_resources: '0',
|
||||
peers: 0,
|
||||
pubkey_node: 'n9K6DaaReKkCjb9sEfXh5xP3BV9JisrJ9biKB3CSSFXancBnv5cW',
|
||||
pubkey_validator: 'none',
|
||||
server_state: 'full',
|
||||
server_state_duration_us: '8752487389',
|
||||
state_accounting: {
|
||||
connected: { duration_us: '0', transitions: 0 },
|
||||
disconnected: { duration_us: '41860', transitions: 1 },
|
||||
full: { duration_us: '20723121268', transitions: 1 },
|
||||
syncing: { duration_us: '0', transitions: 0 },
|
||||
tracking: { duration_us: '0', transitions: 0 },
|
||||
},
|
||||
time: '2021-Sep-23 22:56:55.413151 UTC',
|
||||
uptime: 8752,
|
||||
validated_ledger: {
|
||||
base_fee: 10,
|
||||
close_time: 685829741,
|
||||
hash: 'B98AABCE40A54DF654C86E56088AD7D46BBA8B8E93AD3FAC2426FEFF847F7937',
|
||||
reserve_base: 200000000,
|
||||
reserve_inc: 50000000,
|
||||
seq: 2294,
|
||||
},
|
||||
validation_quorum: 0,
|
||||
validator_list_expires: 0,
|
||||
},
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
|
||||
assert.equal(typeof response.result.state.complete_ledgers, 'string')
|
||||
assert.equal(typeof response.result.state.pubkey_node, 'string')
|
||||
assert.equal(typeof response.result.state.time, 'string')
|
||||
assert.equal(typeof response.result.state.uptime, 'number')
|
||||
assert.equal(
|
||||
typeof response.result.state.server_state_duration_us,
|
||||
'string',
|
||||
)
|
||||
|
||||
const removeKeys = [
|
||||
'complete_ledgers',
|
||||
'load',
|
||||
'state_accounting',
|
||||
'pubkey_node',
|
||||
'time',
|
||||
'uptime',
|
||||
'server_state_duration_us',
|
||||
'validated_ledger',
|
||||
]
|
||||
assert.deepEqual(
|
||||
_.omit(response.result.state, removeKeys),
|
||||
_.omit(expected.result.state, removeKeys),
|
||||
)
|
||||
|
||||
// load
|
||||
assert.equal(typeof response.result.state.load.threads, 'number')
|
||||
for (const obj of response.result.state.load.job_types) {
|
||||
assert.equal(typeof obj.per_second, 'number')
|
||||
assert.equal(typeof obj.job_type, 'string')
|
||||
}
|
||||
// state_accounting
|
||||
Object.keys(response.result.state.state_accounting).forEach(function (key) {
|
||||
assert.equal(typeof response.result.state.io_latency_ms, 'number')
|
||||
assert.equal(typeof response.result.state.complete_ledgers, 'string')
|
||||
assert.equal(typeof response.result.state.pubkey_node, 'string')
|
||||
assert.equal(typeof response.result.state.time, 'string')
|
||||
assert.equal(typeof response.result.state.uptime, 'number')
|
||||
assert.equal(
|
||||
typeof response.result.state.state_accounting[key].duration_us,
|
||||
typeof response.result.state.server_state_duration_us,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.state.state_accounting[key].transitions,
|
||||
'number',
|
||||
)
|
||||
})
|
||||
|
||||
// validated_ledger
|
||||
assert.equal(typeof response.result.state.validated_ledger.hash, 'string')
|
||||
for (const key of Object.keys(
|
||||
_.omit(response.result.state.validated_ledger, 'hash'),
|
||||
)) {
|
||||
assert.equal(typeof response.result.state.validated_ledger[key], 'number')
|
||||
}
|
||||
})
|
||||
const removeKeys = [
|
||||
'complete_ledgers',
|
||||
'load',
|
||||
'state_accounting',
|
||||
'pubkey_node',
|
||||
'time',
|
||||
'uptime',
|
||||
'server_state_duration_us',
|
||||
'validated_ledger',
|
||||
'io_latency_ms',
|
||||
]
|
||||
assert.deepEqual(
|
||||
omit(response.result.state, removeKeys),
|
||||
omit(expected.result.state, removeKeys),
|
||||
)
|
||||
|
||||
// load
|
||||
assert.equal(typeof response.result.state.load?.threads, 'number')
|
||||
for (const obj of response.result.state.load?.job_types ?? []) {
|
||||
assert.equal(typeof obj.job_type, 'string')
|
||||
}
|
||||
// state_accounting
|
||||
Object.keys(response.result.state.state_accounting).forEach(function (
|
||||
key,
|
||||
) {
|
||||
assert.equal(
|
||||
typeof response.result.state.state_accounting[key].duration_us,
|
||||
'string',
|
||||
)
|
||||
assert.equal(
|
||||
typeof response.result.state.state_accounting[key].transitions,
|
||||
'number',
|
||||
)
|
||||
})
|
||||
|
||||
// validated_ledger
|
||||
assert.equal(
|
||||
typeof response.result.state.validated_ledger?.hash,
|
||||
'string',
|
||||
)
|
||||
for (const key of Object.keys(
|
||||
omit(response.result.state.validated_ledger, 'hash'),
|
||||
)) {
|
||||
assert.equal(
|
||||
typeof response.result.state.validated_ledger?.[key],
|
||||
'number',
|
||||
)
|
||||
}
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { decode } from 'ripple-binary-codec/dist'
|
||||
import { decode } from 'ripple-binary-codec'
|
||||
|
||||
import {
|
||||
AccountSet,
|
||||
SubmitRequest,
|
||||
SubmitResponse,
|
||||
hashes,
|
||||
Transaction,
|
||||
} from 'xrpl-local'
|
||||
import { convertStringToHex } from 'xrpl-local/utils'
|
||||
|
||||
} from '../../../src'
|
||||
import { convertStringToHex } from '../../../src/utils'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { ledgerAccept, verifySubmittedTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
@@ -19,59 +22,65 @@ const TIMEOUT = 20000
|
||||
const { hashSignedTx } = hashes
|
||||
|
||||
describe('submit', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('submit', async function () {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
const autofilledTx = await this.client.autofill(accountSet)
|
||||
const signedTx = this.wallet.sign(autofilledTx)
|
||||
const submitRequest: SubmitRequest = {
|
||||
command: 'submit',
|
||||
tx_blob: signedTx.tx_blob,
|
||||
}
|
||||
const submitResponse = await this.client.request(submitRequest)
|
||||
|
||||
await ledgerAccept(this.client)
|
||||
await verifySubmittedTransaction(
|
||||
this.client,
|
||||
signedTx.tx_blob,
|
||||
signedTx.hash,
|
||||
)
|
||||
|
||||
const expectedResponse: SubmitResponse = {
|
||||
id: submitResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
engine_result: 'tesSUCCESS',
|
||||
engine_result_code: 0,
|
||||
engine_result_message:
|
||||
'The transaction was applied. Only final in a validated ledger.',
|
||||
tx_blob: signedTx.tx_blob,
|
||||
tx_json: {
|
||||
...(decode(signedTx.tx_blob) as unknown as Transaction),
|
||||
hash: hashSignedTx(signedTx.tx_blob),
|
||||
},
|
||||
accepted: true,
|
||||
account_sequence_available:
|
||||
submitResponse.result.account_sequence_available,
|
||||
account_sequence_next: submitResponse.result.account_sequence_next,
|
||||
applied: true,
|
||||
broadcast: submitResponse.result.broadcast,
|
||||
kept: true,
|
||||
queued: false,
|
||||
open_ledger_cost: submitResponse.result.open_ledger_cost,
|
||||
validated_ledger_index: submitResponse.result.validated_ledger_index,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(submitResponse, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'submit',
|
||||
async () => {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
const autofilledTx = await testContext.client.autofill(accountSet)
|
||||
const signedTx = testContext.wallet.sign(autofilledTx)
|
||||
const submitRequest: SubmitRequest = {
|
||||
command: 'submit',
|
||||
tx_blob: signedTx.tx_blob,
|
||||
}
|
||||
const submitResponse = await testContext.client.request(submitRequest)
|
||||
|
||||
await ledgerAccept(testContext.client)
|
||||
await verifySubmittedTransaction(
|
||||
testContext.client,
|
||||
signedTx.tx_blob,
|
||||
signedTx.hash,
|
||||
)
|
||||
|
||||
const expectedResponse: SubmitResponse = {
|
||||
id: submitResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
engine_result: 'tesSUCCESS',
|
||||
engine_result_code: 0,
|
||||
engine_result_message:
|
||||
'The transaction was applied. Only final in a validated ledger.',
|
||||
tx_blob: signedTx.tx_blob,
|
||||
tx_json: {
|
||||
...(decode(signedTx.tx_blob) as unknown as Transaction),
|
||||
hash: hashSignedTx(signedTx.tx_blob),
|
||||
},
|
||||
accepted: true,
|
||||
account_sequence_available:
|
||||
submitResponse.result.account_sequence_available,
|
||||
account_sequence_next: submitResponse.result.account_sequence_next,
|
||||
applied: true,
|
||||
broadcast: submitResponse.result.broadcast,
|
||||
kept: true,
|
||||
queued: false,
|
||||
open_ledger_cost: submitResponse.result.open_ledger_cost,
|
||||
validated_ledger_index: submitResponse.result.validated_ledger_index,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(submitResponse, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { decode } from 'ripple-binary-codec/dist'
|
||||
import { decode } from 'ripple-binary-codec'
|
||||
|
||||
import {
|
||||
AccountSet,
|
||||
Client,
|
||||
@@ -9,12 +9,15 @@ import {
|
||||
Transaction,
|
||||
SubmitMultisignedResponse,
|
||||
hashes,
|
||||
} from 'xrpl-local'
|
||||
import { convertStringToHex } from 'xrpl-local/utils'
|
||||
import { multisign } from 'xrpl-local/Wallet/signer'
|
||||
|
||||
} from '../../../src'
|
||||
import { convertStringToHex } from '../../../src/utils'
|
||||
import { multisign } from '../../../src/Wallet/signer'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import {
|
||||
generateFundedWallet,
|
||||
ledgerAccept,
|
||||
@@ -27,73 +30,83 @@ const TIMEOUT = 20000
|
||||
const { hashSignedTx } = hashes
|
||||
|
||||
describe('submit_multisigned', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('submit_multisigned transaction', async function () {
|
||||
const client: Client = this.client
|
||||
const signerWallet1 = await generateFundedWallet(this.client)
|
||||
const signerWallet2 = await generateFundedWallet(this.client)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet1.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(this.client, signerListSet, this.wallet)
|
||||
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const signed1 = signerWallet1.sign(accountSetTx, true)
|
||||
const signed2 = signerWallet2.sign(accountSetTx, true)
|
||||
const multisigned = multisign([signed1.tx_blob, signed2.tx_blob])
|
||||
const multisignedRequest: SubmitMultisignedRequest = {
|
||||
command: 'submit_multisigned',
|
||||
tx_json: decode(multisigned) as unknown as Transaction,
|
||||
}
|
||||
const submitResponse = await client.request(multisignedRequest)
|
||||
await ledgerAccept(client)
|
||||
assert.strictEqual(submitResponse.result.engine_result, 'tesSUCCESS')
|
||||
await verifySubmittedTransaction(this.client, multisigned)
|
||||
|
||||
const expectedResponse: SubmitMultisignedResponse = {
|
||||
id: submitResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
engine_result: 'tesSUCCESS',
|
||||
engine_result_code: 0,
|
||||
engine_result_message:
|
||||
'The transaction was applied. Only final in a validated ledger.',
|
||||
tx_blob: multisigned,
|
||||
tx_json: {
|
||||
...(decode(multisigned) as unknown as Transaction),
|
||||
hash: hashSignedTx(multisigned),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(submitResponse, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'submit_multisigned transaction',
|
||||
async () => {
|
||||
const client: Client = testContext.client
|
||||
const signerWallet1 = await generateFundedWallet(testContext.client)
|
||||
const signerWallet2 = await generateFundedWallet(testContext.client)
|
||||
|
||||
// set up the multisigners for the account
|
||||
const signerListSet: SignerListSet = {
|
||||
TransactionType: 'SignerListSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
SignerEntries: [
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet1.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
SignerEntry: {
|
||||
Account: signerWallet2.classicAddress,
|
||||
SignerWeight: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
SignerQuorum: 2,
|
||||
}
|
||||
await testTransaction(
|
||||
testContext.client,
|
||||
signerListSet,
|
||||
testContext.wallet,
|
||||
)
|
||||
|
||||
// try to multisign
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const accountSetTx = await client.autofill(accountSet, 2)
|
||||
const signed1 = signerWallet1.sign(accountSetTx, true)
|
||||
const signed2 = signerWallet2.sign(accountSetTx, true)
|
||||
const multisigned = multisign([signed1.tx_blob, signed2.tx_blob])
|
||||
const multisignedRequest: SubmitMultisignedRequest = {
|
||||
command: 'submit_multisigned',
|
||||
tx_json: decode(multisigned) as unknown as Transaction,
|
||||
}
|
||||
const submitResponse = await client.request(multisignedRequest)
|
||||
await ledgerAccept(client)
|
||||
assert.strictEqual(submitResponse.result.engine_result, 'tesSUCCESS')
|
||||
await verifySubmittedTransaction(testContext.client, multisigned)
|
||||
|
||||
const expectedResponse: SubmitMultisignedResponse = {
|
||||
id: submitResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
engine_result: 'tesSUCCESS',
|
||||
engine_result_code: 0,
|
||||
engine_result_message:
|
||||
'The transaction was applied. Only final in a validated ledger.',
|
||||
tx_blob: multisigned,
|
||||
tx_json: {
|
||||
...(decode(multisigned) as unknown as Transaction),
|
||||
hash: hashSignedTx(multisigned),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(submitResponse, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import {
|
||||
Client,
|
||||
OfferCreate,
|
||||
SubscribeRequest,
|
||||
Wallet,
|
||||
SubscribeResponse,
|
||||
} from 'xrpl-local'
|
||||
import { StreamType } from 'xrpl-local/models/common'
|
||||
|
||||
} from '../../../src'
|
||||
import { StreamType } from '../../../src/models/common'
|
||||
import type { LedgerStreamResponse } from '../../../src/models/methods/subscribe'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { ledgerAccept, subscribeDone, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
// Note: This test use '.then' to avoid awaits in order to use 'done' style tests.
|
||||
// eslint-disable-next-line max-params -- Helps keep things well-typed
|
||||
async function createTxHandlerTest(
|
||||
client: Client,
|
||||
wallet: Wallet,
|
||||
done: Mocha.Done,
|
||||
subscriptionStream: StreamType,
|
||||
): Promise<void> {
|
||||
const txStream = 'transaction'
|
||||
|
||||
client.on(txStream, (tx) => {
|
||||
assert.equal(tx.type, txStream)
|
||||
subscribeDone(client, done)
|
||||
const transactionPromise = new Promise<void>((resolve) => {
|
||||
client.on(txStream, (tx) => {
|
||||
assert.equal(tx.type, txStream)
|
||||
subscribeDone(client)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
|
||||
const request: SubscribeRequest = {
|
||||
@@ -37,17 +41,21 @@ async function createTxHandlerTest(
|
||||
accounts: [wallet.classicAddress],
|
||||
}
|
||||
|
||||
client.request(request).then((response) => {
|
||||
assert.equal(response.type, 'response')
|
||||
assert.deepEqual(response.result, {})
|
||||
})
|
||||
const response = await client.request(request)
|
||||
|
||||
assert.equal(response.type, 'response')
|
||||
assert.deepEqual(response.result, {})
|
||||
|
||||
return transactionPromise
|
||||
}
|
||||
|
||||
describe('subscribe', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
/**
|
||||
* Subscribe streams which are not testable with just a standalone node:
|
||||
@@ -60,17 +68,21 @@ describe('subscribe', function () {
|
||||
* 'server'.
|
||||
*/
|
||||
|
||||
it('Successfully Subscribes', async function () {
|
||||
const response: SubscribeResponse = await this.client.request({
|
||||
command: 'subscribe',
|
||||
})
|
||||
it(
|
||||
'Successfully Subscribes',
|
||||
async () => {
|
||||
const response: SubscribeResponse = await testContext.client.request({
|
||||
command: 'subscribe',
|
||||
})
|
||||
|
||||
assert.deepEqual(response.result, {})
|
||||
assert.equal(response.type, 'response')
|
||||
})
|
||||
assert.deepEqual(response.result, {})
|
||||
assert.equal(response.type, 'response')
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it('Successfully Unsubscribes', async function () {
|
||||
const response = await this.client.request({
|
||||
const response = await testContext.client.request({
|
||||
command: 'unsubscribe',
|
||||
})
|
||||
|
||||
@@ -78,90 +90,111 @@ describe('subscribe', function () {
|
||||
assert.equal(response.type, 'response')
|
||||
})
|
||||
|
||||
it('Emits transaction', function (done) {
|
||||
const streamType = 'transactions'
|
||||
createTxHandlerTest(this.client, this.wallet, done, streamType).then(() => {
|
||||
it(
|
||||
'Emits transaction',
|
||||
async () => {
|
||||
const streamType = 'transactions'
|
||||
const transactionPromise = createTxHandlerTest(
|
||||
testContext.client,
|
||||
testContext.wallet,
|
||||
streamType,
|
||||
)
|
||||
// Trigger the event
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: this.wallet.classicAddress,
|
||||
Account: testContext.wallet.classicAddress,
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: this.wallet.classicAddress,
|
||||
issuer: testContext.wallet.classicAddress,
|
||||
value: '10',
|
||||
},
|
||||
}
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
await transactionPromise
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
testTransaction(this.client, tx, this.wallet)
|
||||
})
|
||||
})
|
||||
it(
|
||||
'Emits transaction on transactions_proposed',
|
||||
async () => {
|
||||
const transactionPromise = createTxHandlerTest(
|
||||
testContext.client,
|
||||
testContext.wallet,
|
||||
'transactions_proposed',
|
||||
)
|
||||
|
||||
it('Emits transaction on transactions_proposed', function (done) {
|
||||
createTxHandlerTest(
|
||||
this.client,
|
||||
this.wallet,
|
||||
done,
|
||||
'transactions_proposed',
|
||||
).then(() => {
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: this.wallet.classicAddress,
|
||||
Account: testContext.wallet.classicAddress,
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: this.wallet.classicAddress,
|
||||
issuer: testContext.wallet.classicAddress,
|
||||
value: '10',
|
||||
},
|
||||
}
|
||||
|
||||
// The transactions_proposed stream should trigger the transaction handler WITHOUT ledgerAccept
|
||||
const client: Client = this.client
|
||||
client.submit(tx, { wallet: this.wallet })
|
||||
})
|
||||
})
|
||||
await testContext.client.submit(tx, { wallet: testContext.wallet })
|
||||
await transactionPromise
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
// Note: This test use '.then' to avoid awaits in order to use 'done' style tests.
|
||||
it('Emits ledger', function (done) {
|
||||
const request: SubscribeRequest = {
|
||||
command: 'subscribe',
|
||||
streams: ['ledger'],
|
||||
accounts: [this.wallet.classicAddress],
|
||||
}
|
||||
|
||||
this.client.request(request).then((response) => {
|
||||
// Explicitly checking that there are only known fields in the return
|
||||
const expectedResult = {
|
||||
fee_base: response.result.fee_base,
|
||||
fee_ref: response.result.fee_ref,
|
||||
ledger_hash: response.result.ledger_hash,
|
||||
ledger_index: response.result.ledger_index,
|
||||
ledger_time: response.result.ledger_time,
|
||||
reserve_base: response.result.reserve_base,
|
||||
reserve_inc: response.result.reserve_inc,
|
||||
validated_ledgers: response.result.validated_ledgers,
|
||||
it(
|
||||
'Emits ledger',
|
||||
async () => {
|
||||
const request: SubscribeRequest = {
|
||||
command: 'subscribe',
|
||||
streams: ['ledger'],
|
||||
accounts: [testContext.wallet.classicAddress],
|
||||
}
|
||||
|
||||
assert.equal(response.type, 'response')
|
||||
assert.deepEqual(response.result, expectedResult)
|
||||
await testContext.client.request(request).then(async (response) => {
|
||||
const ledgerResponse: LedgerStreamResponse =
|
||||
response.result as LedgerStreamResponse
|
||||
// Explicitly checking that there are only known fields in the return
|
||||
const expectedResult = {
|
||||
fee_base: ledgerResponse.fee_base,
|
||||
fee_ref: ledgerResponse.fee_ref,
|
||||
ledger_hash: ledgerResponse.ledger_hash,
|
||||
ledger_index: ledgerResponse.ledger_index,
|
||||
ledger_time: ledgerResponse.ledger_time,
|
||||
reserve_base: ledgerResponse.reserve_base,
|
||||
reserve_inc: ledgerResponse.reserve_inc,
|
||||
validated_ledgers: ledgerResponse.validated_ledgers,
|
||||
}
|
||||
|
||||
const client: Client = this.client
|
||||
client.on('ledgerClosed', (ledger) => {
|
||||
// Fields that are expected to change between the initial test and now are updated
|
||||
assert.deepEqual(ledger, {
|
||||
...expectedResult,
|
||||
type: 'ledgerClosed',
|
||||
txn_count: ledger.txn_count,
|
||||
ledger_hash: ledger.ledger_hash,
|
||||
ledger_index: parseInt(expectedResult.ledger_index, 10) + 1,
|
||||
ledger_time: ledger.ledger_time,
|
||||
validated_ledgers: ledger.validated_ledgers,
|
||||
assert.equal(response.type, 'response')
|
||||
assert.deepEqual(response.result, expectedResult)
|
||||
|
||||
const client: Client = testContext.client
|
||||
const ledgerClosedPromise = new Promise<void>((resolve) => {
|
||||
client.on('ledgerClosed', (ledger) => {
|
||||
// Fields that are expected to change between the initial test and now are updated
|
||||
assert.deepEqual(ledger, {
|
||||
...expectedResult,
|
||||
type: 'ledgerClosed',
|
||||
txn_count: ledger.txn_count,
|
||||
ledger_hash: ledger.ledger_hash,
|
||||
ledger_index:
|
||||
parseInt(expectedResult.ledger_index.toString(), 10) + 1,
|
||||
ledger_time: ledger.ledger_time,
|
||||
validated_ledgers: ledger.validated_ledgers,
|
||||
})
|
||||
subscribeDone(testContext.client)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
subscribeDone(this.client, done)
|
||||
})
|
||||
|
||||
// Trigger the event
|
||||
ledgerAccept(this.client)
|
||||
})
|
||||
})
|
||||
// Trigger the event
|
||||
await ledgerAccept(testContext.client)
|
||||
|
||||
await ledgerClosedPromise
|
||||
})
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,55 +1,67 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountSet, hashes, SubmitResponse, TxResponse } from 'xrpl-local'
|
||||
import { convertStringToHex } from 'xrpl-local/utils'
|
||||
|
||||
import { AccountSet, hashes, SubmitResponse, TxResponse } from '../../../src'
|
||||
import { convertStringToHex } from '../../../src/utils'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
const { hashSignedTx } = hashes
|
||||
|
||||
describe('tx', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const account = this.wallet.classicAddress
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: account,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
const response: SubmitResponse = await this.client.submit(accountSet, {
|
||||
wallet: this.wallet,
|
||||
})
|
||||
|
||||
const hash = hashSignedTx(response.result.tx_blob)
|
||||
const txResponse = await this.client.request({
|
||||
command: 'tx',
|
||||
transaction: hash,
|
||||
})
|
||||
|
||||
const expectedResponse: TxResponse = {
|
||||
id: txResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
...accountSet,
|
||||
Fee: txResponse.result.Fee,
|
||||
Flags: 0,
|
||||
LastLedgerSequence: txResponse.result.LastLedgerSequence,
|
||||
Sequence: txResponse.result.Sequence,
|
||||
SigningPubKey: this.wallet.publicKey,
|
||||
TxnSignature: txResponse.result.TxnSignature,
|
||||
hash: hashSignedTx(response.result.tx_blob),
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(txResponse, expectedResponse)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const account = testContext.wallet.classicAddress
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: account,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
const response: SubmitResponse = await testContext.client.submit(
|
||||
accountSet,
|
||||
{
|
||||
wallet: testContext.wallet,
|
||||
},
|
||||
)
|
||||
|
||||
const hash = hashSignedTx(response.result.tx_blob)
|
||||
const txResponse = await testContext.client.request({
|
||||
command: 'tx',
|
||||
transaction: hash,
|
||||
})
|
||||
|
||||
const expectedResponse: TxResponse = {
|
||||
id: txResponse.id,
|
||||
type: 'response',
|
||||
result: {
|
||||
...accountSet,
|
||||
Fee: txResponse.result.Fee,
|
||||
Flags: 0,
|
||||
LastLedgerSequence: txResponse.result.LastLedgerSequence,
|
||||
Sequence: txResponse.result.Sequence,
|
||||
SigningPubKey: testContext.wallet.publicKey,
|
||||
TxnSignature: txResponse.result.TxnSignature,
|
||||
hash: hashSignedTx(response.result.tx_blob),
|
||||
validated: false,
|
||||
},
|
||||
}
|
||||
|
||||
assert.deepEqual(txResponse, expectedResponse)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,42 +1,55 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { Client } from 'xrpl-local'
|
||||
import omit from 'lodash/omit'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('Utility method integration tests', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('ping', async function () {
|
||||
const response = await (this.client as Client).request({
|
||||
command: 'ping',
|
||||
})
|
||||
const expected: unknown = {
|
||||
result: { role: 'admin', unlimited: true },
|
||||
type: 'response',
|
||||
}
|
||||
assert.deepEqual(_.omit(response, 'id'), expected)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('random', async function () {
|
||||
const response = await (this.client as Client).request({
|
||||
command: 'random',
|
||||
})
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
random: '[random string of 64 bytes]',
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(response.result.random.length, 64)
|
||||
})
|
||||
it(
|
||||
'ping',
|
||||
async () => {
|
||||
const response = await testContext.client.request({
|
||||
command: 'ping',
|
||||
})
|
||||
const expected: unknown = {
|
||||
result: { role: 'admin', unlimited: true },
|
||||
type: 'response',
|
||||
}
|
||||
assert.deepEqual(omit(response, 'id'), expected)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'random',
|
||||
async () => {
|
||||
const response = await testContext.client.request({
|
||||
command: 'random',
|
||||
})
|
||||
const expected = {
|
||||
id: 0,
|
||||
result: {
|
||||
random: '[random string of 64 bytes]',
|
||||
},
|
||||
type: 'response',
|
||||
}
|
||||
assert.equal(response.type, expected.type)
|
||||
assert.equal(response.result.random.length, 64)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,26 +1,46 @@
|
||||
import { Client, Wallet } from 'xrpl-local'
|
||||
import { Client, Wallet } from '../../src'
|
||||
|
||||
import serverUrl from './serverUrl'
|
||||
import { fundAccount } from './utils'
|
||||
|
||||
export async function teardownClient(this: Mocha.Context): Promise<void> {
|
||||
this.client.removeAllListeners()
|
||||
this.client.disconnect()
|
||||
export interface XrplIntegrationTestContext {
|
||||
client: Client
|
||||
wallet: Wallet
|
||||
}
|
||||
|
||||
export async function teardownClient(
|
||||
context: XrplIntegrationTestContext,
|
||||
): Promise<void> {
|
||||
context.client.removeAllListeners()
|
||||
return context.client.disconnect()
|
||||
}
|
||||
|
||||
async function connectWithRetry(client: Client, tries = 0): Promise<void> {
|
||||
return client.connect().catch(async (error) => {
|
||||
if (tries < 10) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(connectWithRetry(client, tries + 1))
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
throw error
|
||||
})
|
||||
}
|
||||
|
||||
export async function setupClient(
|
||||
this: Mocha.Context,
|
||||
server = serverUrl,
|
||||
): Promise<void> {
|
||||
this.wallet = Wallet.generate()
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
this.client = new Client(server)
|
||||
this.client
|
||||
.connect()
|
||||
.then(async () => {
|
||||
await fundAccount(this.client, this.wallet)
|
||||
resolve()
|
||||
})
|
||||
.catch(reject)
|
||||
): Promise<XrplIntegrationTestContext> {
|
||||
const context: XrplIntegrationTestContext = {
|
||||
client: new Client(server, { timeout: 200000 }),
|
||||
wallet: Wallet.generate(),
|
||||
}
|
||||
return connectWithRetry(context.client).then(async () => {
|
||||
await fundAccount(context.client, context.wallet, {
|
||||
count: 20,
|
||||
delayMs: 1000,
|
||||
})
|
||||
return context
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,91 +1,149 @@
|
||||
/* eslint-disable @typescript-eslint/no-misused-promises -- supposed to return a promise here */
|
||||
/* eslint-disable no-restricted-syntax -- not sure why this rule is here, definitely not needed here */
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { AccountSet, convertStringToHex, ValidationError } from 'xrpl-local'
|
||||
|
||||
import { AccountSet, convertStringToHex, ValidationError } from '../../src'
|
||||
import { assertRejects } from '../testUtils'
|
||||
|
||||
import serverUrl from './serverUrl'
|
||||
import { setupClient, teardownClient } from './setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from './setup'
|
||||
import { ledgerAccept } from './utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 60000
|
||||
|
||||
describe('client.submitAndWait', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it('submitAndWait an unsigned transaction', async function () {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const responsePromise = this.client.submitAndWait(accountSet, {
|
||||
wallet: this.wallet,
|
||||
async function delayedLedgerAccept(): Promise<unknown> {
|
||||
await new Promise<void>((resolve) => {
|
||||
setTimeout(resolve, 1000)
|
||||
})
|
||||
const ledgerPromise = setTimeout(ledgerAccept, 1000, this.client)
|
||||
return Promise.all([responsePromise, ledgerPromise]).then(
|
||||
([response, _ledger]) => {
|
||||
assert.equal(response.type, 'response')
|
||||
assert.equal(response.result.validated, true)
|
||||
},
|
||||
)
|
||||
})
|
||||
return ledgerAccept(testContext.client)
|
||||
}
|
||||
|
||||
it('should throw a ValidationError when submitting an unsigned transaction without a wallet', async function () {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
it(
|
||||
'submitAndWait an unsigned transaction',
|
||||
async () => {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
await assertRejects(
|
||||
this.client.submitAndWait(accountSet),
|
||||
ValidationError,
|
||||
'Wallet must be provided when submitting an unsigned transaction',
|
||||
)
|
||||
})
|
||||
let retries = 10
|
||||
|
||||
it('submitAndWait a signed transaction', async function () {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const { tx_blob: signedAccountSet } = this.wallet.sign(
|
||||
await this.client.autofill(accountSet),
|
||||
)
|
||||
const responsePromise = this.client.submitAndWait(signedAccountSet)
|
||||
const ledgerPromise = setTimeout(ledgerAccept, 1000, this.client)
|
||||
return Promise.all([responsePromise, ledgerPromise]).then(
|
||||
([response, _ledger]) => {
|
||||
assert.equal(response.type, 'response')
|
||||
assert.equal(response.result.validated, true)
|
||||
},
|
||||
)
|
||||
})
|
||||
while (retries > 0) {
|
||||
retries -= 1
|
||||
const responsePromise = testContext.client.submitAndWait(accountSet, {
|
||||
wallet: testContext.wallet,
|
||||
})
|
||||
const ledgerPromise = delayedLedgerAccept()
|
||||
|
||||
it('submitAndWait a signed transaction longer', async function () {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const { tx_blob: signedAccountSet } = this.wallet.sign(
|
||||
await this.client.autofill(accountSet),
|
||||
)
|
||||
const responsePromise = this.client.submitAndWait(signedAccountSet)
|
||||
const ledgerPromise = setTimeout(ledgerAccept, 5000, this.client)
|
||||
return Promise.all([responsePromise, ledgerPromise]).then(
|
||||
([response, _ledger]) => {
|
||||
assert.equal(response.type, 'response')
|
||||
assert.equal(response.result.validated, true)
|
||||
},
|
||||
)
|
||||
})
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop -- Testing purposes
|
||||
const [response, _ledger] = await Promise.all([
|
||||
responsePromise,
|
||||
ledgerPromise,
|
||||
])
|
||||
|
||||
assert.equal(response.type, 'response')
|
||||
assert.equal(response.result.validated, true)
|
||||
retries = 0
|
||||
break
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line max-depth -- Necessary
|
||||
if (!(err instanceof Error)) {
|
||||
throw err
|
||||
}
|
||||
const errorCodeRegex = /(?:Preliminary result:\s)(?<errorCode>.*)$/gu
|
||||
const message = err.message
|
||||
const matches = errorCodeRegex.exec(message)
|
||||
const errorCode = matches?.groups?.errorCode
|
||||
|
||||
// Retry if another transaction finished before this one
|
||||
// eslint-disable-next-line max-depth -- Testing
|
||||
if (['tefPAST_SEQ', 'tefMAX_LEDGER'].includes(errorCode || '')) {
|
||||
// eslint-disable-next-line no-await-in-loop, no-promise-executor-return -- We are waiting on retries
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
} else {
|
||||
retries = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'should throw a ValidationError when submitting an unsigned transaction without a wallet',
|
||||
async () => {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
|
||||
await assertRejects(
|
||||
testContext.client.submitAndWait(accountSet),
|
||||
ValidationError,
|
||||
'Wallet must be provided when submitting an unsigned transaction',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'submitAndWait a signed transaction',
|
||||
async () => {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const { tx_blob: signedAccountSet } = testContext.wallet.sign(
|
||||
await testContext.client.autofill(accountSet),
|
||||
)
|
||||
const responsePromise = testContext.client.submitAndWait(signedAccountSet)
|
||||
const ledgerPromise = delayedLedgerAccept()
|
||||
return Promise.all([responsePromise, ledgerPromise]).then(
|
||||
([response, _ledger]) => {
|
||||
assert.equal(response.type, 'response')
|
||||
assert.equal(response.result.validated, true)
|
||||
},
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
|
||||
it(
|
||||
'submitAndWait a signed transaction longer',
|
||||
async () => {
|
||||
const accountSet: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Domain: convertStringToHex('example.com'),
|
||||
}
|
||||
const { tx_blob: signedAccountSet } = testContext.wallet.sign(
|
||||
await testContext.client.autofill(accountSet),
|
||||
)
|
||||
const responsePromise = testContext.client.submitAndWait(signedAccountSet)
|
||||
const ledgerPromise = delayedLedgerAccept()
|
||||
return Promise.all([responsePromise, ledgerPromise]).then(
|
||||
([response, _ledger]) => {
|
||||
assert.equal(response.type, 'response')
|
||||
assert.equal(response.result.validated, true)
|
||||
},
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,33 +1,64 @@
|
||||
import _ from 'lodash'
|
||||
import { AccountDelete } from 'xrpl-local/models/transactions'
|
||||
|
||||
import { AccountDelete } from '../../../src/models/transactions'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, ledgerAccept, testTransaction } from '../utils'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { generateFundedWallet, submitTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('AccountDelete', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
// to the satisfy the condition that account sequence and current ledger_index should be 256 apart.
|
||||
const promises: Array<Promise<void>> = []
|
||||
for (let iter = 0; iter < 256; iter += 1) {
|
||||
promises.push(ledgerAccept(this.client))
|
||||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
const tx: AccountDelete = {
|
||||
TransactionType: 'AccountDelete',
|
||||
Account: this.wallet.classicAddress,
|
||||
Destination: wallet2.classicAddress,
|
||||
}
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const wallet2 = await generateFundedWallet(testContext.client)
|
||||
// to the satisfy the condition that account sequence and current ledger_index should be 256 apart.
|
||||
// const promises: Array<Promise<void> | Promise<unknown>> = []
|
||||
// for (let iter = 0; iter < 256; iter += 1) {
|
||||
// promises.push(ledgerAccept(testContext.client))
|
||||
// }
|
||||
// await Promise.all(promises)
|
||||
const tx: AccountDelete = {
|
||||
TransactionType: 'AccountDelete',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Destination: wallet2.classicAddress,
|
||||
}
|
||||
|
||||
// Since we are not testing the functionaity of rippled in this library, only that we are submitting commands
|
||||
// properly, we can just test that the AccountDelete command was successfully received.
|
||||
await submitTransaction({
|
||||
client: testContext.client,
|
||||
transaction: tx,
|
||||
wallet: testContext.wallet,
|
||||
})
|
||||
|
||||
// TODO: Re-enable this test once we can test the `engine_result` without waiting a significant amount of time.
|
||||
// Note, we can't test the `engine_result` without waiting a significant
|
||||
// amount of time because accounts can't be deleted until some number of
|
||||
// ledgers have closed since its creation.
|
||||
//
|
||||
// The documentation for `tecTOO_SOON` reads:
|
||||
// "The AccountDelete transaction failed because the account to be deleted had a
|
||||
// Sequence number that is too high. The current ledger index must be at least
|
||||
// 256 higher than the account's sequence number."
|
||||
//
|
||||
// self.assertEqual(response.result['engine_result'], 'tesSUCCESS')
|
||||
// await testTransaction(testContext.client, tx, testContext.wallet, {
|
||||
// // Need to retry when running tests concurrently
|
||||
// count: 5,
|
||||
// delayMs: 1000,
|
||||
// })
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
import _ from 'lodash'
|
||||
import { AccountSet } from 'xrpl-local/models/transactions'
|
||||
|
||||
import { AccountSet } from '../../../src/models/transactions'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('AccountSet', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const tx: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: this.wallet.classicAddress,
|
||||
}
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const tx: AccountSet = {
|
||||
TransactionType: 'AccountSet',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
}
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,63 +1,72 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { CheckCreate, CheckCancel } from 'xrpl-local'
|
||||
|
||||
import { CheckCreate, CheckCancel } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('CheckCancel', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const setupTx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: this.wallet.classicAddress,
|
||||
Destination: wallet2.classicAddress,
|
||||
SendMax: '50',
|
||||
}
|
||||
|
||||
await testTransaction(this.client, setupTx, this.wallet)
|
||||
|
||||
// get check ID
|
||||
const response1 = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
response1.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
const checkId = response1.result.account_objects[0].index
|
||||
|
||||
// actual test - cancel the check
|
||||
const tx: CheckCancel = {
|
||||
TransactionType: 'CheckCancel',
|
||||
Account: this.wallet.classicAddress,
|
||||
CheckID: checkId,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
|
||||
// confirm that the check no longer exists
|
||||
const accountOffersResponse = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
0,
|
||||
'Should be no checks on the ledger',
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const wallet2 = await generateFundedWallet(testContext.client)
|
||||
const setupTx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Destination: wallet2.classicAddress,
|
||||
SendMax: '50',
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, setupTx, testContext.wallet)
|
||||
|
||||
// get check ID
|
||||
const response1 = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
response1.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
const checkId = response1.result.account_objects[0].index
|
||||
|
||||
// actual test - cancel the check
|
||||
const tx: CheckCancel = {
|
||||
TransactionType: 'CheckCancel',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
CheckID: checkId,
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
|
||||
// confirm that the check no longer exists
|
||||
const accountOffersResponse = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
0,
|
||||
'Should be no checks on the ledger',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,66 +1,75 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { CheckCreate, CheckCash } from 'xrpl-local'
|
||||
|
||||
import { CheckCreate, CheckCash } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('CheckCash', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const amount = '500'
|
||||
|
||||
const setupTx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: this.wallet.classicAddress,
|
||||
Destination: wallet2.classicAddress,
|
||||
SendMax: amount,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, setupTx, this.wallet)
|
||||
|
||||
// get check ID
|
||||
const response1 = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
response1.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
const checkId = response1.result.account_objects[0].index
|
||||
|
||||
// actual test - cash the check
|
||||
const tx: CheckCash = {
|
||||
TransactionType: 'CheckCash',
|
||||
Account: wallet2.classicAddress,
|
||||
CheckID: checkId,
|
||||
Amount: amount,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, tx, wallet2)
|
||||
|
||||
// confirm that the check no longer exists
|
||||
const accountOffersResponse = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
0,
|
||||
'Should be no checks on the ledger',
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const wallet2 = await generateFundedWallet(testContext.client)
|
||||
const amount = '500'
|
||||
|
||||
const setupTx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Destination: wallet2.classicAddress,
|
||||
SendMax: amount,
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, setupTx, testContext.wallet)
|
||||
|
||||
// get check ID
|
||||
const response1 = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
response1.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
const checkId = response1.result.account_objects[0].index
|
||||
|
||||
// actual test - cash the check
|
||||
const tx: CheckCash = {
|
||||
TransactionType: 'CheckCash',
|
||||
Account: wallet2.classicAddress,
|
||||
CheckID: checkId,
|
||||
Amount: amount,
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, tx, wallet2)
|
||||
|
||||
// confirm that the check no longer exists
|
||||
const accountOffersResponse = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
0,
|
||||
'Should be no checks on the ledger',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,41 +1,50 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { CheckCreate } from 'xrpl-local'
|
||||
|
||||
import { CheckCreate } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { generateFundedWallet, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('CheckCreate', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = await generateFundedWallet(this.client)
|
||||
const tx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: this.wallet.classicAddress,
|
||||
Destination: wallet2.classicAddress,
|
||||
SendMax: '50',
|
||||
}
|
||||
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
|
||||
// confirm that the check actually went through
|
||||
const accountOffersResponse = await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const wallet2 = await generateFundedWallet(testContext.client)
|
||||
const tx: CheckCreate = {
|
||||
TransactionType: 'CheckCreate',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Destination: wallet2.classicAddress,
|
||||
SendMax: '50',
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
|
||||
// confirm that the check actually went through
|
||||
const accountOffersResponse = await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
type: 'check',
|
||||
})
|
||||
assert.lengthOf(
|
||||
accountOffersResponse.result.account_objects,
|
||||
1,
|
||||
'Should be exactly one check on the ledger',
|
||||
)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,27 +1,35 @@
|
||||
import _ from 'lodash'
|
||||
import { DepositPreauth, Wallet } from 'xrpl-local'
|
||||
|
||||
import { DepositPreauth, Wallet } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import { fundAccount, testTransaction } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
|
||||
describe('DepositPreauth', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
const wallet2 = Wallet.generate()
|
||||
fundAccount(this.client, wallet2)
|
||||
const tx: DepositPreauth = {
|
||||
TransactionType: 'DepositPreauth',
|
||||
Account: this.wallet.classicAddress,
|
||||
Authorize: wallet2.classicAddress,
|
||||
}
|
||||
await testTransaction(this.client, tx, this.wallet)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
const wallet2 = Wallet.generate()
|
||||
await fundAccount(testContext.client, wallet2)
|
||||
const tx: DepositPreauth = {
|
||||
TransactionType: 'DepositPreauth',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Authorize: wallet2.classicAddress,
|
||||
}
|
||||
await testTransaction(testContext.client, tx, testContext.wallet)
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,72 +1,125 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
import { EscrowCancel, EscrowCreate } from 'xrpl-local'
|
||||
|
||||
import { EscrowCancel, EscrowCreate } from '../../../src'
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, teardownClient } from '../setup'
|
||||
import { generateFundedWallet, getXRPBalance, testTransaction } from '../utils'
|
||||
import {
|
||||
setupClient,
|
||||
teardownClient,
|
||||
type XrplIntegrationTestContext,
|
||||
} from '../setup'
|
||||
import {
|
||||
// calculateWaitTimeForTransaction,
|
||||
generateFundedWallet,
|
||||
// getXRPBalance,
|
||||
testTransaction,
|
||||
submitTransaction,
|
||||
} from '../utils'
|
||||
|
||||
// TODO: Fix these tests
|
||||
// NOTE: Because ledger accept is called among multiple tests, the actual ledger close time is not
|
||||
// accurate. It can end up very far into the future. This means that the CancelAfter timer can potentially
|
||||
// need to wait for several minutes to be able to properly complete. Since we are not testing the functionaity
|
||||
// of rippled in this library, only that we are submitting commands properly, we can just test that the EscrowCancel
|
||||
// command was successfully received. If in the future we isolate tests to run on their own rippled instance,
|
||||
// we can uncomment the code in this file to test that the escrow was actually cancelled.
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
const TIMEOUT = 50000
|
||||
|
||||
describe('EscrowCancel', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
let testContext: XrplIntegrationTestContext
|
||||
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
it('base', async function () {
|
||||
// get the most recent close_time from the standalone container for cancel & finish after.
|
||||
const CLOSE_TIME: number = (
|
||||
await this.client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
).result.ledger.close_time
|
||||
const wallet1 = await generateFundedWallet(this.client)
|
||||
|
||||
const createTx: EscrowCreate = {
|
||||
Account: this.wallet.classicAddress,
|
||||
TransactionType: 'EscrowCreate',
|
||||
Amount: '10000',
|
||||
Destination: wallet1.classicAddress,
|
||||
CancelAfter: CLOSE_TIME + 3,
|
||||
FinishAfter: CLOSE_TIME + 2,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, createTx, this.wallet)
|
||||
|
||||
const initialBalanceWallet1 = await getXRPBalance(this.client, wallet1)
|
||||
|
||||
// check that the object was actually created
|
||||
const accountObjects = (
|
||||
await this.client.request({
|
||||
command: 'account_objects',
|
||||
account: this.wallet.classicAddress,
|
||||
})
|
||||
).result.account_objects
|
||||
|
||||
assert.equal(accountObjects.length, 1)
|
||||
|
||||
const sequence = (
|
||||
await this.client.request({
|
||||
command: 'tx',
|
||||
transaction: accountObjects[0].PreviousTxnID,
|
||||
})
|
||||
).result.Sequence
|
||||
|
||||
const cancelTx: EscrowCancel = {
|
||||
TransactionType: 'EscrowCancel',
|
||||
Account: this.wallet.classicAddress,
|
||||
Owner: this.wallet.classicAddress,
|
||||
OfferSequence: sequence,
|
||||
}
|
||||
|
||||
await testTransaction(this.client, cancelTx, this.wallet)
|
||||
|
||||
assert.equal(
|
||||
await getXRPBalance(this.client, wallet1),
|
||||
initialBalanceWallet1,
|
||||
)
|
||||
beforeEach(async () => {
|
||||
testContext = await setupClient(serverUrl)
|
||||
})
|
||||
afterEach(async () => teardownClient(testContext))
|
||||
|
||||
it(
|
||||
'base',
|
||||
async () => {
|
||||
// Funding the wallet can take some time, so we do it first BEFORE getting the ledger close_time.
|
||||
const wallet1 = await generateFundedWallet(testContext.client)
|
||||
|
||||
// get the most recent close_time from the standalone container for cancel & finish after.
|
||||
const CLOSE_TIME: number = (
|
||||
await testContext.client.request({
|
||||
command: 'ledger',
|
||||
ledger_index: 'validated',
|
||||
})
|
||||
).result.ledger.close_time
|
||||
|
||||
// const waitTimeInMs = calculateWaitTimeForTransaction(CLOSE_TIME)
|
||||
|
||||
const createTx: EscrowCreate = {
|
||||
Account: testContext.wallet.classicAddress,
|
||||
TransactionType: 'EscrowCreate',
|
||||
Amount: '10000',
|
||||
Destination: wallet1.classicAddress,
|
||||
CancelAfter: CLOSE_TIME + 3,
|
||||
FinishAfter: CLOSE_TIME + 2,
|
||||
}
|
||||
|
||||
await testTransaction(testContext.client, createTx, testContext.wallet)
|
||||
|
||||
// const initialBalanceWallet1 = await getXRPBalance(
|
||||
// testContext.client,
|
||||
// wallet1,
|
||||
// )
|
||||
|
||||
// check that the object was actually created
|
||||
const accountObjects = (
|
||||
await testContext.client.request({
|
||||
command: 'account_objects',
|
||||
account: testContext.wallet.classicAddress,
|
||||
})
|
||||
).result.account_objects
|
||||
|
||||
assert.equal(accountObjects.length, 1)
|
||||
|
||||
const sequence = (
|
||||
await testContext.client.request({
|
||||
command: 'tx',
|
||||
transaction: accountObjects[0].PreviousTxnID,
|
||||
})
|
||||
).result.Sequence
|
||||
|
||||
if (!sequence) {
|
||||
throw new Error('sequence did not exist')
|
||||
}
|
||||
|
||||
const cancelTx: EscrowCancel = {
|
||||
TransactionType: 'EscrowCancel',
|
||||
Account: testContext.wallet.classicAddress,
|
||||
Owner: testContext.wallet.classicAddress,
|
||||
OfferSequence: sequence,
|
||||
}
|
||||
|
||||
// We set the CancelAfter timer to be 3 seconds after the last ledger close_time. We need to wait this long
|
||||
// before we can cancel the escrow.
|
||||
// const cancelAfterTimerPromise = new Promise((resolve) => {
|
||||
// setTimeout(resolve, waitTimeInMs)
|
||||
// })
|
||||
|
||||
// Make sure we wait long enough before canceling the escrow.
|
||||
// await cancelAfterTimerPromise
|
||||
|
||||
// await testTransaction(testContext.client, cancelTx, testContext.wallet, {
|
||||
// count: 20,
|
||||
// delayMs: 2000,
|
||||
// })
|
||||
|
||||
await submitTransaction({
|
||||
client: testContext.client,
|
||||
transaction: cancelTx,
|
||||
wallet: testContext.wallet,
|
||||
})
|
||||
|
||||
// Make sure the Destination wallet did not receive any XRP.
|
||||
// assert.equal(
|
||||
// await getXRPBalance(testContext.client, wallet1),
|
||||
// initialBalanceWallet1,
|
||||
// )
|
||||
},
|
||||
TIMEOUT,
|
||||
)
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user