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
41 changes: 41 additions & 0 deletions app/components/Nav/App/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -890,4 +890,45 @@ describe('App', () => {
});
});
});

describe('route registration', () => {
const renderAppWithRouteState = (
routeState: PartialState<NavigationState>,
) => {
const mockStore = configureMockStore();
const store = mockStore(initialState);

const Providers = ({ children }: { children: React.ReactElement }) => (
<NavigationContainer initialState={routeState}>
<Provider store={store}>
<ThemeContext.Provider value={mockTheme}>
{children}
</ThemeContext.Provider>
</Provider>
</NavigationContainer>
);

return render(<App />, { wrapper: Providers });
};

it('registers the eligibility failed modal route', async () => {
const routeState = {
index: 0,
routes: [
{
name: Routes.MODAL.ROOT_MODAL_FLOW,
params: {
screen: Routes.SHEET.ELIGIBILITY_FAILED_MODAL,
},
},
],
};

const { getByTestId } = renderAppWithRouteState(routeState);

await waitFor(() => {
expect(getByTestId('eligibility-failed-modal')).toBeTruthy();
});
});
});
});
5 changes: 5 additions & 0 deletions app/components/Nav/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ import SkipAccountSecurityModal from '../../UI/SkipAccountSecurityModal';
import SuccessErrorSheet from '../../Views/SuccessErrorSheet';
import ConfirmTurnOnBackupAndSyncModal from '../../UI/Identity/ConfirmTurnOnBackupAndSyncModal/ConfirmTurnOnBackupAndSyncModal';
import AddNewAccountBottomSheet from '../../Views/AddNewAccount/AddNewAccountBottomSheet';
import EligibilityFailedModal from '../../UI/Ramp/components/EligibilityFailedModal';
import SwitchAccountTypeModal from '../../Views/confirmations/components/modals/switch-account-type-modal';
import { AccountDetails } from '../../Views/MultichainAccounts/AccountDetails/AccountDetails';
import { AccountGroupDetails } from '../../Views/MultichainAccounts/AccountGroupDetails/AccountGroupDetails';
Expand Down Expand Up @@ -400,6 +401,10 @@ const RootModalFlow = (props: RootModalFlowProps) => (
name={Routes.SHEET.SUCCESS_ERROR_SHEET}
component={SuccessErrorSheet}
/>
<Stack.Screen
name={Routes.SHEET.ELIGIBILITY_FAILED_MODAL}
component={EligibilityFailedModal}
/>
<Stack.Screen
name={Routes.SHEET.ACCOUNT_SELECTOR}
component={AccountSelector}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ jest.mock('../../../../../util/theme', () => ({
}));

describe('PredictDetailsChart', () => {
const BASE_TIMESTAMP = 1_700_000_000_000;
const FORTY_FIVE_MINUTES_IN_MS = 45 * 60 * 1000;
const TWELVE_HOURS_IN_MS = 12 * 60 * 60 * 1000;
const TWENTY_FOUR_HOURS_IN_MS = 24 * 60 * 60 * 1000;

const mockSingleSeries: ChartSeries[] = [
{
label: 'Outcome 1',
Expand Down Expand Up @@ -175,7 +180,27 @@ describe('PredictDetailsChart', () => {
});

it('highlights selected timeframe', () => {
const { getByText } = setupTest({ selectedTimeframe: '1d' });
const daySpanSeries: ChartSeries[] = [
{
label: 'Extended Outcome',
color: '#28C76F',
data: [
{ timestamp: BASE_TIMESTAMP, value: 0.4 },
{
timestamp: BASE_TIMESTAMP + 18 * 60 * 60 * 1000,
value: 0.5,
},
{
timestamp: BASE_TIMESTAMP + 36 * 60 * 60 * 1000,
value: 0.6,
},
],
},
];
const { getByText } = setupTest({
data: daySpanSeries,
selectedTimeframe: '1d',
});

expect(getByText('1D')).toBeOnTheScreen();
});
Expand All @@ -196,14 +221,124 @@ describe('PredictDetailsChart', () => {
expect(queryByText('Loading price history...')).not.toBeOnTheScreen();
});

it('renders custom empty label when provided', () => {
it('returns null when no data provided even with custom empty label', () => {
const customLabel = 'No data available';
const { getByText } = setupTest({
const { queryByTestId, queryByText } = setupTest({
data: [{ label: 'Empty', color: '#000', data: [] }],
emptyLabel: customLabel,
});

expect(getByText(customLabel)).toBeOnTheScreen();
expect(queryByTestId('line-chart')).toBeNull();
expect(queryByText(customLabel)).toBeNull();
});
});

describe('Timeframe filtering', () => {
it('returns null when all series fall outside selected timeframe', () => {
const dataOutsideTimeframe: ChartSeries[] = [
{
label: 'Outcome Short',
color: '#123456',
data: [
{ timestamp: BASE_TIMESTAMP, value: 0.5 },
{ timestamp: BASE_TIMESTAMP + 30 * 60 * 1000, value: 0.6 },
],
},
];

const { queryByTestId, queryByText } = setupTest({
data: dataOutsideTimeframe,
selectedTimeframe: '1d',
isLoading: false,
});

expect(queryByTestId('line-chart')).toBeNull();
expect(queryByText('1D')).toBeNull();
});

it('omits series that do not span selected timeframe', () => {
const longSpanSeriesA: ChartSeries = {
label: 'Outcome Long A',
color: '#28C76F',
data: [
{ timestamp: BASE_TIMESTAMP, value: 0.4 },
{
timestamp: BASE_TIMESTAMP + TWELVE_HOURS_IN_MS,
value: 0.5,
},
{
timestamp: BASE_TIMESTAMP + TWENTY_FOUR_HOURS_IN_MS,
value: 0.6,
},
],
};
const longSpanSeriesB: ChartSeries = {
label: 'Outcome Long B',
color: '#4459FF',
data: [
{ timestamp: BASE_TIMESTAMP, value: 0.3 },
{
timestamp: BASE_TIMESTAMP + TWENTY_FOUR_HOURS_IN_MS,
value: 0.35,
},
{
timestamp: BASE_TIMESTAMP + 2 * TWENTY_FOUR_HOURS_IN_MS,
value: 0.38,
},
],
};
const shortSpanSeries: ChartSeries = {
label: 'Outcome Short',
color: '#CA3542',
data: [
{ timestamp: BASE_TIMESTAMP, value: 0.2 },
{
timestamp: BASE_TIMESTAMP + 30 * 60 * 1000,
value: 0.25,
},
],
};

const { getAllByTestId, getByText, queryByText } = setupTest({
data: [longSpanSeriesA, longSpanSeriesB, shortSpanSeries],
selectedTimeframe: '1d',
});

expect(getAllByTestId('line-chart').length).toBeGreaterThan(0);
expect(getByText(/Outcome Long A/)).toBeOnTheScreen();
expect(getByText(/Outcome Long B/)).toBeOnTheScreen();
expect(queryByText('Outcome Short')).toBeNull();
});

it('renders series that cover at least half of selected timeframe span', () => {
const halfDaySpanSeries: ChartSeries = {
label: 'Outcome Half Day',
color: '#FFAA00',
data: [
{ timestamp: BASE_TIMESTAMP, value: 0.45 },
{
timestamp: BASE_TIMESTAMP + TWELVE_HOURS_IN_MS,
value: 0.5,
},
],
};

const { getByTestId } = setupTest({
data: [halfDaySpanSeries],
selectedTimeframe: '1d',
});

expect(getByTestId('line-chart')).toBeOnTheScreen();
});

it('hides chart when series contain no data points for selected timeframe', () => {
const { queryByTestId } = setupTest({
data: [{ label: 'Empty', color: '#000000', data: [] }],
selectedTimeframe: '1d',
isLoading: false,
});

expect(queryByTestId('line-chart')).toBeNull();
});
});

Expand Down Expand Up @@ -297,12 +432,9 @@ describe('PredictDetailsChart', () => {
data: [{ timestamp: 1640995200000, value: 0.5 }],
},
];
const { getByTestId } = setupTest({ data: singlePointData });

const chartData = getByTestId('chart-data');
const data = JSON.parse(String(chartData.children[0]));
const { queryByTestId } = setupTest({ data: singlePointData });

expect(data).toEqual([0.5]);
expect(queryByTestId('line-chart')).toBeNull();
});

it('handles empty data array', () => {
Expand All @@ -313,12 +445,9 @@ describe('PredictDetailsChart', () => {
data: [],
},
];
const { getByTestId } = setupTest({ data: emptyData });
const { queryByTestId } = setupTest({ data: emptyData });

const chartData = getByTestId('chart-data');
const data = JSON.parse(String(chartData.children[0]));

expect(data).toEqual(expect.arrayContaining([0]));
expect(queryByTestId('line-chart')).toBeNull();
});

it('calculates correct chart bounds with padding', () => {
Expand Down Expand Up @@ -525,16 +654,22 @@ describe('PredictDetailsChart', () => {
label: 'Series A',
color: '#4459FF',
data: [
{ timestamp: 1, value: 0.3 },
{ timestamp: 2, value: 0.7 },
{ timestamp: BASE_TIMESTAMP, value: 0.3 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.7,
},
],
},
{
label: 'Series B',
color: '#FF6B6B',
data: [
{ timestamp: 1, value: 0.7 },
{ timestamp: 2, value: 0.3 },
{ timestamp: BASE_TIMESTAMP, value: 0.7 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.3,
},
],
},
];
Expand All @@ -552,16 +687,22 @@ describe('PredictDetailsChart', () => {
label: 'Close A',
color: '#4459FF',
data: [
{ timestamp: 1, value: 0.5 },
{ timestamp: 2, value: 0.501 },
{ timestamp: BASE_TIMESTAMP, value: 0.5 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.501,
},
],
},
{
label: 'Close B',
color: '#FF6B6B',
data: [
{ timestamp: 1, value: 0.502 },
{ timestamp: 2, value: 0.503 },
{ timestamp: BASE_TIMESTAMP, value: 0.502 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.503,
},
],
},
];
Expand Down Expand Up @@ -614,12 +755,24 @@ describe('PredictDetailsChart', () => {
{
label: 'Blue',
color: '#0000FF',
data: [{ timestamp: 1, value: 0.5 }],
data: [
{ timestamp: BASE_TIMESTAMP, value: 0.5 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.55,
},
],
},
{
label: 'Red',
color: '#FF0000',
data: [{ timestamp: 1, value: 0.5 }],
data: [
{ timestamp: BASE_TIMESTAMP, value: 0.5 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.45,
},
],
},
];

Expand All @@ -645,24 +798,33 @@ describe('PredictDetailsChart', () => {
label: 'Series 1',
color: '#4459FF',
data: [
{ timestamp: 1, value: 0.5 },
{ timestamp: 2, value: 0.6 },
{ timestamp: BASE_TIMESTAMP, value: 0.5 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.6,
},
],
},
{
label: 'Series 2',
color: '#FF6B6B',
data: [
{ timestamp: 1, value: 0.3 },
{ timestamp: 2, value: 0.4 },
{ timestamp: BASE_TIMESTAMP, value: 0.3 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.4,
},
],
},
{
label: 'Series 3',
color: '#F0B034',
data: [
{ timestamp: 1, value: 0.2 },
{ timestamp: 2, value: 0.25 },
{ timestamp: BASE_TIMESTAMP, value: 0.2 },
{
timestamp: BASE_TIMESTAMP + FORTY_FIVE_MINUTES_IN_MS,
value: 0.25,
},
],
},
];
Expand Down
Loading
Loading