Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import { StyleSheet } from 'react-native';
import { fireEvent, within } from '@testing-library/react-native';
import { strings } from '../../../../../../../locales/i18n';
import PerpsProOrderBookPanel from './PerpsProOrderBookPanel';
import renderWithProvider from '../../../../../../util/test/renderWithProvider';
import { backgroundState } from '../../../../../../util/test/initial-root-state';
Expand Down Expand Up @@ -64,6 +66,50 @@ const mockOrderBook: OrderBookData = {
maxTotal: '3.5',
};

/**
* kPEPE-shaped book (TAT-3713): a sub-cent mid whose ladder prices need all six
* decimals to stay distinguishable at the 1e-6 grouping step.
*/
const subCentOrderBook: OrderBookData = {
bids: [
{
price: '0.002651',
size: '1500000',
total: '1500000',
notional: '3976.5',
totalNotional: '3976.5',
},
{
price: '0.002650',
size: '2000000',
total: '3500000',
notional: '5300',
totalNotional: '9276.5',
},
],
asks: [
{
price: '0.002653',
size: '1200000',
total: '1200000',
notional: '3183.6',
totalNotional: '3183.6',
},
{
price: '0.002654',
size: '1800000',
total: '3000000',
notional: '4777.2',
totalNotional: '7960.8',
},
],
spread: '0.000002',
spreadPercentage: '0.075',
midPrice: '0.002652',
lastUpdated: 1700000000000,
maxTotal: '3500000',
};

describe('PerpsProOrderBookPanel', () => {
const testID = PerpsProMarketViewSelectorsIDs.ORDER_BOOK_PANEL;

Expand Down Expand Up @@ -504,4 +550,61 @@ describe('PerpsProOrderBookPanel', () => {
nSigFigs: 4,
});
});

describe('sub-cent ladder prices (TAT-3713)', () => {
const renderSubCentLadder = () => {
mockUsePerpsLiveOrderBook.mockImplementation(() => ({
orderBook: subCentOrderBook,
isLoading: false,
error: null,
connectionStatus: 'connected',
reconnect: mockReconnect,
}));

return renderWithProvider(
<PerpsProOrderBookPanel symbol="kPEPE" marketPrice={0.002652} />,
{ state: { engine: { backgroundState } } },
);
};

it('renders all six decimals of a ladder price on one line', () => {
const { getByTestId } = renderSubCentLadder();

const priceCell = getByTestId(`${testID}-bid-row-0-price`);

expect(priceCell).toHaveTextContent('$0.002651');
expect(priceCell).toHaveProp('numberOfLines', 1);
});

it('gives the price cell the width the value cell does not need', () => {
const { getByTestId } = renderSubCentLadder();

const priceStyle = StyleSheet.flatten(
getByTestId(`${testID}-bid-row-0-price`).props.style,
);
const valueStyle = StyleSheet.flatten(
getByTestId(`${testID}-bid-row-0-value`).props.style,
);

// An even split leaves each side 62px of the 132px order-book column,
// which cuts a nine-character price down to "$0.0026…".
expect(priceStyle).toMatchObject({ flexGrow: 1, flexBasis: '0%' });
expect(valueStyle).toMatchObject({ flexShrink: 0 });
expect(valueStyle.flexGrow).toBeUndefined();
});

it('gives the column headers the same width split as the rows', () => {
const { getByTestId } = renderSubCentLadder();

const headerValue = getByTestId(`${testID}-column-header-value`);
const headerValueStyle = StyleSheet.flatten(headerValue.props.style);

// The value header is also wider than half the column.
expect(headerValue).toHaveTextContent(
`${strings('perps.order_book.total')} (USD)`,
);
expect(headerValueStyle).toMatchObject({ flexShrink: 0 });
expect(headerValueStyle.flexGrow).toBeUndefined();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,20 @@ export interface PerpsProOrderBookPanelProps {
}

/**
* Price and value share the row equally (Figma: two 62px columns with an 8px
* gutter). Fixed halves plus single-line text are what keep the two from
* running into each other once either side grows.
* The row cannot be two equal halves. The order-book column is a fixed 132px
* (`PRO_ORDER_BOOK_COLUMN_WIDTH`), so equal halves give each side 62px, and a
* sub-cent price needs more than that: kPEPE renders "$0.002645" — nine
* characters at the 1e-6 grouping step — and got ellipsised to "$0.0026…",
* which makes every ladder row read the same (TAT-3713).
*
* The value side is the one with room to give: `formatColumnValue` compacts
* anything at or above 1,000 to K/M/B/T, so it never exceeds ~7 characters.
* Sizing it to its content and letting the price take the remainder keeps both
* whole. Each side still keeps single-line text, so the extreme case degrades
* to a truncated price rather than a row that wraps or overflows.
*/
const COLUMN_CLASS = 'relative z-10 flex-1';
const VALUE_COLUMN_CLASS = `${COLUMN_CLASS} text-right`;
const PRICE_COLUMN_CLASS = 'relative z-10 flex-1';
const VALUE_COLUMN_CLASS = 'relative z-10 shrink-0 text-right';

interface OrderBookRowProps {
level: OrderBookLevel;
Expand Down Expand Up @@ -149,7 +157,7 @@ const OrderBookRow = ({
fontWeight={FontWeight.Medium}
color={sideColor}
numberOfLines={1}
twClassName={COLUMN_CLASS}
twClassName={PRICE_COLUMN_CLASS}
testID={`${testID}-price`}
>
{priceLabel}
Expand Down Expand Up @@ -642,6 +650,7 @@ const PerpsProOrderBookPanel = ({
color={TextColor.TextAlternative}
numberOfLines={1}
twClassName="flex-1"
testID={`${testID}-column-header-price`}
>
{strings('perps.order_book.price')}
</Text>
Expand All @@ -650,7 +659,8 @@ const PerpsProOrderBookPanel = ({
fontWeight={FontWeight.Medium}
color={TextColor.TextAlternative}
numberOfLines={1}
twClassName="flex-1 text-right"
twClassName="shrink-0 text-right"
testID={`${testID}-column-header-value`}
>
{`${metricLabel} (${unitLabel})`}
</Text>
Expand Down
Loading