- boardStore.js: refactored from per-component useState to a module-level
singleton via useSyncExternalStore. All callers share state (true
singleton). Exposes __resetStore/__setState/__setPersistOnChange for
test isolation. addBoard/addList/addCard still return the new id
(computed from post-action state).
- jest.config.js: added moduleNameMapper for CSS (identity-obj-proxy)
+ transformIgnorePatterns for @dnd-kit ESM modules.
- jest.setup.js: stub window.matchMedia for AppShell, clear localStorage
+ reset store singleton before each test.
- src/test/testUtils.jsx: renderWithStore now wraps the UI in a Host
that calls useBoardStore and clones the child element to inject
{ state, actions } as props. Returns result.state/result.actions
getters so tests can read state and invoke actions from outside.
- src/components/List.test.jsx: Host accepts state/actions props and
falls back to useBoardStore for standalone use.
- src/components/ListHeader.test.jsx + Board.test.jsx: updated to new
result.state API (was store.getState() in P3's API).
- src/App.jsx: final spec wiring — sidebar + board area + TopBar + Board
+ empty states (first-run + select-board). Reads from useBoardStore,
passes state + actions down to AppShell + Board.
- src/App.test.jsx: smoke test — sidebar + topbar + board + lists render
when seeded; +Create board flow creates a board and activates it;
first-run and select-board empty states render correctly; mobile
breakpoint shows hamburger.
All 119 tests pass across 15 suites. npm run build green.
31 lines
1.0 KiB
JavaScript
31 lines
1.0 KiB
JavaScript
import '@testing-library/jest-dom';
|
|
import { __resetStore } from './src/store/boardStore'
|
|
|
|
// jsdom doesn't implement window.matchMedia. AppShell uses it to detect
|
|
// mobile breakpoints. Stub a no-op implementation that always reports
|
|
// desktop (matches=false) unless a test explicitly overrides it.
|
|
if (typeof window !== 'undefined' && !window.matchMedia) {
|
|
Object.defineProperty(window, 'matchMedia', {
|
|
writable: true,
|
|
value: (query) => ({
|
|
matches: false,
|
|
media: query,
|
|
onchange: null,
|
|
addListener: () => {}, // deprecated
|
|
removeListener: () => {}, // deprecated
|
|
addEventListener: () => {},
|
|
removeEventListener: () => {},
|
|
dispatchEvent: () => false,
|
|
}),
|
|
})
|
|
}
|
|
|
|
// The board store is a module-level singleton. Reset it before every test
|
|
// so tests don't leak state into each other. localStorage is also cleared
|
|
// because the store seeds from localStorage on first read.
|
|
beforeEach(() => {
|
|
if (typeof window !== 'undefined' && window.localStorage) {
|
|
window.localStorage.clear()
|
|
}
|
|
__resetStore()
|
|
}) |