2020 */
2121
2222import { renderHook , act } from '@testing-library/react-native' ;
23+ import { type OrderResult , type Position } from '@metamask/perps-controller' ;
2324
2425import { buildPerpsFlowHarness } from '../../../../../tests/integration/harnesses/perps-flow' ;
2526import { usePerpsTrading } from '../hooks/usePerpsTrading' ;
@@ -73,22 +74,20 @@ describe('Perps order lifecycle — FLOW integration', () => {
7374 * → result.current.flipPosition({ position })
7475 * → Engine.context.PerpsController.flipPosition (shim)
7576 * → real TradingService.flipPosition
76- * → constructs OrderParams with size=2x, no currentPrice
77+ * → constructs OrderParams with size=2x
7778 * → real provider.placeOrder(orderParams)
78- * → real validateOrder
79- * → returns ORDER_PRICE_REQUIRED (production bug)
79+ * → fetches live price for validation
80+ * → mocked SDK exchange.order
8081 *
81- * Shape A could only catch the bug by calling `provider.validateOrder`
82- * directly. Shape B catches it through the actual user-facing chain —
83- * proving the TradingService → provider seam is genuinely covered.
82+ * Shape B catches the actual user-facing chain, proving the
83+ * TradingService → provider seam is genuinely covered.
8484 */
85- describe ( 'reversing a position via the hook chain (production bug) ' , ( ) => {
86- it ( 'reproduces the ORDER_PRICE_REQUIRED bug end-to-end' , async ( ) => {
85+ describe ( 'reversing a position via the hook chain' , ( ) => {
86+ it ( 'places the flip market order end-to-end' , async ( ) => {
8787 // Arrange
8888 const { harness } = buildPerpsFlowHarness ( ) ;
8989 harness . setupTradingReady ( ) ;
90- const openLongBTC = {
91- coin : 'BTC' ,
90+ const openLongBTC : Position = {
9291 symbol : 'BTC' ,
9392 size : '0.1' , // positive = long; flipPosition will compute 2x = 0.2
9493 entryPrice : '50000' ,
@@ -100,30 +99,39 @@ describe('Perps order lifecycle — FLOW integration', () => {
10099 maxLeverage : 50 ,
101100 returnOnEquity : '0' ,
102101 cumulativeFunding : { allTime : '0' , sinceOpen : '0' , sinceChange : '0' } ,
102+ takeProfitCount : 0 ,
103+ stopLossCount : 0 ,
103104 } ;
104105 const { result } = renderHook ( ( ) => usePerpsTrading ( ) ) ;
105106
106107 // Act — through the real hook → real TradingService → real provider chain
107- let flipResult : Awaited <
108- ReturnType < typeof result . current . flipPosition >
109- > | null = null ;
108+ let flipResult : OrderResult | null = null ;
110109 await act ( async ( ) => {
111110 flipResult = await result . current . flipPosition ( {
112- position : openLongBTC as never ,
111+ symbol : 'BTC' ,
112+ position : openLongBTC ,
113113 } ) ;
114114 } ) ;
115115
116- // Assert — flipPosition returns a failed result with the right error
117- // code. The bug is reachable because TradingService constructs the
118- // OrderParams without `currentPrice`, and the real provider's
119- // `validateOrder` rejects market orders without a price.
116+ // Assert — flipPosition succeeds because the provider fetches the
117+ // current market price before running order validation.
120118 expect ( flipResult ) . not . toBeNull ( ) ;
121- expect ( flipResult ) . toMatchObject ( { success : false } ) ;
122- expect ( ( flipResult as { error : string } ) . error ) . toMatch (
123- / O R D E R _ P R I C E _ R E Q U I R E D / ,
119+ if ( ! flipResult ) {
120+ throw new Error ( 'Expected flipPosition to return a result' ) ;
121+ }
122+ expect ( flipResult ) . toMatchObject ( { success : true } ) ;
123+ expect ( harness . mocks . exchangeClient . order ) . toHaveBeenCalledTimes ( 1 ) ;
124+ expect ( harness . mocks . exchangeClient . order ) . toHaveBeenCalledWith (
125+ expect . objectContaining ( {
126+ orders : [
127+ expect . objectContaining ( {
128+ a : 0 ,
129+ b : false ,
130+ t : { limit : { tif : 'FrontendMarket' } } ,
131+ } ) ,
132+ ] ,
133+ } ) ,
124134 ) ;
125- // SDK was never called — validation aborted the flow before placement.
126- expect ( harness . mocks . exchangeClient . order ) . not . toHaveBeenCalled ( ) ;
127135 } ) ;
128136 } ) ;
129137} ) ;
0 commit comments