Skip to content

Commit 133bcdd

Browse files
fix: reset filters (with e2e)
1 parent 0f4a6f6 commit 133bcdd

File tree

3 files changed

+59
-39
lines changed

3 files changed

+59
-39
lines changed

packages/curve-ui-kit/src/shared/ui/DataTable/HiddenMarketsResetFilters.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export const HiddenMarketsResetFilters = ({
3030
<Stack direction="row" gap={{ mobile: 2, tablet: 1 }} alignItems="center" sx={{ marginLeft: 'auto' }}>
3131
<Stack direction="row" gap={1} alignItems="center">
3232
<Typography variant="bodyXsRegular">{t`Hidden`}:</Typography>
33-
<Typography variant="highlightS">{hiddenMarketCount ?? '-'}</Typography>
33+
<Typography variant="highlightS" data-testid="hidden-market-count">
34+
{hiddenMarketCount ?? '-'}
35+
</Typography>
3436
</Stack>
3537
<ResetFiltersButton onClick={resetFilters} hidden={!hasFilters} />
3638
</Stack>

packages/curve-ui-kit/src/shared/ui/DataTable/hooks/useColumnFilters.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { kebabCase } from 'lodash'
22
import { useCallback, useEffect, useMemo } from 'react'
3-
import { type PartialRecord, recordValues } from '@curvefi/prices-api/objects.util'
3+
import { notFalsy, type PartialRecord, recordValues } from '@curvefi/prices-api/objects.util'
44
import { useSearchParams } from '@ui-kit/hooks/router'
55

66
// Similar to `ColumnFiltersState` from react-table, but more specific to have only string values (they are saved in url)
@@ -29,7 +29,7 @@ const setColumnFilter = <TColumnId extends string>(id: TColumnId, value: string
2929
const { history, location } = window // avoid depending on the router so we can keep the function identity stable
3030
const params = new URLSearchParams([
3131
...[...new URLSearchParams(location.search).entries()].filter(([key]) => key !== id),
32-
...((value ?? '') !== '' ? [[id, value!] as [string, string]] : []),
32+
...notFalsy(value && [id, value]),
3333
])
3434
const search = params.toString().replaceAll('%2C', ',') // keep commas unencoded for better readability
3535
history.pushState(null, '', params.size ? `?${search}` : location.pathname)
@@ -67,15 +67,10 @@ export function useColumnFilters<TColumnId extends string>(
6767
)
6868

6969
const resetFilters = useCallback(() => {
70-
const allowed = new Set(recordValues(columns))
7170
const params = new URLSearchParams(searchParams)
72-
// remove all allowed filter keys
73-
for (const key of allowed) params.delete(key)
74-
// set defaults
75-
defaultFilters?.forEach(({ id, value }) => params.set(id, value))
76-
const pathname = params.size ? `?${params.toString()}` : location.pathname
77-
history.pushState(null, '', pathname)
78-
}, [defaultFilters, columns, searchParams])
71+
recordValues(columns).forEach((key) => params.delete(key))
72+
history.pushState(null, '', params.size ? `?${params.toString()}` : location.pathname)
73+
}, [columns, searchParams])
7974

8075
return [columnFilters, columnFiltersById, setColumnFilter, resetFilters] as const
8176
}

tests/cypress/e2e/main/dex-markets.cy.ts

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { orderBy } from 'lodash'
22
import { oneOf } from '@cy/support/generators'
33
import { setShowSmallPools } from '@cy/support/helpers/user-profile'
4-
import { API_LOAD_TIMEOUT, type Breakpoint, LOAD_TIMEOUT, oneViewport } from '@cy/support/ui'
4+
import { API_LOAD_TIMEOUT, type Breakpoint, LOAD_TIMEOUT, oneMobileViewport } from '@cy/support/ui'
55

66
const PATH = '/dex/arbitrum/pools/'
77

@@ -22,12 +22,16 @@ function parseCompactUsd(value: string): number {
2222
return num * 10 ** (unitIndex * 3)
2323
}
2424

25-
function visitAndWait(width: number, height: number, options?: { page?: number } & Partial<Cypress.VisitOptions>) {
25+
function visitAndWait(
26+
width: number,
27+
height: number,
28+
options?: { query?: Record<string, string> } & Partial<Cypress.VisitOptions>,
29+
) {
2630
cy.viewport(width, height)
27-
const { page } = options ?? {}
28-
cy.visit(`${PATH}${page ? `?page=${page}` : ''}`, options)
31+
const { query } = options ?? {}
32+
cy.visit(`${PATH}${query ? `?${new URLSearchParams(query)}` : ''}`, options)
2933
cy.get('[data-testid^="data-table-row-"]', API_LOAD_TIMEOUT).should('have.length.greaterThan', 0)
30-
if (page) {
34+
if (query?.['page']) {
3135
cy.get('[data-testid="table-pagination"]').should('be.visible')
3236
}
3337
}
@@ -53,7 +57,8 @@ describe('DEX Pools', () => {
5357
let width: number, height: number
5458

5559
beforeEach(() => {
56-
;[width, height, breakpoint] = oneViewport()
60+
;[width, height, breakpoint] = [...oneMobileViewport(), 'mobile']
61+
// ;[width, height, breakpoint] = oneViewport()
5762
})
5863

5964
describe('First page', () => {
@@ -75,6 +80,10 @@ describe('DEX Pools', () => {
7580
}
7681
}
7782

83+
/**
84+
* Clicks on the given filter chip, opening the drawer on mobile if needed.
85+
* Not using `withFilterChips` because the drawer closes automatically in this case.
86+
*/
7887
function clickFilterChip(chip: string, isMobile = breakpoint === 'mobile') {
7988
if (isMobile) {
8089
cy.get('[data-testid="btn-drawer-filter-dex-pools"]').click()
@@ -86,15 +95,15 @@ describe('DEX Pools', () => {
8695

8796
it('sorts by volume', () => {
8897
getTopUsdValues('volume').then((vals) => expectOrder(vals, 'desc')) // initial is Volume desc
89-
// initial sort may be present; after sorting ascending, URL should include sort=volume
98+
cy.url().should('not.include', 'volume') // initial sort not in URL
9099
if (breakpoint === 'mobile') return // on mobile, we cannot sort ascending at the moment
91100
sortBy('volume', 'asc')
92101
getTopUsdValues('volume').then((vals) => expectOrder(vals, 'asc'))
93102
cy.url().should('include', 'sort=volume')
94103
})
95104

96105
it('sorts by TVL (desc/asc)', () => {
97-
// check URL reflects sorting changes
106+
cy.url().should('not.include', 'tvl') // initial sort not in URL
98107
sortBy('tvl', 'desc')
99108
getTopUsdValues('tvl').then((vals) => expectOrder(vals, 'desc'))
100109
cy.url().should('include', 'sort=-tvl')
@@ -106,31 +115,21 @@ describe('DEX Pools', () => {
106115

107116
it('filters by currency chip', () => {
108117
const currency = oneOf('usd', 'btc')
109-
cy.get('[data-testid^="data-table-row-"]').then(($before) => {
110-
const beforeCount = $before.length
118+
const getHiddenCount = () =>
119+
withFilterChips(() => cy.get('[data-testid="hidden-market-count"]').then(([{ innerText }]) => innerText))
120+
121+
getHiddenCount().then((beforeCount) => {
122+
expect(isNaN(+beforeCount), `Cannot parse hidden count ${beforeCount}`).to.be.false
111123
clickFilterChip(currency)
112-
cy.url().should('include', `filter=${currency}`)
113-
cy.get('[data-testid^="data-table-row-"]').then(($after) => {
114-
const afterCount = $after.length
115-
expect(afterCount).to.be.lessThan(beforeCount)
116-
// chip is in the drawer for mobile, check on desktop only
117-
if (breakpoint !== 'mobile') cy.get(`[data-testid="filter-chip-${currency}"]`).contains(`(${afterCount})`)
124+
getHiddenCount().then((afterCount) => {
125+
expect(+afterCount).to.be.greaterThan(+beforeCount)
126+
// chip is in the drawer for mobile, check on desktop that we show count
127+
if (breakpoint !== 'mobile') cy.get(`[data-testid="filter-chip-${currency}"]`).contains(/\(\d+\)/)
118128
})
119129
cy.get('[data-testid="data-table-cell-PoolName"]').contains(currency.toUpperCase())
120130
})
121131
})
122132

123-
it('persists currency filter across reload', () => {
124-
const currency = oneOf('usd', 'btc')
125-
const currencyUpper = currency.toUpperCase()
126-
cy.viewport(width, height)
127-
cy.visit(`${PATH}?filter=${currency}`)
128-
cy.get('[data-testid^="data-table-row-"]', API_LOAD_TIMEOUT).should('have.length.greaterThan', 0)
129-
cy.url().should('include', `filter=${currency}`)
130-
// Verify content reflects the filter
131-
cy.get('[data-testid="data-table-cell-PoolName"]').first().contains(currencyUpper)
132-
})
133-
134133
it('navigates to pool deposit page by clicking a row', () => {
135134
cy.get('[data-testid^="data-table-row-"]').first().click()
136135
if (breakpoint === 'mobile') {
@@ -142,13 +141,23 @@ describe('DEX Pools', () => {
142141
})
143142
})
144143

144+
it('persists currency filter across reload', () => {
145+
const filter = oneOf('usd', 'btc')
146+
visitAndWait(width, height, { query: { filter } })
147+
cy.get('[data-testid^="data-table-row-"]', API_LOAD_TIMEOUT).should('have.length.greaterThan', 0)
148+
cy.url().should('include', `filter=${filter}`)
149+
cy.get('[data-testid="data-table-cell-PoolName"]').first().contains(filter.toUpperCase())
150+
withFilterChips(() => cy.get(`[data-testid="reset-filter"]`).click())
151+
cy.url().should('not.include', '?')
152+
})
153+
145154
it('paginates', () => {
146155
const getPages = ($buttons: JQuery) =>
147156
Cypress.$.makeArray($buttons).map((el) => el.dataset.testid?.replace('btn-page-', ''))
148157

149158
// open page 5 (1-based)
150159
visitAndWait(width, height, {
151-
page: 5,
160+
query: { page: '5' },
152161
// show small pools so we have more pages to test with, and the tests are more stable
153162
onBeforeLoad: (win) => setShowSmallPools(win.localStorage),
154163
})
@@ -186,4 +195,18 @@ describe('DEX Pools', () => {
186195
)
187196
})
188197
})
198+
199+
/**
200+
* Makes sure that the filter chips are visible during the given callback.
201+
* On mobile, the filters are hidden behind a drawer and need to be expanded for some actions.
202+
*/
203+
function withFilterChips(callback: () => Cypress.Chainable, isMobile = breakpoint === 'mobile') {
204+
if (!isMobile) return callback()
205+
cy.get('[data-testid="btn-drawer-filter-dex-pools"]').click()
206+
cy.get('[data-testid="drawer-filter-menu-dex-pools"]').should('be.visible')
207+
return callback().then((result) => {
208+
cy.get('body').click(0, 0)
209+
return cy.wrap(result)
210+
})
211+
}
189212
})

0 commit comments

Comments
 (0)