Skip to content

Commit

Permalink
Merge branch 'main' into 2025-02-18-rm-typeshare
Browse files Browse the repository at this point in the history
  • Loading branch information
rouzwelt authored Feb 21, 2025
2 parents bd3cbe7 + 7a773c6 commit 317b75c
Show file tree
Hide file tree
Showing 22 changed files with 325 additions and 159 deletions.
10 changes: 10 additions & 0 deletions packages/ui-components/src/__tests__/OrderDetail.test.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@
import type { Readable } from 'svelte/store';
import { Button } from 'flowbite-svelte';
import DepositOrWithdrawButtons from '../lib/components/detail/DepositOrWithdrawButtons.svelte';
import Refresh from '$lib/components/icon/Refresh.svelte';
import { useQueryClient } from '@tanstack/svelte-query';
import type { OrderRemoveModalProps } from '../lib/types/modal';
import type { Hex } from 'viem';
import { invalidateIdQuery } from '$lib/queries/queryClient';
const queryClient = useQueryClient();
export let walletAddressMatchesOrBlank: Readable<(address: string) => boolean> | undefined =
undefined;
Expand Down Expand Up @@ -51,6 +56,11 @@
Remove
</Button>
{/if}

<Refresh
on:click={async () => await invalidateIdQuery(queryClient, id)}
spin={$orderDetailQuery.isLoading || $orderDetailQuery.isFetching}
/>
</svelte:fragment>

<svelte:fragment slot="card" let:data>
Expand Down
47 changes: 47 additions & 0 deletions packages/ui-components/src/__tests__/OrderDetail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { describe, it, vi, type Mock } from 'vitest';
import { expect } from '../lib/test/matchers';
import OrderDetail from './OrderDetail.test.svelte';
import type { SgOrder, SgVault } from '@rainlanguage/orderbook/js_api';
import userEvent from '@testing-library/user-event';
import type { Config } from 'wagmi';

const { mockWalletAddressMatchesOrBlankStore } = await vi.hoisted(
Expand Down Expand Up @@ -217,4 +218,50 @@ describe('OrderDetail Component', () => {
expect(screen.getByText('Input & output vaults')).toBeInTheDocument();
});
});

it('refresh button triggers query invalidation when clicked', async () => {
const mockQuery = vi.mocked(await import('@tanstack/svelte-query'));
const mockInvalidateQueries = vi.fn();

// Mock the createQuery as in other tests
mockQuery.createQuery = vi.fn((__options, _queryClient) => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
subscribe: (fn: (value: any) => void) => {
fn({
data: { order: mockOrder, vaults: new Map() },
status: 'success',
isFetching: false,
refetch: () => {}
});
return { unsubscribe: () => {} };
}
})) as Mock;

// Mock the useQueryClient hook
mockQuery.useQueryClient = vi.fn(() => ({
invalidateQueries: mockInvalidateQueries
// eslint-disable-next-line @typescript-eslint/no-explicit-any
})) as any;

render(OrderDetail, {
props: {
id: 'mockId',
subgraphUrl: 'https://example.com',
walletAddressMatchesOrBlank: mockWalletAddressMatchesOrBlankStore,
chainId,
orderbookAddress
}
});

const refreshButton = screen.getByTestId('refresh-button');
await userEvent.click(refreshButton);

await waitFor(() => {
expect(mockInvalidateQueries).toHaveBeenCalledWith({
queryKey: ['mockId'],
refetchType: 'all',
exact: false
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
export let emptyMessage: string;
export let title: string;
export let head: string;
export let queryKey: string;
</script>

<TanstackAppTable {query} {emptyMessage} rowHoverable>
<TanstackAppTable {query} {emptyMessage} rowHoverable {queryKey}>
<svelte:fragment slot="title">
<h2>{title}</h2>
</svelte:fragment>
Expand Down
177 changes: 84 additions & 93 deletions packages/ui-components/src/__tests__/TanstackAppTable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,176 +2,167 @@ import { render, screen, waitFor } from '@testing-library/svelte';
import { test, expect } from 'vitest';
import TanstackAppTableTest from './TanstackAppTable.test.svelte';
import userEvent from '@testing-library/user-event';
import { createResolvableInfiniteQuery } from '../lib/__mocks__/queries';
import { writable } from 'svelte/store';
import { writable, get } from 'svelte/store';
import type { CreateInfiniteQueryResult, InfiniteData } from '@tanstack/svelte-query';

test('shows head and title', async () => {
const { query, resolve } = createResolvableInfiniteQuery((pageParam) => {
return ['page' + pageParam];
});

render(TanstackAppTableTest, {
query,
vi.mock('@tanstack/svelte-query', () => ({
useQueryClient: () => ({})
}));

const mockInvalidateIdQuery = vi.fn();
vi.mock('$lib/queries/queryClient', () => ({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
invalidateIdQuery: (queryClient: any, queryKey: string) =>
mockInvalidateIdQuery(queryClient, queryKey)
}));

// Helper function to create base pages
const createPages = (pageData: unknown[] = ['page0']) =>
writable({
pages: [pageData],
pageParams: [0]
});

// Helper function to create base mock query
const createMockQuery = (pages: ReturnType<typeof createPages>, overrides = {}) => {
return writable({
data: get(pages),
isLoading: false,
isFetching: false,
isFetchingNextPage: false,
hasNextPage: true,
status: 'success' as const,
fetchStatus: 'idle' as const,
fetchNextPage: vi.fn(),
...overrides
});
};

// Helper function for common render props
const renderTable = (query: ReturnType<typeof createMockQuery>) => {
return render(TanstackAppTableTest, {
query: query as unknown as CreateInfiniteQueryResult<InfiniteData<unknown[], unknown>, Error>,
emptyMessage: 'No rows',
title: 'Test Table',
head: 'Test head'
head: 'Test head',
queryKey: 'test'
});
};

resolve();
test('shows head and title', async () => {
const pages = createPages();
const mockQuery = createMockQuery(pages);
renderTable(mockQuery);

await waitFor(() => expect(screen.getByTestId('head')).toHaveTextContent('Test head'));
expect(screen.getByTestId('title')).toHaveTextContent('Test Table');
});

test('renders rows', async () => {
const { query, resolve } = createResolvableInfiniteQuery((pageParam) => {
return ['page' + pageParam];
});
const pages = createPages();
const mockQuery = createMockQuery(pages);
renderTable(mockQuery);

render(TanstackAppTableTest, {
query,
emptyMessage: 'No rows',
title: 'Test Table',
head: 'Test head'
});

resolve();
await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0'));
});

test('shows empty message', async () => {
const { query, resolve } = createResolvableInfiniteQuery(() => {
return [];
});

render(TanstackAppTableTest, {
query,
emptyMessage: 'No rows',
title: 'Test Table',
head: 'Test head'
});

resolve();
const pages = createPages([]);
const mockQuery = createMockQuery(pages);
renderTable(mockQuery);

await waitFor(() => expect(screen.getByTestId('emptyMessage')).toHaveTextContent('No rows'));
});

test('loads more rows', async () => {
const { query, resolve } = createResolvableInfiniteQuery((pageParam) => {
return ['page' + pageParam];
});

render(TanstackAppTableTest, {
query,
emptyMessage: 'No rows',
title: 'Test Table',
head: 'Test head'
});

resolve();
const pages = createPages();
const mockQuery = createMockQuery(pages, {
fetchNextPage: async () => {
mockQuery.update((q) => ({ ...q, isFetchingNextPage: true }));
await new Promise((resolve) => setTimeout(resolve, 0));
pages.update((data) => ({
pages: [...data.pages, [`page${data.pages.length}`]],
pageParams: [...data.pageParams, data.pageParams.length]
}));
mockQuery.update((q) => ({
...q,
data: get(pages),
isFetchingNextPage: false
}));
}
});
renderTable(mockQuery);

await waitFor(() => expect(screen.getByTestId('bodyRow')).toHaveTextContent('page0'));

// loading more rows
const loadMoreButton = screen.getByTestId('loadMoreButton');
await userEvent.click(loadMoreButton);

resolve();

await waitFor(() => {
expect(screen.getAllByTestId('bodyRow')).toHaveLength(2);
});

let rows = screen.getAllByTestId('bodyRow');

expect(rows).toHaveLength(2);
expect(rows[0]).toHaveTextContent('page0');
expect(rows[1]).toHaveTextContent('page1');

// loading more rows
await userEvent.click(loadMoreButton);

resolve();

await waitFor(() => {
expect(screen.getAllByTestId('bodyRow')).toHaveLength(3);
});

rows = screen.getAllByTestId('bodyRow');

expect(rows).toHaveLength(3);
expect(rows[0]).toHaveTextContent('page0');
expect(rows[1]).toHaveTextContent('page1');
expect(rows[2]).toHaveTextContent('page2');
});

test('load more button message changes when loading', async () => {
const { query, resolve } = createResolvableInfiniteQuery((pageParam) => {
return ['page' + pageParam];
});

render(TanstackAppTableTest, {
query,
emptyMessage: 'No rows',
title: 'Test Table',
head: 'Test head'
const pages = createPages();
const mockQuery = createMockQuery(pages, {
fetchNextPage: async () => {
mockQuery.update((q) => ({ ...q, isFetchingNextPage: true }));
await new Promise((resolve) => setTimeout(resolve, 100));
mockQuery.update((q) => ({ ...q, isFetchingNextPage: false }));
}
});

resolve();
renderTable(mockQuery);

expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Load More');

// loading more rows
const loadMoreButton = screen.getByTestId('loadMoreButton');
await userEvent.click(loadMoreButton);

expect(await screen.findByTestId('loadMoreButton')).toHaveTextContent('Loading more...');

resolve();

await waitFor(() => {
expect(screen.getByTestId('loadMoreButton')).toHaveTextContent('Load More');
});
});

test('shows refresh icon', async () => {
const { query, resolve } = createResolvableInfiniteQuery((pageParam) => {
return ['page' + pageParam];
});

render(TanstackAppTableTest, {
query,
emptyMessage: 'No rows',
title: 'Test Table',
head: 'Test head'
});

resolve();
const pages = createPages();
const mockQuery = createMockQuery(pages);
renderTable(mockQuery);

await waitFor(() => expect(screen.getByTestId('refreshButton')).toBeInTheDocument());
});

test('refetches data when refresh button is clicked', async () => {
const mockRefetch = vi.fn();
const mockQuery = writable({
const mockQuery = createMockQuery(createPages(), {
status: 'success',
fetchStatus: 'idle',
isLoading: false,
isFetching: false,
refetch: mockRefetch
});

render(TanstackAppTableTest, {
query: mockQuery as unknown as CreateInfiniteQueryResult<
InfiniteData<unknown[], unknown>,
Error
>,
emptyMessage: 'No rows',
title: 'Test Table',
head: 'Test head'
});
renderTable(mockQuery);

const refreshButton = screen.getByTestId('refreshButton');
await userEvent.click(refreshButton);

expect(mockRefetch).toHaveBeenCalled();
expect(mockInvalidateIdQuery).toHaveBeenCalledWith(expect.anything(), 'test');
});
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ test('refreshes the quote when the refresh icon is clicked', async () => {
}
]);

const refreshButton = screen.getByTestId('refreshButton');
const refreshButton = screen.getByTestId('refresh-button');
fireEvent.click(refreshButton);

await waitFor(() => {
Expand Down
Loading

0 comments on commit 317b75c

Please sign in to comment.