-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DataGrid] Improve test coverage of server side data source #15942
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
f57926a
[DataGrid] Improve test coverage of server side data source
MBilalShafi 32b8b36
Merge branch 'master' into test/data-source
MBilalShafi 3a16a18
Lint fix
MBilalShafi 023bf55
Update
MBilalShafi 5b5866f
Merge branch 'master' into test/data-source
MBilalShafi 75bdbda
Improve tests' logic
MBilalShafi 15dd057
Merge branch 'master' into test/data-source
MBilalShafi c984b23
One more test run - just to make sure
MBilalShafi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
282 changes: 282 additions & 0 deletions
282
packages/x-data-grid-pro/src/tests/dataSource.DataGridPro.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,282 @@ | ||
import * as React from 'react'; | ||
import { useMockServer } from '@mui/x-data-grid-generator'; | ||
import { act, createRenderer, waitFor, screen, within } from '@mui/internal-test-utils'; | ||
import { expect } from 'chai'; | ||
import { | ||
DataGridPro, | ||
DataGridProProps, | ||
GridApi, | ||
GridDataSource, | ||
GridDataSourceCache, | ||
GridGetRowsParams, | ||
GridGetRowsResponse, | ||
useGridApiRef, | ||
} from '@mui/x-data-grid-pro'; | ||
import { SinonSpy, spy } from 'sinon'; | ||
import { getKey } from '../hooks/features/dataSource/cache'; | ||
|
||
const isJSDOM = /jsdom/.test(window.navigator.userAgent); | ||
const cache = new Map<string, GridGetRowsResponse>(); | ||
|
||
const testCache: GridDataSourceCache = { | ||
set: (key, value) => cache.set(getKey(key), value), | ||
get: (key) => cache.get(getKey(key)), | ||
clear: () => cache.clear(), | ||
}; | ||
|
||
describe('<DataGridPro /> - Data source', () => { | ||
const { render } = createRenderer(); | ||
|
||
let apiRef: React.MutableRefObject<GridApi>; | ||
let fetchRowsSpy: SinonSpy; | ||
let mockServer: ReturnType<typeof useMockServer>; | ||
|
||
function TestDataSource(props: Partial<DataGridProProps> & { shouldRequestsFail?: boolean }) { | ||
apiRef = useGridApiRef(); | ||
const { shouldRequestsFail = false, ...rest } = props; | ||
mockServer = useMockServer( | ||
{ rowLength: 100, maxColumns: 1 }, | ||
{ useCursorPagination: false, minDelay: 0, maxDelay: 0, verbose: false }, | ||
shouldRequestsFail, | ||
); | ||
fetchRowsSpy = spy(mockServer, 'fetchRows'); | ||
const { fetchRows } = mockServer; | ||
|
||
const dataSource: GridDataSource = React.useMemo( | ||
() => ({ | ||
getRows: async (params: GridGetRowsParams) => { | ||
const urlParams = new URLSearchParams({ | ||
filterModel: JSON.stringify(params.filterModel), | ||
sortModel: JSON.stringify(params.sortModel), | ||
start: `${params.start}`, | ||
end: `${params.end}`, | ||
}); | ||
|
||
const getRowsResponse = await fetchRows( | ||
`https://mui.com/x/api/data-grid?${urlParams.toString()}`, | ||
); | ||
|
||
return { | ||
rows: getRowsResponse.rows, | ||
rowCount: getRowsResponse.rowCount, | ||
}; | ||
}, | ||
}), | ||
[fetchRows], | ||
); | ||
|
||
const baselineProps = { | ||
unstable_dataSource: dataSource, | ||
columns: mockServer.columns, | ||
initialState: { pagination: { paginationModel: { page: 0, pageSize: 10 } } }, | ||
disableVirtualization: true, | ||
}; | ||
|
||
return ( | ||
<div style={{ width: 300, height: 300 }}> | ||
<DataGridPro apiRef={apiRef} {...baselineProps} {...rest} /> | ||
</div> | ||
); | ||
} | ||
|
||
beforeEach(function beforeTest() { | ||
if (isJSDOM) { | ||
this.skip(); // Needs layout | ||
} | ||
|
||
cache.clear(); | ||
}); | ||
|
||
it('should fetch the data on initial render', async () => { | ||
render(<TestDataSource />); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(1); | ||
}); | ||
}); | ||
|
||
it('should re-fetch the data on filter change', async () => { | ||
const { setProps } = render(<TestDataSource />); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(1); | ||
}); | ||
setProps({ filterModel: { items: [{ field: 'name', value: 'John', operator: 'contains' }] } }); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(2); | ||
}); | ||
}); | ||
|
||
it('should re-fetch the data on sort change', async () => { | ||
const { setProps } = render(<TestDataSource />); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(1); | ||
}); | ||
setProps({ sortModel: [{ field: 'name', sort: 'asc' }] }); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(2); | ||
}); | ||
}); | ||
|
||
it('should re-fetch the data on pagination change', async () => { | ||
const { setProps } = render(<TestDataSource />); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(1); | ||
}); | ||
setProps({ paginationModel: { page: 1, pageSize: 10 } }); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(2); | ||
}); | ||
}); | ||
|
||
describe('Cache', () => { | ||
it('should cache the data using the default cache', async () => { | ||
render(<TestDataSource />); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(1); | ||
}); | ||
|
||
const dataRow1 = await screen.findByText( | ||
(_, el) => el?.getAttribute('data-rowindex') === '0', | ||
); | ||
|
||
const cell1 = within(dataRow1).getByRole('gridcell'); | ||
const cell1Content = cell1.innerText; | ||
|
||
act(() => { | ||
apiRef.current.setPage(1); | ||
}); | ||
|
||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(2); | ||
}); | ||
|
||
const dataRow2 = await screen.findByText( | ||
(_, el) => el?.getAttribute('data-rowindex') === '0' && el !== dataRow1, | ||
); | ||
const cell2 = within(dataRow2).getByRole('gridcell'); | ||
const cell2Content = cell2.innerText; | ||
expect(cell2Content).not.to.equal(cell1Content); | ||
|
||
act(() => { | ||
apiRef.current.setPage(0); | ||
}); | ||
|
||
expect(fetchRowsSpy.callCount).to.equal(2); | ||
|
||
const dataRow3 = await screen.findByText( | ||
(_, el) => el?.getAttribute('data-rowindex') === '0' && el !== dataRow1 && el !== dataRow2, | ||
); | ||
const cell3 = within(dataRow3).getByRole('gridcell'); | ||
const cell3Content = cell3.innerText; | ||
expect(cell3Content).to.equal(cell1Content); | ||
}); | ||
|
||
it('should cache the data using the custom cache', async () => { | ||
render(<TestDataSource unstable_dataSourceCache={testCache} />); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(1); | ||
}); | ||
expect(cache.size).to.equal(1); | ||
}); | ||
|
||
it('should use the cached data when the same query is made again', async () => { | ||
render(<TestDataSource unstable_dataSourceCache={testCache} />); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(1); | ||
}); | ||
expect(cache.size).to.equal(1); | ||
|
||
const dataRow1 = await screen.findByText( | ||
(_, el) => el?.getAttribute('data-rowindex') === '0', | ||
); | ||
|
||
const cell1 = within(dataRow1).getByRole('gridcell'); | ||
|
||
const cell1Content = cell1.innerText; | ||
|
||
act(() => { | ||
apiRef.current.setPage(1); | ||
}); | ||
|
||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(2); | ||
}); | ||
expect(cache.size).to.equal(2); | ||
|
||
const dataRow2 = await screen.findByText( | ||
(_, el) => el?.getAttribute('data-rowindex') === '0' && el !== dataRow1, | ||
); | ||
|
||
const cell2 = within(dataRow2).getByRole('gridcell'); | ||
|
||
const cell2Content = cell2.innerText; | ||
expect(cell2Content).not.to.equal(cell1Content); | ||
|
||
act(() => { | ||
apiRef.current.setPage(0); | ||
}); | ||
|
||
const dataRow3 = await screen.findByText( | ||
(_, el) => el?.getAttribute('data-rowindex') === '0' && el !== dataRow1 && el !== dataRow2, | ||
); | ||
|
||
const cell3 = within(dataRow3).getByRole('gridcell'); | ||
|
||
const cell3Content = cell3.innerText; | ||
expect(cell3Content).to.equal(cell1Content); | ||
|
||
expect(fetchRowsSpy.callCount).to.equal(2); | ||
expect(cache.size).to.equal(2); | ||
}); | ||
|
||
it('should allow to disable the default cache', async () => { | ||
// only | ||
render(<TestDataSource unstable_dataSourceCache={null} />); | ||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(1); | ||
}); | ||
|
||
const dataRow1 = await screen.findByText( | ||
(_, el) => el?.getAttribute('data-rowindex') === '0', | ||
); | ||
|
||
const cell1 = within(dataRow1).getByRole('gridcell'); | ||
|
||
const cell1Content = cell1.innerText; | ||
|
||
act(() => { | ||
apiRef.current.setPage(1); | ||
}); | ||
|
||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(2); | ||
}); | ||
|
||
const dataRow2 = await screen.findByText( | ||
(_, el) => el?.getAttribute('data-rowindex') === '0' && el !== dataRow1, | ||
); | ||
|
||
const cell2 = within(dataRow2).getByRole('gridcell'); | ||
|
||
const cell2Content = cell2.innerText; | ||
expect(cell2Content).not.to.equal(cell1Content); | ||
|
||
act(() => { | ||
apiRef.current.setPage(0); | ||
}); | ||
|
||
await waitFor(() => { | ||
expect(fetchRowsSpy.callCount).to.equal(3); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('Error handling', () => { | ||
it('should call `unstable_onDataSourceError` when the data source returns an error', async () => { | ||
const onDataSourceError = spy(); | ||
render(<TestDataSource unstable_onDataSourceError={onDataSourceError} shouldRequestsFail />); | ||
await waitFor(() => { | ||
expect(onDataSourceError.callCount).to.equal(1); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @arminmeh for the test bed introduced in lazy loading PR, I reused it here.