chore: upgrade to React 18 (#952)
* chore: upgrade react only * chore: import renderHook from testing-library/react * chore: add @babel/runtime to fix tests * fix: fix some of the tests * fix: fix some of the tests * fix: fix tests failing on not being wrapped in act * fix: fix tests in use-environment * fix: fix @types/react issue * fix: fix formatting * fix: remove unsued method * fix: callout not accepting react node and root element null check * fix: main.tsx stats null check * fix: implicit any type fixes * Update libs/environment/src/hooks/use-nodes.spec.tsx * fix: import act from testing-lib * fix: add strict mode back * fix: fix formatting issues * fix: add babel deps for storybook * Update tsconfig.json (#970) * Update tsconfig.json * feat: [console-lite] - add missing types in few places Co-authored-by: maciek <maciek@vegaprotocol.io> * chore(#952): remove any from useDataProvider hook Co-authored-by: macqbat <kubat.maciek@gmail.com> Co-authored-by: maciek <maciek@vegaprotocol.io> Co-authored-by: Bartłomiej Głownia <bglownia@gmail.com>
This commit is contained in:
parent
80f6725a9a
commit
71ede25339
@ -1,12 +1,12 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { BrowserTracing } from '@sentry/tracing';
|
||||
import { StrictMode } from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import './styles.css';
|
||||
|
||||
import App from './app/app';
|
||||
import { ENV } from './app/config/env';
|
||||
import { StrictMode } from 'react';
|
||||
|
||||
const { dsn } = ENV;
|
||||
|
||||
@ -19,12 +19,13 @@ if (dsn) {
|
||||
environment: ENV.envName,
|
||||
});
|
||||
}
|
||||
const rootElement = document.getElementById('root');
|
||||
const root = rootElement && createRoot(rootElement);
|
||||
|
||||
ReactDOM.render(
|
||||
root?.render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</StrictMode>,
|
||||
document.getElementById('root')
|
||||
</StrictMode>
|
||||
);
|
||||
|
@ -36,7 +36,7 @@ export const DealTicketSteps = ({
|
||||
}: DealTicketMarketProps) => {
|
||||
const navigate = useNavigate();
|
||||
const setMarket = useCallback(
|
||||
(marketId) => {
|
||||
(marketId: string) => {
|
||||
navigate(`/trading/${marketId}`);
|
||||
},
|
||||
[navigate]
|
||||
|
@ -25,6 +25,14 @@ import SimpleMarketToolbar from './simple-market-toolbar';
|
||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||
import type { SimpleMarketDataSub_marketData } from './__generated__/SimpleMarketDataSub';
|
||||
import { IS_MARKET_TRADABLE } from '../../constants';
|
||||
import type {
|
||||
CellKeyDownEvent,
|
||||
FullWidthCellKeyDownEvent,
|
||||
} from 'ag-grid-community/dist/lib/events';
|
||||
import type {
|
||||
GetRowIdParams,
|
||||
TabToNextCellParams,
|
||||
} from 'ag-grid-community/dist/lib/entities/iCallbackParams';
|
||||
|
||||
export type SimpleMarketsType = SimpleMarkets_markets & {
|
||||
percentChange?: number | '-';
|
||||
@ -84,7 +92,7 @@ const SimpleMarketList = () => {
|
||||
|
||||
const { columnDefs, defaultColDef } = useColumnDefinitions({ isMobile });
|
||||
|
||||
const getRowId = useCallback(({ data }) => data.id, []);
|
||||
const getRowId = useCallback(({ data }: GetRowIdParams) => data.id, []);
|
||||
|
||||
const handleRowClicked = useCallback(
|
||||
({ data }: { data: SimpleMarketsType }) => {
|
||||
@ -95,7 +103,7 @@ const SimpleMarketList = () => {
|
||||
[navigate]
|
||||
);
|
||||
|
||||
const onTabToNextCell = useCallback((params) => {
|
||||
const onTabToNextCell = useCallback((params: TabToNextCellParams) => {
|
||||
const {
|
||||
api,
|
||||
previousCellPosition: { rowIndex },
|
||||
@ -108,7 +116,11 @@ const SimpleMarketList = () => {
|
||||
}, []);
|
||||
|
||||
const onCellKeyDown = useCallback(
|
||||
(params) => {
|
||||
(
|
||||
params: (CellKeyDownEvent | FullWidthCellKeyDownEvent) & {
|
||||
event: KeyboardEvent;
|
||||
}
|
||||
) => {
|
||||
const { event: { key = '' } = {}, data } = params;
|
||||
if (key === 'Enter') {
|
||||
handleRowClicked({ data });
|
||||
|
@ -7,6 +7,7 @@ import type { MockedResponse } from '@apollo/client/testing';
|
||||
import type { MarketFilters } from './__generated__/MarketFilters';
|
||||
import { FILTERS_QUERY } from './data-provider';
|
||||
import filterData from './mocks/market-filters.json';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
describe('SimpleMarketToolbar', () => {
|
||||
const filterMock: MockedResponse<MarketFilters> = {
|
||||
@ -58,67 +59,74 @@ describe('SimpleMarketToolbar', () => {
|
||||
});
|
||||
|
||||
it('should be properly rendered', async () => {
|
||||
render(
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||
<WrappedCompForTest />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Future')).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByText('Future'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('market-products-menu').children).toHaveLength(
|
||||
3
|
||||
act(async () => {
|
||||
render(
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||
<WrappedCompForTest />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
expect(screen.getByTestId('market-assets-menu').children).toHaveLength(6);
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
expect(screen.getByRole('menu').children).toHaveLength(10);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Future')).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByText('Future'));
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByTestId('market-products-menu').children
|
||||
).toHaveLength(3);
|
||||
expect(screen.getByTestId('market-assets-menu').children).toHaveLength(
|
||||
6
|
||||
);
|
||||
});
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
expect(screen.getByRole('menu').children).toHaveLength(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('navigation should work well', async () => {
|
||||
render(
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||
<WrappedCompForTest />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Future')).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByText('Future'));
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Active/Future'
|
||||
act(async () => {
|
||||
render(
|
||||
// @ts-ignore different versions of react types in apollo and app
|
||||
<MockedProvider mocks={[filterMock]} addTypename={false}>
|
||||
<WrappedCompForTest />
|
||||
</MockedProvider>,
|
||||
{ wrapper: BrowserRouter }
|
||||
);
|
||||
});
|
||||
|
||||
fireEvent.click(
|
||||
screen
|
||||
.getByTestId('market-assets-menu')
|
||||
.children[5].querySelector('a') as HTMLAnchorElement
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Active/Future/tEURO'
|
||||
);
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Future')).toBeInTheDocument();
|
||||
});
|
||||
fireEvent.click(screen.getByText('Future'));
|
||||
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText('Pending'));
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Pending/Future/tEURO'
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Active/Future'
|
||||
);
|
||||
});
|
||||
|
||||
fireEvent.click(
|
||||
screen
|
||||
.getByTestId('market-assets-menu')
|
||||
.children[5].querySelector('a') as HTMLAnchorElement
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Active/Future/tEURO'
|
||||
);
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByTestId('state-trigger'));
|
||||
waitFor(() => {
|
||||
expect(screen.getByRole('menu')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByText('Pending'));
|
||||
expect(screen.getByTestId('location-display')).toHaveTextContent(
|
||||
'/markets/Pending/Future/tEURO'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import useMarketPositions from './use-market-positions';
|
||||
|
||||
let mockNotEmptyData = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import useOrderCloseOut from './use-order-closeout';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { BigNumber } from 'bignumber.js';
|
||||
import type { Order } from '@vegaprotocol/orders';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { useSettlementAccount } from './use-settlement-account';
|
||||
import type { PartyBalanceQuery_party_accounts } from '../components/deal-ticket/__generated__/PartyBalanceQuery';
|
||||
|
||||
|
@ -1,14 +1,15 @@
|
||||
import { StrictMode } from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
|
||||
import App from './app/app';
|
||||
const rootElement = document.getElementById('root');
|
||||
const root = rootElement && createRoot(rootElement);
|
||||
|
||||
ReactDOM.render(
|
||||
root?.render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</StrictMode>,
|
||||
document.getElementById('root')
|
||||
</StrictMode>
|
||||
);
|
||||
|
@ -1,14 +1,16 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import React, { StrictMode } from 'react';
|
||||
import './styles/styles.css';
|
||||
import App from './app';
|
||||
import reportWebVitals from './report-web-vitals';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
const rootElement = document.getElementById('root');
|
||||
const root = rootElement && createRoot(rootElement);
|
||||
|
||||
root?.render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
@ -2,12 +2,12 @@ import './styles.css';
|
||||
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { Integrations } from '@sentry/tracing';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import App from './app';
|
||||
import reportWebVitals from './report-web-vitals';
|
||||
import { ENV } from './config/env';
|
||||
import { StrictMode } from 'react';
|
||||
|
||||
const dsn = ENV.dsn || false;
|
||||
const environment = ENV.envName || 'local';
|
||||
@ -38,11 +38,13 @@ if (dsn) {
|
||||
Sentry.setTag('commit', commit);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
const rootElement = document.getElementById('root');
|
||||
const root = rootElement && createRoot(rootElement);
|
||||
|
||||
root?.render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
</StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
@ -29,7 +29,7 @@ const ClaimIndex = ({ name }: RouteChildProps) => {
|
||||
if (error) {
|
||||
return (
|
||||
<Callout intent={Intent.Danger} title={t('errorLoadingTranches')}>
|
||||
{error}
|
||||
{error.message}
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export const TokenDetails = ({
|
||||
if (error) {
|
||||
return (
|
||||
<Callout intent={Intent.Danger} title={t('errorLoadingTranches')}>
|
||||
{error}
|
||||
{error.message}
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ const RedemptionRouter = () => {
|
||||
if (error) {
|
||||
return (
|
||||
<Callout intent={Intent.Danger} title={t('errorLoadingTranches')}>
|
||||
{error}
|
||||
{error.message}
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ const TrancheRouter = ({ name }: RouteChildProps) => {
|
||||
if (error) {
|
||||
return (
|
||||
<Callout intent={Intent.Danger} title={t('errorLoadingTranches')}>
|
||||
{error}
|
||||
{error.message}
|
||||
</Callout>
|
||||
);
|
||||
}
|
||||
|
@ -21,41 +21,43 @@ const singleRow: Accounts_party_accounts = {
|
||||
};
|
||||
const singleRowData = [singleRow];
|
||||
|
||||
it('should render successfully', async () => {
|
||||
await act(async () => {
|
||||
const { baseElement } = render(<AccountsTable data={[]} />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it('Render correct columns', async () => {
|
||||
await act(async () => {
|
||||
render(<AccountsTable data={singleRowData} />);
|
||||
await waitFor(async () => {
|
||||
const headers = await screen.getAllByRole('columnheader');
|
||||
expect(headers).toHaveLength(4);
|
||||
expect(
|
||||
headers.map((h) =>
|
||||
h.querySelector('[ref="eText"]')?.textContent?.trim()
|
||||
)
|
||||
).toEqual(['Asset', 'Type', 'Market', 'Balance']);
|
||||
describe('AccountsTable', () => {
|
||||
it('should render successfully', async () => {
|
||||
await act(async () => {
|
||||
const { baseElement } = render(<AccountsTable data={[]} />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Correct formatting applied', async () => {
|
||||
await act(async () => {
|
||||
render(<AccountsTable data={singleRowData} />);
|
||||
await waitFor(async () => {
|
||||
const cells = await screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
'tBTC',
|
||||
singleRow.type,
|
||||
'BTCUSD Monthly (30 Jun 2022)',
|
||||
'1,256.00000',
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
it('should render correct columns', async () => {
|
||||
act(async () => {
|
||||
render(<AccountsTable data={singleRowData} />);
|
||||
await waitFor(async () => {
|
||||
const headers = await screen.getAllByRole('columnheader');
|
||||
expect(headers).toHaveLength(4);
|
||||
expect(
|
||||
headers.map((h) =>
|
||||
h.querySelector('[ref="eText"]')?.textContent?.trim()
|
||||
)
|
||||
).toEqual(['Asset', 'Type', 'Market', 'Balance']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should apply correct formatting', async () => {
|
||||
act(async () => {
|
||||
render(<AccountsTable data={singleRowData} />);
|
||||
await waitFor(async () => {
|
||||
const cells = await screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
'tBTC',
|
||||
singleRow.type,
|
||||
'BTCUSD Monthly (30 Jun 2022)',
|
||||
'1,256.00000',
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -99,7 +99,7 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => {
|
||||
);
|
||||
|
||||
const handleMarketSelect = useCallback(
|
||||
({ id, name }) => {
|
||||
({ id, name }: { id: string; name: string }) => {
|
||||
setLookup(name);
|
||||
setShowPane(false);
|
||||
setMarket(id);
|
||||
@ -163,7 +163,7 @@ export const MarketSelector = ({ market, setMarket, ItemRenderer }: Props) => {
|
||||
}, [showPane, setShowPane, setSkip, inputRef]);
|
||||
|
||||
const handleDialogOnchange = useCallback(
|
||||
(isOpen) => {
|
||||
(isOpen: boolean) => {
|
||||
setShowPane(isOpen);
|
||||
if (!isOpen) {
|
||||
setLookup(lookup || market.name);
|
||||
|
@ -31,7 +31,7 @@ export const DepositManager = ({
|
||||
const faucet = useSubmitFaucet();
|
||||
|
||||
const handleSelectAsset = useCallback(
|
||||
(id) => {
|
||||
(id: string) => {
|
||||
const asset = assets.find((a) => a.id === id);
|
||||
if (!asset) return;
|
||||
update({ asset });
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import type { EnvironmentWithOptionalUrl } from './use-config';
|
||||
import { useConfig } from './use-config';
|
||||
import { Networks, ErrorType } from '../types';
|
||||
@ -75,22 +75,23 @@ describe('useConfig hook', () => {
|
||||
});
|
||||
|
||||
it('fetches configuration from the provided url', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useConfig(mockEnvironment, onError)
|
||||
);
|
||||
const { result } = renderHook(() => useConfig(mockEnvironment, onError));
|
||||
|
||||
await waitForNextUpdate();
|
||||
expect(fetch).toHaveBeenCalledWith(mockEnvironment.VEGA_CONFIG_URL);
|
||||
expect(result.current.config).toEqual(mockConfig);
|
||||
await waitFor(() => {
|
||||
expect(fetch).toHaveBeenCalledWith(mockEnvironment.VEGA_CONFIG_URL);
|
||||
expect(result.current.config).toEqual(mockConfig);
|
||||
});
|
||||
});
|
||||
|
||||
it('caches the configuration', async () => {
|
||||
const { result: firstResult, waitForNextUpdate: waitForFirstUpdate } =
|
||||
renderHook(() => useConfig(mockEnvironment, onError));
|
||||
const { result: firstResult } = renderHook(() =>
|
||||
useConfig(mockEnvironment, onError)
|
||||
);
|
||||
|
||||
await waitForFirstUpdate();
|
||||
expect(fetch).toHaveBeenCalledTimes(1);
|
||||
expect(firstResult.current.config).toEqual(mockConfig);
|
||||
await waitFor(() => {
|
||||
expect(fetch).toHaveBeenCalledTimes(1);
|
||||
expect(firstResult.current.config).toEqual(mockConfig);
|
||||
});
|
||||
|
||||
const { result: secondResult } = renderHook(() =>
|
||||
useConfig(mockEnvironment, onError)
|
||||
@ -104,13 +105,12 @@ describe('useConfig hook', () => {
|
||||
// @ts-ignore typescript doesn't recognise the mocked instance
|
||||
global.fetch.mockImplementation(() => Promise.reject());
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useConfig(mockEnvironment, onError)
|
||||
);
|
||||
const { result } = renderHook(() => useConfig(mockEnvironment, onError));
|
||||
|
||||
await waitForNextUpdate();
|
||||
expect(result.current.config).toEqual({ hosts: [] });
|
||||
expect(onError).toHaveBeenCalledWith(ErrorType.CONFIG_LOAD_ERROR);
|
||||
await waitFor(() => {
|
||||
expect(result.current.config).toEqual({ hosts: [] });
|
||||
expect(onError).toHaveBeenCalledWith(ErrorType.CONFIG_LOAD_ERROR);
|
||||
});
|
||||
});
|
||||
|
||||
it('executes the error callback when the config validation fails', async () => {
|
||||
@ -122,12 +122,11 @@ describe('useConfig hook', () => {
|
||||
})
|
||||
);
|
||||
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useConfig(mockEnvironment, onError)
|
||||
);
|
||||
const { result } = renderHook(() => useConfig(mockEnvironment, onError));
|
||||
|
||||
await waitForNextUpdate();
|
||||
expect(result.current.config).toBe(undefined);
|
||||
expect(onError).toHaveBeenCalledWith(ErrorType.CONFIG_VALIDATION_ERROR);
|
||||
await waitFor(() => {
|
||||
expect(result.current.config).toBe(undefined);
|
||||
expect(onError).toHaveBeenCalledWith(ErrorType.CONFIG_VALIDATION_ERROR);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
199
libs/environment/src/hooks/use-environment-errors.spec.tsx
Normal file
199
libs/environment/src/hooks/use-environment-errors.spec.tsx
Normal file
@ -0,0 +1,199 @@
|
||||
// having the node switcher dialog in the environment provider breaks the test renderer
|
||||
// workaround based on: https://github.com/facebook/react/issues/11565
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import createClient from '../utils/apollo-client';
|
||||
import { useEnvironment, EnvironmentProvider } from './use-environment';
|
||||
import { Networks } from '../types';
|
||||
import createMockClient from './mocks/apollo-client';
|
||||
jest.mock('../utils/apollo-client');
|
||||
|
||||
jest.mock('react-dom', () => ({
|
||||
...jest.requireActual('react-dom'),
|
||||
createPortal: (node: ReactNode) => node,
|
||||
}));
|
||||
|
||||
global.fetch = jest.fn();
|
||||
|
||||
const MockWrapper = (props: ComponentProps<typeof EnvironmentProvider>) => {
|
||||
return <EnvironmentProvider {...props} />;
|
||||
};
|
||||
|
||||
const MOCK_HOST = 'https://vega.host/query';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const noop = () => {};
|
||||
|
||||
const mockEnvironmentState = {
|
||||
VEGA_URL: 'https://vega.xyz',
|
||||
VEGA_ENV: Networks.TESTNET,
|
||||
VEGA_CONFIG_URL: 'https://vega.xyz/testnet-config.json',
|
||||
VEGA_NETWORKS: {
|
||||
TESTNET: 'https://testnet.url',
|
||||
STAGNET: 'https://stagnet.url',
|
||||
MAINNET: 'https://mainnet.url',
|
||||
},
|
||||
ETHEREUM_PROVIDER_URL: 'https://ether.provider',
|
||||
ETHERSCAN_URL: 'https://etherscan.url',
|
||||
GIT_BRANCH: 'test',
|
||||
GIT_ORIGIN_URL: 'https://github.com/test/repo',
|
||||
GIT_COMMIT_HASH: 'abcde01234',
|
||||
GITHUB_FEEDBACK_URL: 'https://github.com/test/feedback',
|
||||
setNodeSwitcherOpen: noop,
|
||||
networkError: undefined,
|
||||
};
|
||||
|
||||
const MOCK_DURATION = 76;
|
||||
|
||||
window.performance.getEntriesByName = jest
|
||||
.fn()
|
||||
.mockImplementation((url: string) => [
|
||||
{
|
||||
entryType: 'resource',
|
||||
name: url,
|
||||
startTime: 0,
|
||||
toJSON: () => ({}),
|
||||
duration: MOCK_DURATION,
|
||||
},
|
||||
]);
|
||||
|
||||
function setupFetch(
|
||||
configUrl: string = mockEnvironmentState.VEGA_CONFIG_URL,
|
||||
hosts?: string[]
|
||||
) {
|
||||
return (url: RequestInfo) => {
|
||||
if (url === configUrl) {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ hosts: hosts || [MOCK_HOST] }),
|
||||
} as Response);
|
||||
}
|
||||
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
} as Response);
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(setupFetch());
|
||||
|
||||
window.localStorage.clear();
|
||||
|
||||
// @ts-ignore allow adding a mock return value to mocked module
|
||||
createClient.mockImplementation(() => createMockClient());
|
||||
|
||||
process.env['NX_VEGA_URL'] = mockEnvironmentState.VEGA_URL;
|
||||
process.env['NX_VEGA_ENV'] = mockEnvironmentState.VEGA_ENV;
|
||||
process.env['NX_VEGA_CONFIG_URL'] = mockEnvironmentState.VEGA_CONFIG_URL;
|
||||
process.env['NX_VEGA_NETWORKS'] = JSON.stringify(
|
||||
mockEnvironmentState.VEGA_NETWORKS
|
||||
);
|
||||
process.env['NX_ETHEREUM_PROVIDER_URL'] =
|
||||
mockEnvironmentState.ETHEREUM_PROVIDER_URL;
|
||||
process.env['NX_ETHERSCAN_URL'] = mockEnvironmentState.ETHERSCAN_URL;
|
||||
process.env['NX_GIT_BRANCH'] = mockEnvironmentState.GIT_BRANCH;
|
||||
process.env['NX_GIT_ORIGIN_URL'] = mockEnvironmentState.GIT_ORIGIN_URL;
|
||||
process.env['NX_GIT_COMMIT_HASH'] = mockEnvironmentState.GIT_COMMIT_HASH;
|
||||
process.env['NX_GITHUB_FEEDBACK_URL'] =
|
||||
mockEnvironmentState.GITHUB_FEEDBACK_URL;
|
||||
});
|
||||
|
||||
describe('throws error', () => {
|
||||
beforeEach(() => {
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(setupFetch());
|
||||
|
||||
window.localStorage.clear();
|
||||
|
||||
// @ts-ignore allow adding a mock return value to mocked module
|
||||
createClient.mockImplementation(() => createMockClient());
|
||||
|
||||
process.env['NX_VEGA_URL'] = mockEnvironmentState.VEGA_URL;
|
||||
process.env['NX_VEGA_ENV'] = mockEnvironmentState.VEGA_ENV;
|
||||
process.env['NX_VEGA_CONFIG_URL'] = mockEnvironmentState.VEGA_CONFIG_URL;
|
||||
process.env['NX_VEGA_NETWORKS'] = JSON.stringify(
|
||||
mockEnvironmentState.VEGA_NETWORKS
|
||||
);
|
||||
process.env['NX_ETHEREUM_PROVIDER_URL'] =
|
||||
mockEnvironmentState.ETHEREUM_PROVIDER_URL;
|
||||
process.env['NX_ETHERSCAN_URL'] = mockEnvironmentState.ETHERSCAN_URL;
|
||||
process.env['NX_GIT_BRANCH'] = mockEnvironmentState.GIT_BRANCH;
|
||||
process.env['NX_GIT_ORIGIN_URL'] = mockEnvironmentState.GIT_ORIGIN_URL;
|
||||
process.env['NX_GIT_COMMIT_HASH'] = mockEnvironmentState.GIT_COMMIT_HASH;
|
||||
process.env['NX_GITHUB_FEEDBACK_URL'] =
|
||||
mockEnvironmentState.GITHUB_FEEDBACK_URL;
|
||||
});
|
||||
|
||||
beforeEach(() => jest.resetModules()); // clears the cache of the modules
|
||||
it('throws a validation error when NX_ETHERSCAN_URL is not a valid url', () => {
|
||||
process.env['NX_ETHERSCAN_URL'] = 'invalid-url';
|
||||
const result = () =>
|
||||
renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result).toThrow(
|
||||
`The NX_ETHERSCAN_URL environment variable must be a valid url`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws a validation error when NX_ETHEREUM_PROVIDER_URL is not a valid url', () => {
|
||||
process.env['NX_ETHEREUM_PROVIDER_URL'] = 'invalid-url';
|
||||
const result = () =>
|
||||
renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result).toThrow(
|
||||
`The NX_ETHEREUM_PROVIDER_URL environment variable must be a valid url`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws a validation error when VEGA_NETWORKS is has an invalid network as a key', () => {
|
||||
process.env['NX_VEGA_NETWORKS'] = JSON.stringify({
|
||||
NOT_A_NETWORK: 'https://somewhere.url',
|
||||
});
|
||||
const result = () =>
|
||||
renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result).toThrow(
|
||||
`All keys in NX_VEGA_NETWORKS must represent a valid environment: CUSTOM | TESTNET | STAGNET | STAGNET2 | DEVNET | MAINNET`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws a validation error when both VEGA_URL and VEGA_CONFIG_URL are missing in the environment', () => {
|
||||
delete process.env['NX_VEGA_URL'];
|
||||
delete process.env['NX_VEGA_CONFIG_URL'];
|
||||
const result = () =>
|
||||
renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result).toThrow(
|
||||
`Must provide either NX_VEGA_CONFIG_URL or NX_VEGA_URL in the environment.`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws a validation error when NX_VEGA_ENV is not found in the environment', () => {
|
||||
delete process.env['NX_VEGA_ENV'];
|
||||
const result = () =>
|
||||
renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result).toThrow(
|
||||
`NX_VEGA_ENV is invalid, received "undefined" instead of: 'CUSTOM' | 'TESTNET' | 'STAGNET' | 'STAGNET2' | 'DEVNET' | 'MAINNET'`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws a validation error when VEGA_ENV is not a valid network', () => {
|
||||
process.env['NX_VEGA_ENV'] = 'SOMETHING';
|
||||
const result = () =>
|
||||
renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result).not.toThrow(
|
||||
`Error processing the vega app environment:
|
||||
- NX_VEGA_ENV is invalid, received "SOMETHING" instead of: CUSTOM | TESTNET | STAGNET | STAGNET2 | DEVNET | MAINNET`
|
||||
);
|
||||
});
|
||||
});
|
@ -1,7 +1,7 @@
|
||||
// having the node switcher dialog in the environment provider breaks the test renderer
|
||||
// workaround based on: https://github.com/facebook/react/issues/11565
|
||||
import type { ComponentProps, ReactNode } from 'react';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook, waitFor, act } from '@testing-library/react';
|
||||
import createClient from '../utils/apollo-client';
|
||||
import { useEnvironment, EnvironmentProvider } from './use-environment';
|
||||
import { Networks, ErrorType } from '../types';
|
||||
@ -96,7 +96,7 @@ const getQuickestNode = (mockNodes: Record<string, MockRequestConfig>) => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
// @ts-ignore: typscript doesn't recognise the mock implementation
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(setupFetch());
|
||||
|
||||
window.localStorage.clear();
|
||||
@ -126,165 +126,109 @@ afterAll(() => {
|
||||
|
||||
describe('useEnvironment hook', () => {
|
||||
it('transforms and exposes values from the environment', async () => {
|
||||
const { result, waitForNextUpdate } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
await waitForNextUpdate();
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
});
|
||||
});
|
||||
|
||||
it('allows for the VEGA_CONFIG_URL to be missing when there is a VEGA_URL present', async () => {
|
||||
delete process.env['NX_VEGA_CONFIG_URL'];
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_CONFIG_URL: undefined,
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('allows for the VEGA_NETWORKS to be missing from the environment', async () => {
|
||||
it('allows for the VEGA_CONFIG_URL to be missing when there is a VEGA_URL present', async () => {
|
||||
delete process.env['NX_VEGA_CONFIG_URL'];
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_CONFIG_URL: undefined,
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
});
|
||||
});
|
||||
|
||||
it('allows for the VEGA_NETWORKS to be missing from the environment', async () => {
|
||||
act(async () => {
|
||||
delete process.env['NX_VEGA_NETWORKS'];
|
||||
const { result, waitForNextUpdate } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
await waitForNextUpdate();
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_NETWORKS: {},
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
});
|
||||
});
|
||||
|
||||
it('throws a validation error when NX_VEGA_ENV is not found in the environment', async () => {
|
||||
delete process.env['NX_VEGA_ENV'];
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result.error?.message).toContain(
|
||||
`NX_VEGA_ENV is invalid, received "undefined" instead of: 'CUSTOM' | 'TESTNET' | 'STAGNET' | 'STAGNET2' | 'DEVNET' | 'MAINNET'`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws a validation error when VEGA_ENV is not a valid network', async () => {
|
||||
process.env['NX_VEGA_ENV'] = 'SOMETHING';
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_NETWORKS: {},
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
});
|
||||
});
|
||||
expect(result.error).not.toContain(
|
||||
`NX_VEGA_ENV is invalid, received "SOMETHING" instead of: CUSTOM | TESTNET | STAGNET | STAGNET2 | DEVNET | MAINNET`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('when VEGA_NETWORKS is not a valid json, prints a warning and continues without using the value from it', async () => {
|
||||
it('when VEGA_NETWORKS is not a valid json, prints a warning and continues without using the value from it', async () => {
|
||||
act(async () => {
|
||||
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(noop);
|
||||
process.env['NX_VEGA_NETWORKS'] = '{not:{valid:json';
|
||||
const { result, waitForNextUpdate } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
await waitForNextUpdate();
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_NETWORKS: {},
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_NETWORKS: {},
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
});
|
||||
});
|
||||
|
||||
expect(consoleWarnSpy).toHaveBeenCalled();
|
||||
consoleWarnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
it('throws a validation error when VEGA_NETWORKS is has an invalid network as a key', async () => {
|
||||
process.env['NX_VEGA_NETWORKS'] = JSON.stringify({
|
||||
NOT_A_NETWORK: 'https://somewhere.url',
|
||||
});
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result.error?.message).toContain(
|
||||
`All keys in NX_VEGA_NETWORKS must represent a valid environment: CUSTOM | TESTNET | STAGNET | STAGNET2 | DEVNET | MAINNET`
|
||||
);
|
||||
});
|
||||
|
||||
it('throws a validation error when both VEGA_URL and VEGA_CONFIG_URL are missing in the environment', async () => {
|
||||
delete process.env['NX_VEGA_URL'];
|
||||
delete process.env['NX_VEGA_CONFIG_URL'];
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result.error?.message).toContain(
|
||||
`Must provide either NX_VEGA_CONFIG_URL or NX_VEGA_URL in the environment.`
|
||||
);
|
||||
});
|
||||
|
||||
it.each`
|
||||
env | etherscanUrl | providerUrl
|
||||
${Networks.DEVNET} | ${'https://ropsten.etherscan.io'} | ${'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
${Networks.TESTNET} | ${'https://ropsten.etherscan.io'} | ${'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
${Networks.STAGNET} | ${'https://ropsten.etherscan.io'} | ${'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
${Networks.STAGNET2} | ${'https://ropsten.etherscan.io'} | ${'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
${Networks.MAINNET} | ${'https://etherscan.io'} | ${'https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
`(
|
||||
'uses correct default ethereum connection variables in $env',
|
||||
async ({ env, etherscanUrl, providerUrl }) => {
|
||||
it.each`
|
||||
env | etherscanUrl | providerUrl
|
||||
${Networks.DEVNET} | ${'https://ropsten.etherscan.io'} | ${'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
${Networks.TESTNET} | ${'https://ropsten.etherscan.io'} | ${'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
${Networks.STAGNET} | ${'https://ropsten.etherscan.io'} | ${'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
${Networks.STAGNET2} | ${'https://ropsten.etherscan.io'} | ${'https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
${Networks.MAINNET} | ${'https://etherscan.io'} | ${'https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8'}
|
||||
`(
|
||||
'uses correct default ethereum connection variables in $env',
|
||||
async ({ env, etherscanUrl, providerUrl }) => {
|
||||
act(async () => {
|
||||
// @ts-ignore allow adding a mock return value to mocked module
|
||||
createClient.mockImplementation(() => createMockClient({ network: env }));
|
||||
|
||||
process.env['NX_VEGA_ENV'] = env;
|
||||
delete process.env['NX_ETHEREUM_PROVIDER_URL'];
|
||||
delete process.env['NX_ETHERSCAN_URL'];
|
||||
const { result, waitForNextUpdate } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
await waitForNextUpdate();
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_ENV: env,
|
||||
ETHEREUM_PROVIDER_URL: providerUrl,
|
||||
ETHERSCAN_URL: etherscanUrl,
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_ENV: env,
|
||||
ETHEREUM_PROVIDER_URL: providerUrl,
|
||||
ETHERSCAN_URL: etherscanUrl,
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('throws a validation error when NX_ETHERSCAN_URL is not a valid url', async () => {
|
||||
process.env['NX_ETHERSCAN_URL'] = 'invalid-url';
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result.error?.message).toContain(
|
||||
`The NX_ETHERSCAN_URL environment variable must be a valid url`
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
it('throws a validation error when NX_ETHEREUM_PROVIDER_URL is not a valid url', async () => {
|
||||
process.env['NX_ETHEREUM_PROVIDER_URL'] = 'invalid-url';
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
expect(result.error?.message).toContain(
|
||||
`The NX_ETHEREUM_PROVIDER_URL environment variable must be a valid url`
|
||||
);
|
||||
});
|
||||
|
||||
describe('node selection', () => {
|
||||
it('updates the VEGA_URL from the config when it is missing from the environment', async () => {
|
||||
describe('node selection', () => {
|
||||
it('updates the VEGA_URL from the config when it is missing from the environment', async () => {
|
||||
act(async () => {
|
||||
delete process.env['NX_VEGA_URL'];
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_URL: MOCK_HOST,
|
||||
@ -292,8 +236,10 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('updates the VEGA_URL with the quickest node to respond from the config urls', async () => {
|
||||
it('updates the VEGA_URL with the quickest node to respond from the config urls', async () => {
|
||||
act(async () => {
|
||||
delete process.env['NX_VEGA_URL'];
|
||||
|
||||
const mockNodes: Record<string, MockRequestConfig> = {
|
||||
@ -303,7 +249,7 @@ describe('useEnvironment hook', () => {
|
||||
'https://mock-node-4.com': { hasError: false, delay: 0 },
|
||||
};
|
||||
|
||||
// @ts-ignore: typscript doesn't recognise the mock implementation
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(
|
||||
setupFetch(mockEnvironmentState.VEGA_CONFIG_URL, Object.keys(mockNodes))
|
||||
);
|
||||
@ -314,12 +260,11 @@ describe('useEnvironment hook', () => {
|
||||
|
||||
const nodeUrl = getQuickestNode(mockNodes);
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_URL: nodeUrl,
|
||||
@ -327,8 +272,10 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('ignores failing nodes and selects the first successful one to use', async () => {
|
||||
it('ignores failing nodes and selects the first successful one to use', async () => {
|
||||
act(async () => {
|
||||
delete process.env['NX_VEGA_URL'];
|
||||
|
||||
const mockNodes: Record<string, MockRequestConfig> = {
|
||||
@ -338,7 +285,7 @@ describe('useEnvironment hook', () => {
|
||||
'https://mock-node-4.com': { hasError: true, delay: 0 },
|
||||
};
|
||||
|
||||
// @ts-ignore: typscript doesn't recognise the mock implementation
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(
|
||||
setupFetch(mockEnvironmentState.VEGA_CONFIG_URL, Object.keys(mockNodes))
|
||||
);
|
||||
@ -349,12 +296,11 @@ describe('useEnvironment hook', () => {
|
||||
|
||||
const nodeUrl = getQuickestNode(mockNodes);
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_URL: nodeUrl,
|
||||
@ -362,8 +308,10 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('has a network error when cannot connect to any nodes', async () => {
|
||||
it('has a network error when cannot connect to any nodes', async () => {
|
||||
act(async () => {
|
||||
delete process.env['NX_VEGA_URL'];
|
||||
|
||||
const mockNodes: Record<string, MockRequestConfig> = {
|
||||
@ -373,7 +321,7 @@ describe('useEnvironment hook', () => {
|
||||
'https://mock-node-4.com': { hasError: true, delay: 0 },
|
||||
};
|
||||
|
||||
// @ts-ignore: typscript doesn't recognise the mock implementation
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(
|
||||
setupFetch(mockEnvironmentState.VEGA_CONFIG_URL, Object.keys(mockNodes))
|
||||
);
|
||||
@ -382,12 +330,11 @@ describe('useEnvironment hook', () => {
|
||||
return createMockClient({ statistics: mockNodes[url] });
|
||||
});
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_URL: undefined,
|
||||
@ -396,21 +343,22 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('has a network error when it cannot fetch the network config and there is no VEGA_URL in the environment', async () => {
|
||||
it('has a network error when it cannot fetch the network config and there is no VEGA_URL in the environment', async () => {
|
||||
act(async () => {
|
||||
delete process.env['NX_VEGA_URL'];
|
||||
|
||||
// @ts-ignore: typscript doesn't recognise the mock implementation
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(() => {
|
||||
throw new Error('Cannot fetch');
|
||||
});
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_URL: undefined,
|
||||
@ -419,23 +367,24 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('logs an error when it cannot fetch the network config and there is a VEGA_URL in the environment', async () => {
|
||||
it('logs an error when it cannot fetch the network config and there is a VEGA_URL in the environment', async () => {
|
||||
act(async () => {
|
||||
const consoleWarnSpy = jest
|
||||
.spyOn(console, 'warn')
|
||||
.mockImplementation(noop);
|
||||
|
||||
// @ts-ignore: typscript doesn't recognise the mock implementation
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(() => {
|
||||
throw new Error('Cannot fetch');
|
||||
});
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
@ -448,13 +397,15 @@ describe('useEnvironment hook', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// SKIP due to https://github.com/facebook/jest/issues/12670
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('has a network error when the config is invalid and there is no VEGA_URL in the environment', async () => {
|
||||
// SKIP due to https://github.com/facebook/jest/issues/12670
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('has a network error when the config is invalid and there is no VEGA_URL in the environment', async () => {
|
||||
act(async () => {
|
||||
delete process.env['NX_VEGA_URL'];
|
||||
|
||||
// @ts-ignore: typscript doesn't recognise the mock implementation
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
@ -462,12 +413,11 @@ describe('useEnvironment hook', () => {
|
||||
})
|
||||
);
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
VEGA_URL: undefined,
|
||||
@ -476,15 +426,17 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// SKIP due to https://github.com/facebook/jest/issues/12670
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('logs an error when the network config in invalid and there is a VEGA_URL in the environment', async () => {
|
||||
// SKIP due to https://github.com/facebook/jest/issues/12670
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('logs an error when the network config in invalid and there is a VEGA_URL in the environment', async () => {
|
||||
act(async () => {
|
||||
const consoleWarnSpy = jest
|
||||
.spyOn(console, 'warn')
|
||||
.mockImplementation(noop);
|
||||
|
||||
// @ts-ignore: typscript doesn't recognise the mock implementation
|
||||
// @ts-ignore: typescript doesn't recognize the mock implementation
|
||||
global.fetch.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
@ -492,12 +444,11 @@ describe('useEnvironment hook', () => {
|
||||
})
|
||||
);
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
setNodeSwitcherOpen: result.current.setNodeSwitcherOpen,
|
||||
@ -510,18 +461,19 @@ describe('useEnvironment hook', () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// SKIP due to https://github.com/facebook/jest/issues/12670
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('has a network error when the selected node is not a valid url', async () => {
|
||||
// SKIP due to https://github.com/facebook/jest/issues/12670
|
||||
// eslint-disable-next-line jest/no-disabled-tests
|
||||
it.skip('has a network error when the selected node is not a valid url', async () => {
|
||||
act(async () => {
|
||||
process.env['NX_VEGA_URL'] = 'not-url';
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
networkError: ErrorType.INVALID_URL,
|
||||
@ -529,19 +481,20 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('has a network error when cannot connect to the selected node', async () => {
|
||||
it('has a network error when cannot connect to the selected node', async () => {
|
||||
act(async () => {
|
||||
// @ts-ignore allow adding a mock return value to mocked module
|
||||
createClient.mockImplementation(() => {
|
||||
return createMockClient({ statistics: { hasError: true } });
|
||||
});
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
networkError: ErrorType.CONNECTION_ERROR,
|
||||
@ -549,19 +502,20 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('has a network error when the selected node is not on the correct network', async () => {
|
||||
it('has a network error when the selected node is not on the correct network', async () => {
|
||||
act(async () => {
|
||||
// @ts-ignore allow adding a mock return value to mocked module
|
||||
createClient.mockImplementation(() => {
|
||||
return createMockClient({ network: Networks.MAINNET });
|
||||
});
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
networkError: ErrorType.INVALID_NETWORK,
|
||||
@ -569,19 +523,20 @@ describe('useEnvironment hook', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('has a network error when the selected node has not ssl available', async () => {
|
||||
it('has a network error when the selected node has not ssl available', async () => {
|
||||
act(async () => {
|
||||
// @ts-ignore allow adding a mock return value to mocked module
|
||||
createClient.mockImplementation(() => {
|
||||
return createMockClient({ busEvents: { hasError: true } });
|
||||
});
|
||||
|
||||
const { result, waitFor } = renderHook(() => useEnvironment(), {
|
||||
const { result } = renderHook(() => useEnvironment(), {
|
||||
wrapper: MockWrapper,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.error).toBe(undefined);
|
||||
expect(result.current).toEqual({
|
||||
...mockEnvironmentState,
|
||||
networkError: ErrorType.SSL_ERROR,
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { renderHook, act } from '@testing-library/react-hooks';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { ApolloClient } from '@apollo/client';
|
||||
import createClient from '../utils/apollo-client';
|
||||
import { useNodes } from './use-nodes';
|
||||
import createMockClient, {
|
||||
getMockStatisticsResult,
|
||||
} from './mocks/apollo-client';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
|
||||
jest.mock('../utils/apollo-client');
|
||||
|
||||
@ -65,9 +66,7 @@ describe('useNodes hook', () => {
|
||||
|
||||
it('sets loading state while waiting for the results', async () => {
|
||||
const node = 'https://some.url';
|
||||
const { result, waitForNextUpdate } = renderHook(() =>
|
||||
useNodes({ hosts: [node] })
|
||||
);
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
expect(result.current.state[node]).toEqual({
|
||||
...initialState,
|
||||
@ -90,14 +89,12 @@ describe('useNodes hook', () => {
|
||||
isLoading: true,
|
||||
},
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
});
|
||||
|
||||
it('sets statistics results', async () => {
|
||||
const mockResult = getMockStatisticsResult();
|
||||
const node = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.state[node].block).toEqual({
|
||||
@ -122,7 +119,7 @@ describe('useNodes hook', () => {
|
||||
|
||||
it('sets subscription result', async () => {
|
||||
const node = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.state[node].ssl).toEqual({
|
||||
@ -135,7 +132,7 @@ describe('useNodes hook', () => {
|
||||
|
||||
it('sets error when host in not a valid url', async () => {
|
||||
const node = 'not-url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.state[node].block.hasError).toBe(true);
|
||||
@ -152,7 +149,7 @@ describe('useNodes hook', () => {
|
||||
);
|
||||
|
||||
const node = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.state[node].block).toEqual({
|
||||
@ -182,7 +179,7 @@ describe('useNodes hook', () => {
|
||||
);
|
||||
|
||||
const node = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.state[node].ssl).toEqual({
|
||||
@ -196,7 +193,7 @@ describe('useNodes hook', () => {
|
||||
it('allows updating block values', async () => {
|
||||
const mockResult = getMockStatisticsResult();
|
||||
const node = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.state[node].block.value).toEqual(
|
||||
@ -216,7 +213,7 @@ describe('useNodes hook', () => {
|
||||
it('does nothing when calling the block update on a non-existing node', async () => {
|
||||
const mockResult = getMockStatisticsResult();
|
||||
const node = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.state[node].block.value).toEqual(
|
||||
@ -233,7 +230,7 @@ describe('useNodes hook', () => {
|
||||
|
||||
it('adds new node', async () => {
|
||||
const node = 'custom-node-key';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [] }));
|
||||
|
||||
expect(result.current.state[node]).toEqual(undefined);
|
||||
|
||||
@ -249,7 +246,7 @@ describe('useNodes hook', () => {
|
||||
it('sets new url for node', async () => {
|
||||
const node = 'https://some.url';
|
||||
const newUrl = 'https://some-other.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [node] }));
|
||||
|
||||
act(() => {
|
||||
result.current.updateNodeUrl(node, newUrl);
|
||||
@ -263,7 +260,7 @@ describe('useNodes hook', () => {
|
||||
it('sets error when custom node has an invalid url', async () => {
|
||||
const node = 'node-key';
|
||||
const url = 'not-url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [] }));
|
||||
|
||||
expect(result.current.state[node]).toBe(undefined);
|
||||
|
||||
@ -288,7 +285,7 @@ describe('useNodes hook', () => {
|
||||
|
||||
const node = 'node-key';
|
||||
const url = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [] }));
|
||||
|
||||
expect(result.current.state[node]).toBe(undefined);
|
||||
|
||||
@ -325,7 +322,7 @@ describe('useNodes hook', () => {
|
||||
|
||||
const node = 'node-key';
|
||||
const url = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [] }));
|
||||
|
||||
expect(result.current.state[node]).toBe(undefined);
|
||||
|
||||
@ -345,9 +342,7 @@ describe('useNodes hook', () => {
|
||||
it('exposes a collection of clients', async () => {
|
||||
const url1 = 'https://some.url';
|
||||
const url2 = 'https://some-other.url';
|
||||
const { result, waitFor } = renderHook(() =>
|
||||
useNodes({ hosts: [url1, url2] })
|
||||
);
|
||||
const { result } = renderHook(() => useNodes({ hosts: [url1, url2] }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.clients[url1]).toBeInstanceOf(ApolloClient);
|
||||
@ -358,7 +353,7 @@ describe('useNodes hook', () => {
|
||||
it('exposes a client for the custom node', async () => {
|
||||
const node = 'node-key';
|
||||
const url = 'https://some.url';
|
||||
const { result, waitFor } = renderHook(() => useNodes({ hosts: [] }));
|
||||
const { result } = renderHook(() => useNodes({ hosts: [] }));
|
||||
|
||||
act(() => {
|
||||
result.current.updateNodeUrl(node, url);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import { render, screen, waitFor, act } from '@testing-library/react';
|
||||
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import type { PartialDeep } from 'type-fest';
|
||||
@ -46,134 +46,142 @@ describe('FillsTable', () => {
|
||||
};
|
||||
});
|
||||
|
||||
it('correct columns are rendered', async () => {
|
||||
render(<FillsTable partyId="party-id" rowData={[generateFill()]} />);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
it('should render correct columns', async () => {
|
||||
act(async () => {
|
||||
render(<FillsTable partyId="party-id" rowData={[generateFill()]} />);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
expect(headers).toHaveLength(7);
|
||||
expect(headers.map((h) => h.textContent?.trim())).toEqual([
|
||||
'Market',
|
||||
'Amount',
|
||||
'Value',
|
||||
'Filled value',
|
||||
'Role',
|
||||
'Fee',
|
||||
'Date',
|
||||
]);
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
expect(headers).toHaveLength(7);
|
||||
expect(headers.map((h) => h.textContent?.trim())).toEqual([
|
||||
'Market',
|
||||
'Amount',
|
||||
'Value',
|
||||
'Filled value',
|
||||
'Role',
|
||||
'Fee',
|
||||
'Date',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('formats cells correctly for buyer fill', async () => {
|
||||
const partyId = 'party-id';
|
||||
const buyerFill = generateFill({
|
||||
...defaultFill,
|
||||
buyer: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Side.Sell,
|
||||
buyerFee: {
|
||||
makerFee: '2',
|
||||
infrastructureFee: '2',
|
||||
liquidityFee: '2',
|
||||
},
|
||||
it('should format cells correctly for buyer fill', async () => {
|
||||
act(async () => {
|
||||
const partyId = 'party-id';
|
||||
const buyerFill = generateFill({
|
||||
...defaultFill,
|
||||
buyer: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Side.Sell,
|
||||
buyerFee: {
|
||||
makerFee: '2',
|
||||
infrastructureFee: '2',
|
||||
liquidityFee: '2',
|
||||
},
|
||||
});
|
||||
|
||||
render(<FillsTable partyId={partyId} rowData={[buyerFill]} />);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
buyerFill.market.name,
|
||||
'+3.00000',
|
||||
'1.00 BTC',
|
||||
'3.00 BTC',
|
||||
'Maker',
|
||||
'0.06 BTC',
|
||||
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
|
||||
const amountCell = cells.find((c) => c.getAttribute('col-id') === 'size');
|
||||
expect(amountCell).toHaveClass('text-vega-green');
|
||||
});
|
||||
|
||||
render(<FillsTable partyId={partyId} rowData={[buyerFill]} />);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
buyerFill.market.name,
|
||||
'+3.00000',
|
||||
'1.00 BTC',
|
||||
'3.00 BTC',
|
||||
'Maker',
|
||||
'0.06 BTC',
|
||||
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
|
||||
const amountCell = cells.find((c) => c.getAttribute('col-id') === 'size');
|
||||
expect(amountCell).toHaveClass('text-vega-green');
|
||||
});
|
||||
|
||||
it('formats cells correctly for seller fill', async () => {
|
||||
const partyId = 'party-id';
|
||||
const buyerFill = generateFill({
|
||||
...defaultFill,
|
||||
seller: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Side.Sell,
|
||||
sellerFee: {
|
||||
makerFee: '1',
|
||||
infrastructureFee: '1',
|
||||
liquidityFee: '1',
|
||||
},
|
||||
it('should format cells correctly for seller fill', async () => {
|
||||
act(async () => {
|
||||
const partyId = 'party-id';
|
||||
const buyerFill = generateFill({
|
||||
...defaultFill,
|
||||
seller: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Side.Sell,
|
||||
sellerFee: {
|
||||
makerFee: '1',
|
||||
infrastructureFee: '1',
|
||||
liquidityFee: '1',
|
||||
},
|
||||
});
|
||||
|
||||
render(<FillsTable partyId={partyId} rowData={[buyerFill]} />);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
buyerFill.market.name,
|
||||
'-3.00000',
|
||||
'1.00 BTC',
|
||||
'3.00 BTC',
|
||||
'Taker',
|
||||
'0.03 BTC',
|
||||
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
|
||||
const amountCell = cells.find((c) => c.getAttribute('col-id') === 'size');
|
||||
expect(amountCell).toHaveClass('text-vega-red');
|
||||
});
|
||||
|
||||
render(<FillsTable partyId={partyId} rowData={[buyerFill]} />);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
buyerFill.market.name,
|
||||
'-3.00000',
|
||||
'1.00 BTC',
|
||||
'3.00 BTC',
|
||||
'Taker',
|
||||
'0.03 BTC',
|
||||
getDateTimeFormat().format(new Date(buyerFill.createdAt)),
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
|
||||
const amountCell = cells.find((c) => c.getAttribute('col-id') === 'size');
|
||||
expect(amountCell).toHaveClass('text-vega-red');
|
||||
});
|
||||
|
||||
it('renders correct maker or taker role', async () => {
|
||||
const partyId = 'party-id';
|
||||
const takerFill = generateFill({
|
||||
seller: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Side.Sell,
|
||||
it('should render correct maker or taker role', async () => {
|
||||
act(async () => {
|
||||
const partyId = 'party-id';
|
||||
const takerFill = generateFill({
|
||||
seller: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Side.Sell,
|
||||
});
|
||||
|
||||
const { rerender } = render(
|
||||
<FillsTable partyId={partyId} rowData={[takerFill]} />
|
||||
);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
expect(
|
||||
screen
|
||||
.getAllByRole('gridcell')
|
||||
.find((c) => c.getAttribute('col-id') === 'aggressor')
|
||||
).toHaveTextContent('Taker');
|
||||
|
||||
const makerFill = generateFill({
|
||||
seller: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Side.Buy,
|
||||
});
|
||||
|
||||
rerender(<FillsTable partyId={partyId} rowData={[makerFill]} />);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
expect(
|
||||
screen
|
||||
.getAllByRole('gridcell')
|
||||
.find((c) => c.getAttribute('col-id') === 'aggressor')
|
||||
).toHaveTextContent('Maker');
|
||||
});
|
||||
|
||||
const { rerender } = render(
|
||||
<FillsTable partyId={partyId} rowData={[takerFill]} />
|
||||
);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
expect(
|
||||
screen
|
||||
.getAllByRole('gridcell')
|
||||
.find((c) => c.getAttribute('col-id') === 'aggressor')
|
||||
).toHaveTextContent('Taker');
|
||||
|
||||
const makerFill = generateFill({
|
||||
seller: {
|
||||
id: partyId,
|
||||
},
|
||||
aggressor: Side.Buy,
|
||||
});
|
||||
|
||||
rerender(<FillsTable partyId={partyId} rowData={[makerFill]} />);
|
||||
await waitForGridToBeInTheDOM();
|
||||
await waitForDataToHaveLoaded();
|
||||
|
||||
expect(
|
||||
screen
|
||||
.getAllByRole('gridcell')
|
||||
.find((c) => c.getAttribute('col-id') === 'aggressor')
|
||||
).toHaveTextContent('Maker');
|
||||
});
|
||||
});
|
||||
|
@ -69,19 +69,22 @@ describe('ProposalForm', () => {
|
||||
it('handles validation', async () => {
|
||||
const mockSendTx = jest.fn().mockReturnValue(Promise.resolve());
|
||||
setup(mockSendTx);
|
||||
|
||||
fireEvent.click(screen.getByTestId('proposal-submit'));
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByTestId('proposal-submit'));
|
||||
});
|
||||
expect(mockSendTx).not.toHaveBeenCalled();
|
||||
|
||||
expect(await screen.findByTestId('input-error-text')).toHaveTextContent(
|
||||
'Required'
|
||||
);
|
||||
|
||||
fireEvent.change(screen.getByTestId('proposal-data'), {
|
||||
target: { value: 'invalid' },
|
||||
await act(async () => {
|
||||
fireEvent.change(screen.getByTestId('proposal-data'), {
|
||||
target: { value: 'invalid' },
|
||||
});
|
||||
});
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByTestId('proposal-submit'));
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByTestId('proposal-submit'));
|
||||
expect(mockSendTx).not.toHaveBeenCalled();
|
||||
|
||||
expect(await screen.findByTestId('input-error-text')).toHaveTextContent(
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { VegaTxStatus, VegaWalletContext } from '@vegaprotocol/wallet';
|
||||
import type {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type {
|
||||
VegaKeyExtended,
|
||||
VegaWalletContextShape,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type { Order } from '../utils';
|
||||
import type {
|
||||
VegaKeyExtended,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import {
|
||||
VegaWalletOrderTimeInForce,
|
||||
VegaWalletOrderType,
|
||||
|
@ -56,46 +56,48 @@ const singleRow: Positions_party_positions = {
|
||||
};
|
||||
const singleRowData = [singleRow];
|
||||
|
||||
it('should render successfully', async () => {
|
||||
await act(async () => {
|
||||
const { baseElement } = render(<PositionsTable data={[]} />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
it('Render correct columns', async () => {
|
||||
await act(async () => {
|
||||
render(<PositionsTable data={singleRowData} />);
|
||||
await waitFor(async () => {
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
expect(headers).toHaveLength(5);
|
||||
expect(headers.map((h) => h.textContent?.trim())).toEqual([
|
||||
'Market',
|
||||
'Amount',
|
||||
'Average Entry Price',
|
||||
'Mark Price',
|
||||
'Realised PNL',
|
||||
]);
|
||||
describe('PositionsTable', () => {
|
||||
it('should render successfully', async () => {
|
||||
act(async () => {
|
||||
const { baseElement } = render(<PositionsTable data={[]} />);
|
||||
expect(baseElement).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Correct formatting applied', async () => {
|
||||
await act(async () => {
|
||||
render(<PositionsTable data={singleRowData} />);
|
||||
await waitFor(async () => {
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
singleRow.market.tradableInstrument.instrument.code,
|
||||
'+100.00',
|
||||
'11.29935',
|
||||
'11.38885',
|
||||
'+5,200.000',
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
it('should render correct columns', async () => {
|
||||
act(async () => {
|
||||
render(<PositionsTable data={singleRowData} />);
|
||||
await waitFor(async () => {
|
||||
const headers = screen.getAllByRole('columnheader');
|
||||
expect(headers).toHaveLength(5);
|
||||
expect(headers.map((h) => h.textContent?.trim())).toEqual([
|
||||
'Market',
|
||||
'Amount',
|
||||
'Average Entry Price',
|
||||
'Mark Price',
|
||||
'Realised PNL',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should apply correct formatting', () => {
|
||||
act(async () => {
|
||||
render(<PositionsTable data={singleRowData} />);
|
||||
await waitFor(async () => {
|
||||
const cells = screen.getAllByRole('gridcell');
|
||||
const expectedValues = [
|
||||
singleRow.market.tradableInstrument.instrument.code,
|
||||
'+100.00',
|
||||
'11.29935',
|
||||
'11.38885',
|
||||
'+5,200.000',
|
||||
];
|
||||
cells.forEach((cell, i) => {
|
||||
expect(cell).toHaveTextContent(expectedValues[i]);
|
||||
});
|
||||
expect(cells[cells.length - 1]).toHaveClass('color-vega-green');
|
||||
});
|
||||
expect(cells[cells.length - 1]).toHaveClass('color-vega-green');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useApplyGridTransaction } from './use-apply-grid-transaction';
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
type Items = Array<{ id: string; value: number }>;
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import type { OperationVariables } from '@apollo/client';
|
||||
import type { Subscribe, Load } from '../lib/generic-data-provider';
|
||||
import type {
|
||||
Subscribe,
|
||||
Load,
|
||||
UpdateCallback,
|
||||
} from '../lib/generic-data-provider';
|
||||
|
||||
/**
|
||||
*
|
||||
@ -54,14 +58,14 @@ export function useDataProvider<Data, Delta>({
|
||||
}
|
||||
return Promise.reject();
|
||||
}, []);
|
||||
const callback = useCallback(
|
||||
const callback = useCallback<UpdateCallback<Data, Delta>>(
|
||||
({ data, error, loading, delta, insertionData, totalCount }) => {
|
||||
setError(error);
|
||||
setLoading(loading);
|
||||
if (!error && !loading) {
|
||||
// if update or insert function returns true it means that component handles updates
|
||||
// component can use flush() which will call callback without delta and cause data state update
|
||||
if (initialized.current) {
|
||||
if (initialized.current && data) {
|
||||
if (delta && update && update({ delta, data })) {
|
||||
return;
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ export const PriceCell = React.memo(
|
||||
return <span data-testid="price">-</span>;
|
||||
}
|
||||
const decimalSeparator = getDecimalSeparator();
|
||||
const valueSplit = decimalSeparator
|
||||
? valueFormatted.split(decimalSeparator)
|
||||
: [value];
|
||||
const valueSplit: string[] = decimalSeparator
|
||||
? valueFormatted.split(decimalSeparator).map((v) => `${v}`)
|
||||
: [`${value}`];
|
||||
return (
|
||||
<span
|
||||
className="font-mono relative text-ui-small text-black dark:text-white"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type { VegaWalletContextShape } from './context';
|
||||
import { VegaWalletContext } from './context';
|
||||
import type { ReactNode } from 'react';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { renderHook, act } from '@testing-library/react-hooks/dom';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { EthTxStatus } from './use-ethereum-transaction';
|
||||
import { useEthereumTransaction } from './use-ethereum-transaction';
|
||||
import type { ethers } from 'ethers';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { act, renderHook } from '@testing-library/react-hooks';
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import type { MockedResponse } from '@apollo/client/testing';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import type { ReactNode } from 'react';
|
||||
|
30
package.json
30
package.json
@ -14,6 +14,9 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.5.8",
|
||||
"@babel/plugin-proposal-export-default-from": "^7.18.10",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/runtime": "^7.18.9",
|
||||
"@blueprintjs/icons": "^3.32.0",
|
||||
"@emotion/react": "^11.9.0",
|
||||
"@emotion/styled": "^11.8.1",
|
||||
@ -29,7 +32,7 @@
|
||||
"@sentry/nextjs": "^6.19.3",
|
||||
"@sentry/react": "^6.19.2",
|
||||
"@sentry/tracing": "^6.19.2",
|
||||
"@testing-library/user-event": "^14.2.1",
|
||||
"@testing-library/user-event": "^14.4.1",
|
||||
"@walletconnect/ethereum-provider": "^1.7.5",
|
||||
"@web3-react/core": "8.0.20-beta.0",
|
||||
"@web3-react/metamask": "8.0.16-beta.0",
|
||||
@ -56,16 +59,16 @@
|
||||
"immer": "^9.0.12",
|
||||
"js-sha3": "^0.8.0",
|
||||
"lodash": "^4.17.21",
|
||||
"next": "^12.0.7",
|
||||
"next": "12.0.9",
|
||||
"pennant": "^0.4.12",
|
||||
"postcss": "^8.4.6",
|
||||
"react": "17.0.2",
|
||||
"react": "18.2.0",
|
||||
"react-copy-to-clipboard": "^5.0.4",
|
||||
"react-dom": "17.0.2",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.27.0",
|
||||
"react-i18next": "^11.11.4",
|
||||
"react-intersection-observer": "^9.2.2",
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-router-dom": "6.3.0",
|
||||
"react-syntax-highlighter": "^15.4.5",
|
||||
"react-use-websocket": "^3.0.0",
|
||||
"react-virtualized-auto-sizer": "^1.0.6",
|
||||
@ -107,25 +110,24 @@
|
||||
"@storybook/react": "~6.4.12",
|
||||
"@svgr/webpack": "^5.4.0",
|
||||
"@testing-library/jest-dom": "^5.16.2",
|
||||
"@testing-library/react": "12.1.2",
|
||||
"@testing-library/react-hooks": "7.0.2",
|
||||
"@testing-library/react": "13.3.0",
|
||||
"@types/classnames": "^2.3.1",
|
||||
"@types/faker": "^5.5.8",
|
||||
"@types/jest": "27.0.2",
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/lodash": "^4.14.171",
|
||||
"@types/node": "16.11.7",
|
||||
"@types/node": "18.0.4",
|
||||
"@types/prismjs": "^1.26.0",
|
||||
"@types/react": "17.0.39",
|
||||
"@types/react": "18.0.1",
|
||||
"@types/react-copy-to-clipboard": "^5.0.2",
|
||||
"@types/react-dom": "17.0.9",
|
||||
"@types/react-dom": "18.0.6",
|
||||
"@types/react-router-dom": "5.3.1",
|
||||
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||
"@types/react-window": "^1.8.5",
|
||||
"@types/react-window-infinite-loader": "^1.0.6",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@typescript-eslint/eslint-plugin": "5.18.0",
|
||||
"@typescript-eslint/parser": "5.18.0",
|
||||
"babel-jest": "27.2.3",
|
||||
"@typescript-eslint/eslint-plugin": "5.32.0",
|
||||
"@typescript-eslint/parser": "5.32.0",
|
||||
"babel-jest": "27.5.1",
|
||||
"babel-loader": "8.1.0",
|
||||
"cypress": "^10.2.0",
|
||||
"cypress-cucumber-preprocessor": "^4.3.1",
|
||||
|
Loading…
Reference in New Issue
Block a user