import { CreateChannelParams } from '@statechannels/client-api-schema' ; import Knex from 'knex' ; import { setupPeerEngines , teardownPeerSetup , PeerSetup } from '../../jest/with-peers-setup-teardown' ; import { WalletObjective , ObjectiveModel } from '../models/objective' ; import { createChannelArgs } from '../engine/__test__/fixtures/create-channel' ; import { bob } from '../engine/__test__/fixtures/participants' ; import { getChannelResultFor , getPayloadFor } from '../__test__/test-helpers' ; jest . setTimeout ( 10000 ) ; let peerSetup ; beforeAll ( async ( ) => { peerSetup = await setupPeerEngines ( true ) ; } ) ; afterAll ( async ( ) => { await teardownPeerSetup ( peerSetup ) ; } ) ; test ( 'Objectives can be synced if a message is lost' , async ( ) => { const createChannelParams = createChannelArgs ( ) ; const { peerEngines } = peerSetup ; const messageToLose = await peerEngines . a . createChannel ( createChannelParams ) ; const channelId = messageToLose . channelResult . channelId ; const objectiveId = `OpenChannel-${ channelId }` ; expect ( await getObjective ( peerEngines . a . knex , objectiveId ) ) . toBeDefined ( ) ; expect ( await getObjective ( peerEngines . b . knex , objectiveId ) ) . toBeUndefined ( ) ; const outbox = await peerEngines . a . syncObjectives ( [ objectiveId ] ) ; const { channelResults } = await peerEngines . b . pushMessage ( getPayloadFor ( bob ( ) . participantId , outbox ) ) ; expect ( getChannelResultFor ( channelId , channelResults ) ) . toMatchObject ( { status : 'proposed' , turnNum : 0 , } ) ; } ) ; test ( 'handles the objective being synced even if no message is lost' , async ( ) => { const createChannelParams = createChannelArgs ( ) ; const { peerEngines } = peerSetup ; const messageResponse = await peerEngines . a . createChannel ( createChannelParams ) ; const channelId = messageResponse . channelResult . channelId ; const objectiveId = `OpenChannel-${ channelId }` ; await peerEngines . b . pushMessage ( getPayloadFor ( bob ( ) . participantId , messageResponse . outbox ) ) ; expect ( await getObjective ( peerEngines . a . knex , objectiveId ) ) . toBeDefined ( ) ; expect ( await getObjective ( peerEngines . b . knex , objectiveId ) ) . toBeDefined ( ) ; const syncOutbox = await peerEngines . a . syncObjectives ( [ objectiveId ] ) ; const { outbox , channelResults } = await peerEngines . b . pushMessage ( getPayloadFor ( bob ( ) . participantId , syncOutbox ) ) ; expect ( outbox ) . toHaveLength ( 1 ) ; expect ( outbox [ 0 ] ) . toMatchObject ( { method : 'MessageQueued' , params : { recipient : 'alice' , sender : 'bob' , data : { signedStates : [ expect . objectContaining ( { turnNum : 0 } ) ] } , } , } ) ; expect ( channelResults ) . toHaveLength ( 1 ) ; } ) ; test ( 'Can successfully push the sync objective message multiple times' , async ( ) => { const createChannelParams = createChannelArgs ( ) ; const { peerEngines } = peerSetup ; const messageToLose = await peerEngines . a . createChannel ( createChannelParams ) ; const channelId = messageToLose . channelResult . channelId ; const objectiveId = `OpenChannel-${ channelId }` ; expect ( await getObjective ( peerEngines . a . knex , objectiveId ) ) . toBeDefined ( ) ; expect ( await getObjective ( peerEngines . b . knex , objectiveId ) ) . toBeUndefined ( ) ; const syncResult = await peerEngines . a . syncObjectives ( [ objectiveId ] ) ; await peerEngines . b . pushMessage ( getPayloadFor ( bob ( ) . participantId , syncResult ) ) ; const { outbox , channelResults } = await peerEngines . b . pushMessage ( getPayloadFor ( bob ( ) . participantId , syncResult ) ) ; expect ( outbox ) . toHaveLength ( 1 ) ; expect ( outbox [ 0 ] ) . toMatchObject ( { method : 'MessageQueued' , params : { recipient : 'alice' , sender : 'bob' , data : { signedStates : [ expect . objectContaining ( { turnNum : 0 } ) ] } , } , } ) ; expect ( channelResults ) . toHaveLength ( 1 ) ; expect ( channelResults [ 0 ] ) . toMatchObject ( { channelId } ) ; } ) ; async function getObjective ( knex , objectiveId ) { const model = await ObjectiveModel . query ( knex ) . findById ( objectiveId ) ; return model ?. toObjective ( ) ; }