Skip to content

Commit

Permalink
update testing library conventions in unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
kenkunz committed Nov 21, 2024
1 parent f35cd1a commit 115411f
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 46 deletions.
15 changes: 8 additions & 7 deletions src/lib/components/Timestamp.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { vi } from 'vitest';
import { render } from '@testing-library/svelte';
import { render, screen } from '@testing-library/svelte';
import Timestamp from './Timestamp.svelte';

describe('Timestamp component', () => {
const date = new Date('2023-01-01T12:00Z');

test('should render fallback string if no valid date supplied', () => {
const { getByText } = render(Timestamp, { date: undefined });
getByText('---');
render(Timestamp, { date: undefined });
screen.getByText('---');
});

test('should render iso date string by default', () => {
const { getByText, queryByText } = render(Timestamp, { date });
getByText('2023-01-01');
expect(queryByText('12:00')).toBeNull();
render(Timestamp, { date });
screen.getByText('2023-01-01');
expect(screen.queryByText('12:00')).toBeNull();
});

test('should render iso date with time', () => {
Expand All @@ -36,7 +36,8 @@ describe('Timestamp component', () => {
vi.useFakeTimers();
vi.setSystemTime('2023-01-15T12:00Z');

const timeEl = render(Timestamp, { date, relative: true }).container.querySelector('time');
const { container } = render(Timestamp, { date, relative: true });
const timeEl = container.querySelector('time');

expect(timeEl).toHaveAttribute('datetime', date.toISOString());
expect(timeEl).toHaveTextContent('14 days ago');
Expand Down
6 changes: 3 additions & 3 deletions src/lib/components/Tooltip.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render } from '@testing-library/svelte';
import { mount } from 'svelte';
import Tooltip from './Tooltip.svelte';

describe('Tooltip component', () => {
Expand All @@ -8,8 +8,8 @@ describe('Tooltip component', () => {
// (the popup content is not hidden on initial page render).
// see: https://stackoverflow.com/questions/40531029 updates 3 & 4
test('should use button tag for popup content', () => {
const { container } = render(Tooltip);
const popup = container.querySelector('.popup');
mount(Tooltip, { target: document.body });
const popup = document.body.querySelector('.popup');
expect(popup?.tagName).toBe('BUTTON');
// button should be disabled to remove from tab index and prevent click events
expect(popup).toBeDisabled();
Expand Down
11 changes: 6 additions & 5 deletions src/lib/search/components/Search.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { vi } from 'vitest';
import { render } from '@testing-library/svelte';
import { render, screen } from '@testing-library/svelte';
import userEvent from '@testing-library/user-event';
import Search from './Search.svelte';

Expand All @@ -12,12 +12,13 @@ vi.mock('$lib/search/trading-entities');
describe('Search component', () => {
test('should submit form when user hits enter', async () => {
const user = userEvent.setup();
const searchBox = render(Search).getByLabelText('search-desktop') as HTMLFormElement;
const formSubmitHandler = vi.fn();
render(Search);
const searchBox = screen.getByLabelText('search-desktop') as HTMLFormElement;
const formSubmitSpy = vi.fn();
searchBox.form.onsubmit = formSubmitSpy;

searchBox.form.onsubmit = formSubmitHandler;
searchBox.focus();
await user.keyboard('eth{Enter}');
expect(formSubmitHandler).toHaveBeenCalled();
expect(formSubmitSpy).toHaveBeenCalled();
});
});
27 changes: 14 additions & 13 deletions src/routes/search/SearchPanel.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render } from '@testing-library/svelte';
import { render, screen } from '@testing-library/svelte';
import userEvent from '@testing-library/user-event';
import SearchPanel from './SearchPanel.svelte';

Expand All @@ -15,23 +15,23 @@ const defaultProps = {

describe('SearchPanel component', () => {
test('should display "search for" fallback when no search criteria', async () => {
const { getByText, queryAllByRole } = render(SearchPanel, defaultProps);
getByText('Search exchanges, tokens, trading pairs and lending reserves.');
expect(queryAllByRole('listitem')).toHaveLength(0);
render(SearchPanel, defaultProps);
screen.getByText('Search exchanges, tokens, trading pairs and lending reserves.');
expect(screen.queryAllByRole('listitem')).toHaveLength(0);
});

test('should display "no results" fallback when no results found', async () => {
const { getByText, queryAllByRole } = render(SearchPanel, {
render(SearchPanel, {
...defaultProps,
hasSearch: true,
hits: []
});
getByText('No results found', { exact: false });
expect(queryAllByRole('listitem')).toHaveLength(0);
screen.getByText('No results found', { exact: false });
expect(screen.queryAllByRole('listitem')).toHaveLength(0);
});

test('should display results when results found', async () => {
const { queryByText, queryAllByRole } = render(SearchPanel, {
render(SearchPanel, {
...defaultProps,
hasSearch: true,
hits: [
Expand All @@ -45,16 +45,17 @@ describe('SearchPanel component', () => {
}
]
});
expect(queryByText('No results found', { exact: false })).toBeNull();
expect(queryByText('Search exchanges, tokens and trading pairs.')).toBeNull();
expect(queryAllByRole('listitem')).toHaveLength(1);
expect(screen.queryByText('No results found', { exact: false })).toBeNull();
expect(screen.queryByText('Search exchanges, tokens and trading pairs.')).toBeNull();
expect(screen.queryAllByRole('listitem')).toHaveLength(1);
});

test('search field should lose focus when "Enter" key is pressed', async () => {
const user = userEvent.setup();
const searchBox = render(SearchPanel, defaultProps).getByRole('searchbox');
searchBox.focus();
render(SearchPanel, defaultProps);
const searchBox = screen.getByRole('searchbox');

searchBox.focus();
await user.keyboard('eth');
expect(searchBox).toHaveFocus();

Expand Down
20 changes: 10 additions & 10 deletions src/routes/search/SortSelect.test.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { render } from '@testing-library/svelte';
import SortSelect, { getSortParams } from './SortSelect.svelte';
import { render, screen } from '@testing-library/svelte';
import { default as SortSelect, getSortParams } from './SortSelect.svelte';

describe('SortSelect component', () => {
test('should render a drop-down with sort options', () => {
const { getAllByRole } = render(SortSelect);
expect(getAllByRole('option')).toHaveLength(6);
render(SortSelect);
expect(screen.getAllByRole('option')).toHaveLength(6);
});

test('should select first option by default', () => {
const { getByRole } = render(SortSelect);
getByRole('option', { name: '▼ TVL', selected: true });
render(SortSelect);
screen.getByRole('option', { name: '▼ TVL', selected: true });
});

test('should select option matching the value prop', () => {
const { getByRole } = render(SortSelect, { value: 'volume:desc' });
getByRole('option', { name: '▼ Volume', selected: true });
render(SortSelect, { value: 'volume:desc' });
screen.getByRole('option', { name: '▼ Volume', selected: true });
});

test('should default to first option if value does not match any options', () => {
const { getByRole } = render(SortSelect, { value: 'foo:bar' });
getByRole('option', { name: '▼ TVL', selected: true });
render(SortSelect, { value: 'foo:bar' });
screen.getByRole('option', { name: '▼ TVL', selected: true });
});

describe('getSortParams module function', () => {
Expand Down
14 changes: 7 additions & 7 deletions src/routes/strategies/StrategyTile.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render } from '@testing-library/svelte';
import StrategyTile from './StrategyTile.svelte';
import type { ConnectedStrategyInfo } from 'trade-executor/models/strategy-info';
import { render, screen } from '@testing-library/svelte';
import StrategyTile from './StrategyTile.svelte';

const baseStrategy = {
id: 'strategy_1',
Expand All @@ -22,11 +22,11 @@ describe('StrategyTile component', () => {
} as const;

test('should display error message', async () => {
const { getByText } = render(StrategyTile, { strategy, chartDateRange });
render(StrategyTile, { strategy, chartDateRange });
// check for tooltip trigger
getByText(/Error/);
screen.getByText(/Error/);
// check for tooltip popup content
const popup = getByText(/Trade executor offline/);
const popup = screen.getByText(/Trade executor offline/);
});
});

Expand Down Expand Up @@ -136,8 +136,8 @@ describe('StrategyTile component', () => {
});

test('should display historic performance value', async () => {
const { getByTestId } = render(StrategyTile, { strategy, chartDateRange });
const performanceElem = getByTestId('key-metric-profitability-value');
render(StrategyTile, { strategy, chartDateRange });
const performanceElem = screen.getByTestId('key-metric-profitability-value');
expect(performanceElem).toHaveTextContent('▲ 12.0%');
});

Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"sourceMap": true,
"strict": true,
"moduleResolution": "bundler",
"types": ["vitest/globals"]
"types": ["vitest/globals", "@testing-library/jest-dom"]
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
Expand Down

0 comments on commit 115411f

Please sign in to comment.