101. How would you test a sortable, paginated data table?
The table renders ten rows per page from a 27-record fixture, supports ascending and descending sort by name, exposes column headers and sort state accessibly, and fetches a new page on navigation. Define unit tests for pure ordering, DOM integration tests for header and pagination controls, delayed success and error fixtures, focus behavior, stable-row expectations for duplicate names, browser boundary, and mocked versus real network use. Include a test that a stale page response cannot replace the currently requested page.
I would split the tests by confidence boundary. I would unit test the pure name ordering in both directions, including stable ordering for duplicate names. I would render the real table for header sorting, pagination, accessible sort state, loading, errors, keyboard use, and focus. I would use Mock Service Worker for deterministic page responses, including delayed and failed responses. I would also prove that a slow page two response cannot overwrite page three. Finally, I would keep a smaller Playwright test with a real browser and controlled real network path because mocked component tests do not prove the complete browser flow.
This table shows ten records at a time from twenty seven records. A person can sort names, move between pages, and see when new information is loading or when something goes wrong. The tests should check that names appear in the correct order, page controls show the correct records, repeated names keep their original order, and an old request cannot replace newer information. They should also check that a person using a keyboard can reach and use the controls, that focus behaves as expected, and that the current sort direction is communicated clearly.
- Should the selected name sort apply across every requested page or only to rows already loaded in the browser?
- After a page change, which element should receive focus according to the product requirement?
- Is there already a controlled browser test environment that can use the real network path?
I would start by separating the behavior into confidence boundaries.
First, I would unit test the pure sortRows logic. I would use explicit rows with different names and duplicate names. I would verify ascending order, descending order, and stability. Stability means that two rows with the same name keep their original relative order. This test does not need a DOM or network.
Next, I would render the real DataTable component for DOM integration tests. The fixture contains twenty seven records, and the table shows ten rows on each page. I would interact with the component through accessible roles and names rather than private state or component methods.
For header sorting, I would activate the Name column header once and verify ascending row order. I would activate the same header again and verify descending order. I would also assert that the column header exposes the correct accessible sort state after each action.
For pagination, I would begin on page one. I would verify that Previous is disabled there. I would activate Next or page two, verify that the component requests page two with the expected page, page size, sort key, and sort direction values, and then verify that the page two rows become visible. With twenty seven records and ten rows on each page, the interface has three pages.
For most component tests, I would keep the real component request code and replace only the network boundary with Mock Service Worker. The handlers would return the fixture data requested by the component. I would create normal success, delayed success, and error handlers. This keeps the tests deterministic while still exercising the component request flow.
For delayed success, I would verify that the loading state appears while the response is pending and that the expected rows appear when the response completes. For the error handler, I would verify that the visible error state appears. I would wait for observable conditions with Testing Library utilities instead of using a fixed sleep.
The most important asynchronous edge case is the stale response test. I would make page two respond slowly and page three respond faster. I would request page two and then quickly request page three. Each request would receive an increasing request identifier. Page three would finish first and become visible. I would then allow the old page two response to finish. The component must apply a response only when its request identifier equals the latest request identifier. The final assertion is that page three data remains visible and the late page two response does not replace it.
I would also test keyboard and focus behavior. A keyboard user should be able to reach the sortable header and pagination controls in a logical order. Activating the header with the keyboard should change the sort and accessible sort state. Activating a pagination control should update the page and move focus to the product defined target. The test should verify visible focus and the expected focus target rather than guessing from internal implementation.
The example test stack shown by this design uses Vitest with Testing Library and userEvent for component behavior, Mock Service Worker for the controlled request boundary, and Playwright for a smaller end to end browser test. An axe based accessibility check can catch common automated accessibility problems, but it does not replace the keyboard and focus assertions.
The Playwright test should use a real browser and a controlled test service. It should exercise a complete user flow such as sorting by name, moving through the pages, and checking the visible rows. This layer gives browser and real network confidence that the mocked component tests cannot provide. It should not depend on production systems or production user data.
After every component test, I would reset Mock Service Worker handlers, clear any mocks or timers that were changed, unmount the rendered component, and restore changed browser state. Each test should create independent fixture state so test order cannot affect the result.
This gives a useful balance. Unit tests make pure ordering failures easy to diagnose. DOM tests give strong coverage of visible sorting, pagination, accessibility, loading, errors, focus, and stale response protection. A small real browser layer then checks the complete flow without making every test slow or dependent on real network behavior.
- Define the visible behavior. The table shows ten rows on each page from twenty seven records, sorts by name in both directions, exposes accessible sort state, changes pages, handles loading and errors, supports keyboard and focus behavior, keeps duplicate names stable, and blocks stale responses.
- Unit test sortRows with explicit records. Verify ascending order, descending order, and stable relative order when names are equal.
- Render the real DataTable for DOM integration tests. Find the Name header and pagination controls with accessible queries.
- Configure Mock Service Worker handlers that return the requested fixture page. Add success, delayed success, error, and controlled race behavior.
- Test sorting. Activate the Name header once and assert ascending order and accessible sort state. Activate it again and assert descending order and the updated accessible sort state.
- Test pagination. Verify Previous is disabled on page one. Request page two and assert the expected request parameters and visible page two rows.
- Test delayed success and error behavior. Assert loading while the delayed response is pending, rows after success, and a visible error after failure.
- Test the stale response guard. Give page two a slow response and page three a faster response. Request page two and then page three. Apply page three first, release page two later, and assert that page three remains visible because only the latest request identifier may update the table.
- Test keyboard and focus behavior. Reach the header and pagination controls with the keyboard, activate them, and assert the accessible state and product defined focus target.
- Run a smaller Playwright test in a real browser with a controlled test service. Cover a complete flow that sorts and moves through pages.
- Reset request handlers, mocks, timers, rendered DOM, and changed browser state so every test remains independent.
Interviewers ask this to see whether I can separate pure ordering logic from visible component behavior and real browser behavior. They also want to see whether I choose a useful network boundary, control asynchronous work reliably, test accessibility and focus, keep duplicate rows stable, and prevent an older page response from replacing the page the user most recently requested.
Common mistakes include testing private component state instead of visible behavior, mocking the component request logic instead of the network boundary, using a live production service in normal component tests, using fixed sleep calls, forgetting stable ordering for duplicate names, checking only successful requests, ignoring keyboard and focus behavior, failing to reset Mock Service Worker handlers, sharing mutable fixtures between tests, and forgetting that a slow older page response can arrive after the newest response and incorrectly replace the current rows.
Explain the boundaries in order. Start with pure sorting, then the rendered table, then the controlled Mock Service Worker network boundary, and finally the smaller real browser test. Call out the stale response race because it shows production awareness. Also state clearly that mocked component tests give deterministic coverage but do not prove the complete real browser and network path.








