Skip to content

Commit

Permalink
wip: wip tests before rebasing to origin/main.
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt561 committed Jan 10, 2025
1 parent f98b00e commit 4d71a35
Show file tree
Hide file tree
Showing 17 changed files with 717 additions and 207 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { strings } from '../../../../../../../locales/i18n';

// Small dataset ~10 points or less
export const SMALL_DATASET_THRESHOLD = 10;
export const SMALL_DATASET_PADDING = 16;
// Large dataset ~90 points and more
export const SMALL_DATASET_SNAP_RATIO = 0.5;
export const SMALL_DATASET_GRAPH_INSET = 20;
export const STANDARD_DATASET_GRAPH_INSET = 10;

export const CHART_BUTTONS: ChartButton[] = [
{ label: strings('stake.interactive_chart.timespan_buttons.7D'), value: 7 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,114 +2,105 @@ import React from 'react';
import renderWithProvider from '../../../../../../util/test/renderWithProvider';
import InteractiveTimespanChart, { InteractiveTimespanChartProps } from '.';
import { strings } from '../../../../../../../locales/i18n';
import { fireEvent } from '@testing-library/react-native';
import { AreaChart } from 'react-native-svg-charts';
import { fireEvent, screen } from '@testing-library/react-native';
import { MOCK_VAULT_APYS_ONE_YEAR } from '../mockVaultRewards';
import BigNumber from 'bignumber.js';
import GraphTooltip from './GraphTooltip';

jest.mock('react-native-svg-charts', () => ({
...jest.requireActual('react-native-svg-charts'),
AreaChart: jest.fn(),
}));

jest.mock('./GraphTooltip', () => {
const actualComponent = jest.requireActual('./GraphTooltip');
return {
__esModule: true,
default: jest.fn(actualComponent.default),
};
});
import { fireLayoutEvent } from './InteractiveTimespanChart.testUtils';
import { formatChartDate } from './InteractiveTimespanChart.utils';

const props: InteractiveTimespanChartProps<
(typeof MOCK_VAULT_APYS_ONE_YEAR)[number]
> = {
dataPoints: MOCK_VAULT_APYS_ONE_YEAR,
yAccessor: (point) => new BigNumber(point.daily_apy).toNumber(),
defaultTitle: 'Interactive Timespan Chart',
titleAccessor: (point) =>
`${new BigNumber(point.daily_apy).toFixed(
2,
BigNumber.ROUND_DOWN,
)}% ${strings('stake.apr')}`,
defaultSubtitle: 'Displays Mock Data Points',
subtitleAccessor: (point) => formatChartDate(point.timestamp),
};

let renderResult: ReturnType<typeof renderWithProvider>;

describe('InteractiveTimespanChart', () => {
beforeEach(() => {
jest.clearAllMocks();
});

afterAll(() => {
jest.restoreAllMocks();
renderResult = renderWithProvider(<InteractiveTimespanChart {...props} />);
/**
* react-native-svg-charts components listen for onLayout changes before they render any data.
* You need to trigger these event handlers for each component in your tests.
*/
fireLayoutEvent(screen.root, { width: 100, height: 100 });
});

it('render matches snapshot', () => {
const props: InteractiveTimespanChartProps<
(typeof MOCK_VAULT_APYS_ONE_YEAR)[number]
> = {
dataPoints: MOCK_VAULT_APYS_ONE_YEAR,
defaultTitle: 'Interactive Timespan Chart',
defaultSubtitle: 'Displays Mock Data Points',
yAccessor: (point) => new BigNumber(point.daily_apy).toNumber(),
};

const { toJSON } = renderWithProvider(
<InteractiveTimespanChart {...props} />,
);

const { toJSON } = renderResult;
expect(toJSON()).toMatchSnapshot();
});

it('supports customizing color', () => {
const props: InteractiveTimespanChartProps<
it('supports customizing color', async () => {
const customColor = 'red';

const testProps: InteractiveTimespanChartProps<
(typeof MOCK_VAULT_APYS_ONE_YEAR)[number]
> = {
dataPoints: MOCK_VAULT_APYS_ONE_YEAR,
defaultTitle: 'Interactive Timespan Chart',
defaultSubtitle: 'Displays Mock Data Points',
yAccessor: (point) => new BigNumber(point.daily_apy).toNumber(),
};

const { toJSON } = renderWithProvider(
<InteractiveTimespanChart {...props} />,
> = { ...props, graphOptions: { color: customColor } };

const { toJSON, findByText, getByTestId } = renderWithProvider(
<InteractiveTimespanChart {...testProps} />,
);

fireLayoutEvent(screen.root, { width: 100, height: 100 });

const titleText = await findByText(testProps.defaultTitle);
const plotLine = getByTestId('InteractiveChartPlotLine');

const redColorARGB = 4294901760;

expect(titleText?.props?.style?.color).toBe(customColor);
expect(plotLine?.props?.stroke?.payload).toBe(redColorARGB);

expect(toJSON()).toMatchSnapshot();
});

// TODO: Maybe just write a playwrigh test?
it('supports toggling between different timespans', () => {
const props: InteractiveTimespanChartProps<
(typeof MOCK_VAULT_APYS_ONE_YEAR)[number]
> = {
dataPoints: MOCK_VAULT_APYS_ONE_YEAR,
defaultTitle: 'Interactive Timespan Chart',
defaultSubtitle: 'Displays Mock Data Points',
yAccessor: (point) => new BigNumber(point.daily_apy).toNumber(),
};

const { getByText } = renderWithProvider(
<InteractiveTimespanChart {...props} />,
);
const { getByText, getByTestId } = renderResult;

const oneMonthButton = getByText(
strings('stake.interactive_chart.timespan_buttons.1M'),
).parent;

const interactiveTimespanChart = getByTestId('InteractiveTimespanChart');
const areaChartComponent =
interactiveTimespanChart.children[2].children[0].children[0];

// Chart defaults to 7 data points shown (1 week).
expect(areaChartComponent.props.data.length).toEqual(7);

// Display 30 data points (1 month).
fireEvent.press(oneMonthButton);

expect((AreaChart as jest.Mock).mock.calls.length).toBe(2);
expect((AreaChart as jest.Mock).mock.calls[0][0].data.length).toBe(7);
expect((AreaChart as jest.Mock).mock.calls[1][0].data.length).toBe(30);
});
expect(areaChartComponent.props.data.length).toEqual(30);

it.only('displays GraphTooltip when a point is pressed', () => {
const props: InteractiveTimespanChartProps<
(typeof MOCK_VAULT_APYS_ONE_YEAR)[number]
> = {
dataPoints: MOCK_VAULT_APYS_ONE_YEAR,
defaultTitle: 'Interactive Timespan Chart',
defaultSubtitle: 'Displays Mock Data Points',
yAccessor: (point) => new BigNumber(point.daily_apy).toNumber(),
};

const { getByTestId } = renderWithProvider(
<InteractiveTimespanChart {...props} />,
);
// Display 90 data points (3 months).
const threeMonthButton = getByText(
strings('stake.interactive_chart.timespan_buttons.3M'),
).parent;

const plotLine = getByTestId('InteractiveChartPlotLine');
fireEvent.press(threeMonthButton);

fireEvent.press(plotLine);
expect(areaChartComponent.props.data.length).toEqual(90);

expect(GraphTooltip).toHaveBeenCalledWith({ test });
});
// Display 180 data points (6 months).
const sixMonthButton = getByText(
strings('stake.interactive_chart.timespan_buttons.6M'),
).parent;

fireEvent.press(sixMonthButton);

it.todo('displays GraphCursor when a point is pressed');
expect(areaChartComponent.props.data.length).toEqual(180);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { fireEvent } from '@testing-library/react-native';

/**
* Purpose: This file is used to test react-native-svg-charts components
*
* Why this is needed: react-native-svg-charts components listen for onLayout changes before they render any data.
* For these components to render, you need to trigger these event handlers for each component in your tests.
*/

// File Source: https://github.com/JesperLekland/react-native-svg-charts/issues/418
function _findByProp(root: any, prop = '', found: any[] = []) {
if (!root) return found;

if (root.props) {
if (Object.keys(root.props).includes(prop)) found.push(root);
}

if (root.children?.length) {
root.children.forEach((c: any) => _findByProp(c, prop, found));
}

return found;
}

/**
* Find components in the given component hierarchy based
* on the name of one of their props. For example,
* `findByProp(root, 'foo')` will return a list of all
* components with a `foo` prop of any value.
*/
export function findByProp(
/**
* The root of the component tree to search through.
*/
root: any,
/**
* The name of the prop you are using to select components.
*/
prop = '',
) {
return _findByProp(root, prop);
}

/**
* Fire the same layout event for all components that have
* an `onLayout` prop. Generally you won't want to do this because
* the layout dimensions would be different for each component.
* However, this can be useful if you don't have a way to determine
* which components should receive specific dimensions.
*/
export function fireLayoutEvent(
/**
* The root node to search for components with `onLayout` props.
*/
root: any,
/**
* The event options inside of `event.nativeElement.layout`
*/
options = {
width: 0,
height: 0,
},
) {
findByProp(root, 'onLayout').forEach((n) =>
fireEvent(n, 'layout', { nativeEvent: { layout: options } }),
);
}
Loading

0 comments on commit 4d71a35

Please sign in to comment.