mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-04-27 07:48:01 -07:00
implement gameboard v1
This commit is contained in:
parent
b103db681b
commit
0d7336edc2
177 changed files with 16995 additions and 139 deletions
|
|
@ -1,4 +1,10 @@
|
|||
export { withMockLocation } from './globalGuards';
|
||||
export { renderWithProviders } from './renderWithProviders';
|
||||
export { createMockWebClient } from './mockWebClient';
|
||||
export { disconnectedState, connectedState, connectedWithRoomsState, makeUser } from './storeFixtures';
|
||||
export {
|
||||
disconnectedState,
|
||||
connectedState,
|
||||
connectedWithRoomsState,
|
||||
makeStoreState,
|
||||
makeUser,
|
||||
} from './storeFixtures';
|
||||
|
|
|
|||
|
|
@ -34,10 +34,43 @@ export function createMockWebClient() {
|
|||
leaveRoom: vi.fn(),
|
||||
roomSay: vi.fn(),
|
||||
createGame: vi.fn(),
|
||||
joinGame: vi.fn(),
|
||||
},
|
||||
game: {
|
||||
joinGame: vi.fn(),
|
||||
leaveGame: vi.fn(),
|
||||
kickFromGame: vi.fn(),
|
||||
gameSay: vi.fn(),
|
||||
readyStart: vi.fn(),
|
||||
concede: vi.fn(),
|
||||
unconcede: vi.fn(),
|
||||
judge: vi.fn(),
|
||||
nextTurn: vi.fn(),
|
||||
setActivePhase: vi.fn(),
|
||||
reverseTurn: vi.fn(),
|
||||
moveCard: vi.fn(),
|
||||
flipCard: vi.fn(),
|
||||
attachCard: vi.fn(),
|
||||
createToken: vi.fn(),
|
||||
setCardAttr: vi.fn(),
|
||||
setCardCounter: vi.fn(),
|
||||
incCardCounter: vi.fn(),
|
||||
drawCards: vi.fn(),
|
||||
undoDraw: vi.fn(),
|
||||
createArrow: vi.fn(),
|
||||
deleteArrow: vi.fn(),
|
||||
createCounter: vi.fn(),
|
||||
setCounter: vi.fn(),
|
||||
incCounter: vi.fn(),
|
||||
delCounter: vi.fn(),
|
||||
shuffle: vi.fn(),
|
||||
dumpZone: vi.fn(),
|
||||
revealCards: vi.fn(),
|
||||
changeZoneProperties: vi.fn(),
|
||||
deckSelect: vi.fn(),
|
||||
setSideboardPlan: vi.fn(),
|
||||
setSideboardLock: vi.fn(),
|
||||
mulligan: vi.fn(),
|
||||
rollDie: vi.fn(),
|
||||
},
|
||||
admin: {
|
||||
adjustMod: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -6,13 +6,25 @@ import { MemoryRouter } from 'react-router-dom';
|
|||
import { I18nextProvider } from 'react-i18next';
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import { DndContext } from '@dnd-kit/core';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
|
||||
import { gamesReducer } from '../store/game';
|
||||
import { roomsReducer } from '../store/rooms';
|
||||
import { serverReducer } from '../store/server';
|
||||
import { actionReducer } from '../store/actions';
|
||||
// Disables MUI's ripple animation in tests. The ripple fires a deferred
|
||||
// state update after clicks/focus that would otherwise trigger a noisy
|
||||
// "update to ForwardRef(TouchRipple) was not wrapped in act(...)" warning.
|
||||
const testTheme = createTheme({
|
||||
components: {
|
||||
MuiButtonBase: { defaultProps: { disableRipple: true } },
|
||||
},
|
||||
});
|
||||
|
||||
import { WebClientContext } from '../hooks/useWebClient';
|
||||
import type { WebClient } from '../websocket';
|
||||
import rootReducer from '../store/rootReducer';
|
||||
import { ToastProvider } from '../components/Toast/ToastContext';
|
||||
import { storeMiddlewareOptions } from '../store/store';
|
||||
import type { RootState } from '../store/store';
|
||||
import { createMockWebClient } from './mockWebClient';
|
||||
|
||||
// Non-empty `resources` registers en-US so `resolvedLanguage` is defined;
|
||||
// without it MUI warns about out-of-range Select values.
|
||||
|
|
@ -24,15 +36,18 @@ testI18n.use(initReactI18next).init({
|
|||
interpolation: { escapeValue: false },
|
||||
});
|
||||
|
||||
// `configureStore`'s `preloadedState` wants `PreloadedState<CombinedState<…>>`
|
||||
// which narrows collection types past our slice interfaces. A single cast
|
||||
// here keeps the test harness loose (each test injects only the slices it
|
||||
// cares about) while specs themselves stay strict via `makeStoreState`.
|
||||
function createTestStore(preloadedState?: Partial<RootState>) {
|
||||
return configureStore({
|
||||
reducer: {
|
||||
games: gamesReducer,
|
||||
rooms: roomsReducer,
|
||||
server: serverReducer,
|
||||
action: actionReducer,
|
||||
},
|
||||
preloadedState: preloadedState as any,
|
||||
reducer: rootReducer,
|
||||
preloadedState: preloadedState as Parameters<typeof configureStore>[0]['preloadedState'],
|
||||
// Share the production middleware config so the serializableCheck
|
||||
// tolerates protobuf messages (isMessage) the same way the real store
|
||||
// does — otherwise every proto-payload dispatch in tests spams stderr.
|
||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware(storeMiddlewareOptions),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -40,6 +55,7 @@ interface ExtendedRenderOptions extends Omit<RenderOptions, 'wrapper'> {
|
|||
preloadedState?: Partial<RootState>;
|
||||
store?: EnhancedStore;
|
||||
route?: string;
|
||||
webClient?: WebClient;
|
||||
}
|
||||
|
||||
export function renderWithProviders(
|
||||
|
|
@ -48,6 +64,7 @@ export function renderWithProviders(
|
|||
preloadedState,
|
||||
store = createTestStore(preloadedState),
|
||||
route = '/',
|
||||
webClient = createMockWebClient(),
|
||||
...renderOptions
|
||||
}: ExtendedRenderOptions = {},
|
||||
) {
|
||||
|
|
@ -55,11 +72,21 @@ export function renderWithProviders(
|
|||
return (
|
||||
<Provider store={store}>
|
||||
<I18nextProvider i18n={testI18n}>
|
||||
<ToastProvider>
|
||||
<MemoryRouter initialEntries={[route]}>
|
||||
{children}
|
||||
</MemoryRouter>
|
||||
</ToastProvider>
|
||||
<ThemeProvider theme={testTheme}>
|
||||
<ToastProvider>
|
||||
<MemoryRouter initialEntries={[route]}>
|
||||
<WebClientContext value={webClient}>
|
||||
<DndContext
|
||||
accessibility={{
|
||||
screenReaderInstructions: { draggable: '' },
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DndContext>
|
||||
</WebClientContext>
|
||||
</MemoryRouter>
|
||||
</ToastProvider>
|
||||
</ThemeProvider>
|
||||
</I18nextProvider>
|
||||
</Provider>
|
||||
);
|
||||
|
|
@ -67,6 +94,7 @@ export function renderWithProviders(
|
|||
|
||||
return {
|
||||
store,
|
||||
webClient,
|
||||
...render(ui, { wrapper: Wrapper, ...renderOptions }),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ export const disconnectedState: Partial<RootState> = {
|
|||
messages: {},
|
||||
sortGamesBy: { field: App.GameSortField.START_TIME, order: App.SortDirection.DESC },
|
||||
sortUsersBy: { field: App.UserSortField.NAME, order: App.SortDirection.ASC },
|
||||
selectedGameIds: {},
|
||||
gameFilters: {},
|
||||
},
|
||||
games: { games: {} },
|
||||
action: { type: null, payload: null, meta: null, error: false, count: 0 },
|
||||
|
|
@ -122,3 +124,27 @@ export const connectedWithRoomsState: Partial<RootState> = {
|
|||
};
|
||||
|
||||
export { makeUser };
|
||||
|
||||
/**
|
||||
* Deep-partial of a root state. Let specs pass partial slice shapes
|
||||
* (typically just `games: { games: { ... } }`) without the ~60 fields of
|
||||
* server/rooms that the test doesn't care about.
|
||||
*/
|
||||
type DeepPartial<T> = T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;
|
||||
|
||||
/**
|
||||
* Wraps a partial root-state literal with a safe single `as`-cast so specs
|
||||
* don't need to sprinkle `as any` on every `preloadedState` argument. The
|
||||
* runtime value is the exact same literal; the only thing this helper buys
|
||||
* is deleting the `as any` cast from call sites.
|
||||
*
|
||||
* @example
|
||||
* renderWithProviders(<MyComponent />, {
|
||||
* preloadedState: makeStoreState({
|
||||
* games: { games: { 1: makeGameEntry({ ... }) } },
|
||||
* }),
|
||||
* });
|
||||
*/
|
||||
export function makeStoreState(partial: DeepPartial<RootState>): Partial<RootState> {
|
||||
return partial as Partial<RootState>;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue