mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-05 05:15:48 +00:00
test: subscription standalone integration tests (#1690)
Add tests for pathFind and other subscriptions that can be tested with a standalone node.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import type { Amount, Currency, Path, StreamType } from '../common'
|
||||
import Offer from '../ledger/offer'
|
||||
import { OfferCreate, Transaction } from '../transactions'
|
||||
import TransactionMetadata from '../transactions/metadata'
|
||||
|
||||
@@ -71,9 +72,12 @@ export interface SubscribeRequest extends BaseRequest {
|
||||
* @category Responses
|
||||
*/
|
||||
export interface SubscribeResponse extends BaseResponse {
|
||||
result: Record<string, never> | Stream
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- actually should be an empty object
|
||||
result: {} | LedgerStreamResponse | BooksSnapshot
|
||||
}
|
||||
|
||||
type BooksSnapshot = Offer[]
|
||||
|
||||
interface BaseStream {
|
||||
type: string
|
||||
}
|
||||
@@ -124,6 +128,46 @@ export interface LedgerStream extends BaseStream {
|
||||
validated_ledgers?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* This response mirrors the LedgerStream, except it does NOT include the 'type' nor 'txn_count' fields.
|
||||
*/
|
||||
// eslint-disable-next-line import/no-unused-modules -- Detailed enough to be worth exporting for end users.
|
||||
export interface LedgerStreamResponse {
|
||||
/**
|
||||
* The reference transaction cost as of this ledger version, in drops of XRP.
|
||||
* If this ledger version includes a SetFee pseudo-transaction the new.
|
||||
* Transaction cost applies starting with the following ledger version.
|
||||
*/
|
||||
fee_base: number
|
||||
/** The reference transaction cost in "fee units". */
|
||||
fee_ref: number
|
||||
/** The identifying hash of the ledger version that was closed. */
|
||||
ledger_hash: string
|
||||
/** The ledger index of the ledger that was closed. */
|
||||
ledger_index: number
|
||||
/** The time this ledger was closed, in seconds since the Ripple Epoch. */
|
||||
ledger_time: number
|
||||
/**
|
||||
* The minimum reserve, in drops of XRP, that is required for an account. If
|
||||
* this ledger version includes a SetFee pseudo-transaction the new base reserve
|
||||
* applies starting with the following ledger version.
|
||||
*/
|
||||
reserve_base: number
|
||||
/**
|
||||
* The owner reserve for each object an account owns in the ledger, in drops
|
||||
* of XRP. If the ledger includes a SetFee pseudo-transaction the new owner
|
||||
* reserve applies after this ledger.
|
||||
*/
|
||||
reserve_inc: number
|
||||
/**
|
||||
* Range of ledgers that the server has available. This may be a disjoint
|
||||
* sequence such as 24900901-24900984,24901116-24901158. This field is not
|
||||
* returned if the server is not connected to the network, or if it is
|
||||
* connected but has not yet obtained a ledger from the network.
|
||||
*/
|
||||
validated_ledgers?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* The validations stream sends messages whenever it receives validation
|
||||
* messages, also called validation votes, regardless of whether or not the
|
||||
@@ -344,7 +388,9 @@ export interface PathFindStream extends BaseStream {
|
||||
* Array of objects with suggested paths to take. If empty, then no paths
|
||||
* were found connecting the source and destination accounts.
|
||||
*/
|
||||
alternatives: {
|
||||
alternatives:
|
||||
| []
|
||||
| {
|
||||
paths_computed: Path[]
|
||||
source_amount: Amount
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ async function processSuccessfulResponse(
|
||||
wallet: walletToFund,
|
||||
balance: await getUpdatedBalance(
|
||||
client,
|
||||
walletToFund.getClassicAddress(),
|
||||
walletToFund.classicAddress,
|
||||
startingBalance,
|
||||
),
|
||||
})
|
||||
|
||||
@@ -34,6 +34,7 @@ export * from './requests/noRippleCheck'
|
||||
export * from './requests/pathFind'
|
||||
export * from './requests/ripplePathFind'
|
||||
export * from './requests/submit'
|
||||
export * from './requests/subscribe'
|
||||
export * from './requests/tx'
|
||||
export * from './requests/utility'
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import { PathFindRequest, PathFindResponse } from 'xrpl-local'
|
||||
import {
|
||||
PathFindRequest,
|
||||
PathFindResponse,
|
||||
Client,
|
||||
PathFindStream,
|
||||
} from 'xrpl-local'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } from '../setup'
|
||||
import { generateFundedWallet } from '../utils'
|
||||
import { generateFundedWallet, ledgerAccept, subscribeDone } from '../utils'
|
||||
|
||||
// how long before each test case times out
|
||||
const TIMEOUT = 20000
|
||||
@@ -44,4 +49,61 @@ describe('path_find', function () {
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
})
|
||||
|
||||
/**
|
||||
* 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.getClassicAddress(),
|
||||
destination_account: wallet2.getClassicAddress(),
|
||||
destination_amount: '100',
|
||||
}
|
||||
this.client.request(pathFind).then((response) => {
|
||||
const expectedResponse: PathFindResponse = {
|
||||
id: response.id,
|
||||
status: 'success',
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
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
|
||||
client.on('path_find', (path) => {
|
||||
assert.equal(path.type, 'path_find')
|
||||
assert.deepEqual(
|
||||
_.omit(path, 'id'),
|
||||
_.omit(expectedStreamResult, 'id'),
|
||||
)
|
||||
subscribeDone(this.client, done)
|
||||
})
|
||||
|
||||
assert.deepEqual(response, expectedResponse)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
ledgerAccept(this.client)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
170
test/integration/requests/subscribe.ts
Normal file
170
test/integration/requests/subscribe.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import { assert } from 'chai'
|
||||
import _ from 'lodash'
|
||||
|
||||
import {
|
||||
Client,
|
||||
OfferCreate,
|
||||
SubscribeRequest,
|
||||
Wallet,
|
||||
SubscribeResponse,
|
||||
} from 'xrpl-local'
|
||||
import { StreamType } from 'xrpl-local/models/common'
|
||||
|
||||
import serverUrl from '../serverUrl'
|
||||
import { setupClient, suiteClientSetup, teardownClient } 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 request: SubscribeRequest = {
|
||||
command: 'subscribe',
|
||||
streams: [subscriptionStream],
|
||||
accounts: [wallet.getClassicAddress()],
|
||||
}
|
||||
|
||||
client.request(request).then((response) => {
|
||||
assert.equal(response.status, 'success')
|
||||
assert.equal(response.type, 'response')
|
||||
assert.deepEqual(response.result, {})
|
||||
})
|
||||
}
|
||||
|
||||
describe('subscribe', function () {
|
||||
this.timeout(TIMEOUT)
|
||||
|
||||
before(suiteClientSetup)
|
||||
beforeEach(_.partial(setupClient, serverUrl))
|
||||
afterEach(teardownClient)
|
||||
|
||||
/**
|
||||
* Subscribe streams which are not testable with just a standalone node:
|
||||
* (If that changes, please add tests for these streams).
|
||||
*
|
||||
* 'consensus'
|
||||
* 'manifests'
|
||||
* 'peer_status'
|
||||
* 'validations'
|
||||
* 'server'.
|
||||
*/
|
||||
|
||||
it('Successfully Subscribes', async function () {
|
||||
const response: SubscribeResponse = await this.client.request({
|
||||
command: 'subscribe',
|
||||
})
|
||||
|
||||
assert.deepEqual(response.result, {})
|
||||
assert.equal(response.type, 'response')
|
||||
})
|
||||
|
||||
it('Successfully Unsubscribes', async function () {
|
||||
const response = await this.client.request({
|
||||
command: 'unsubscribe',
|
||||
})
|
||||
|
||||
assert.deepEqual(response.result, {})
|
||||
assert.equal(response.type, 'response')
|
||||
})
|
||||
|
||||
it('Emits transaction', function (done) {
|
||||
const streamType = 'transactions'
|
||||
createTxHandlerTest(this.client, this.wallet, done, streamType).then(() => {
|
||||
// Trigger the event
|
||||
const tx: OfferCreate = {
|
||||
TransactionType: 'OfferCreate',
|
||||
Account: this.wallet.getClassicAddress(),
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: this.wallet.getClassicAddress(),
|
||||
value: '10',
|
||||
},
|
||||
}
|
||||
|
||||
testTransaction(this.client, tx, this.wallet)
|
||||
})
|
||||
})
|
||||
|
||||
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.getClassicAddress(),
|
||||
TakerGets: '13100000',
|
||||
TakerPays: {
|
||||
currency: 'USD',
|
||||
issuer: this.wallet.getClassicAddress(),
|
||||
value: '10',
|
||||
},
|
||||
}
|
||||
|
||||
// The transactions_proposed stream should trigger the transaction handler WITHOUT ledgerAccept
|
||||
const client: Client = this.client
|
||||
client.submit(this.wallet, tx)
|
||||
})
|
||||
})
|
||||
|
||||
// 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.getClassicAddress()],
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
assert.equal(response.type, 'response')
|
||||
assert.deepEqual(response.result, expectedResult)
|
||||
|
||||
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,
|
||||
})
|
||||
subscribeDone(this.client, done)
|
||||
})
|
||||
|
||||
// Trigger the event
|
||||
ledgerAccept(this.client)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -14,6 +14,11 @@ export async function ledgerAccept(client: Client): Promise<void> {
|
||||
await client.connection.request(request)
|
||||
}
|
||||
|
||||
export function subscribeDone(client: Client, done: Mocha.Done): void {
|
||||
client.removeAllListeners()
|
||||
done()
|
||||
}
|
||||
|
||||
export async function fundAccount(
|
||||
client: Client,
|
||||
wallet: Wallet,
|
||||
|
||||
Reference in New Issue
Block a user