mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-13 01:24:46 -07:00
upgrade packages
This commit is contained in:
parent
c62c336a11
commit
ae1bc3da38
30 changed files with 1138 additions and 1783 deletions
2181
webclient/package-lock.json
generated
2181
webclient/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -21,25 +21,25 @@
|
||||||
"@bufbuild/protobuf": "^2.11.0",
|
"@bufbuild/protobuf": "^2.11.0",
|
||||||
"@emotion/react": "^11.8.2",
|
"@emotion/react": "^11.8.2",
|
||||||
"@emotion/styled": "^11.8.1",
|
"@emotion/styled": "^11.8.1",
|
||||||
"@mui/icons-material": "^7.3.10",
|
"@mui/icons-material": "^9.0.0",
|
||||||
"@mui/material": "^7.3.10",
|
"@mui/material": "^9.0.0",
|
||||||
"@reduxjs/toolkit": "^2.11.2",
|
"@reduxjs/toolkit": "^2.11.2",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dexie": "^4.4.2",
|
"dexie": "^4.4.2",
|
||||||
"dompurify": "^3.3.3",
|
"dompurify": "^3.4.0",
|
||||||
"final-form": "^5.0.0",
|
"final-form": "^5.0.0",
|
||||||
"final-form-set-field-touched": "^1.0.1",
|
"final-form-set-field-touched": "^1.0.1",
|
||||||
"i18next": "^26.0.4",
|
"i18next": "^26.0.5",
|
||||||
"i18next-browser-languagedetector": "^8.2.1",
|
"i18next-browser-languagedetector": "^8.2.1",
|
||||||
"i18next-icu": "^2.0.3",
|
"i18next-icu": "^2.0.3",
|
||||||
"intl-messageformat": "^11.2.1",
|
"intl-messageformat": "^11.2.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^18.2.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-final-form": "^7.0.0",
|
"react-final-form": "^7.0.0",
|
||||||
"react-final-form-listeners": "^3.0.0",
|
"react-final-form-listeners": "^3.0.0",
|
||||||
"react-i18next": "^17.0.2",
|
"react-i18next": "^17.0.3",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-router-dom": "^7.14.1",
|
"react-router-dom": "^7.14.1",
|
||||||
"react-virtualized-auto-sizer": "^2.0.3",
|
"react-virtualized-auto-sizer": "^2.0.3",
|
||||||
|
|
@ -47,10 +47,10 @@
|
||||||
"rxjs": "^7.5.4"
|
"rxjs": "^7.5.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@bufbuild/buf": "^1.67.0",
|
"@bufbuild/buf": "^1.68.1",
|
||||||
"@bufbuild/protoc-gen-es": "^2.11.0",
|
"@bufbuild/protoc-gen-es": "^2.11.0",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@mui/types": "^7.1.3",
|
"@mui/types": "^9.0.0",
|
||||||
"@testing-library/dom": "^10.4.1",
|
"@testing-library/dom": "^10.4.1",
|
||||||
"@testing-library/jest-dom": "^6.4.0",
|
"@testing-library/jest-dom": "^6.4.0",
|
||||||
"@testing-library/react": "^16.3.2",
|
"@testing-library/react": "^16.3.2",
|
||||||
|
|
@ -58,23 +58,22 @@
|
||||||
"@types/lodash": "^4.14.179",
|
"@types/lodash": "^4.14.179",
|
||||||
"@types/node": "^22.19.17",
|
"@types/node": "^22.19.17",
|
||||||
"@types/prop-types": "^15.7.4",
|
"@types/prop-types": "^15.7.4",
|
||||||
"@types/react": "18.0.24",
|
"@types/react": "^19.0.0",
|
||||||
"@types/react-dom": "18.0.8",
|
"@types/react-dom": "^19.0.0",
|
||||||
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
"@types/react-virtualized-auto-sizer": "^1.0.1",
|
||||||
"@types/react-window": "^1.8.5",
|
"@types/react-window": "^1.8.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.58.2",
|
"@typescript-eslint/eslint-plugin": "^8.58.2",
|
||||||
"@typescript-eslint/parser": "^8.58.2",
|
"@typescript-eslint/parser": "^8.58.2",
|
||||||
"@vitejs/plugin-react": "^5.2.0",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
"@vitest/coverage-v8": "^4.1.4",
|
"@vitest/coverage-v8": "^4.1.4",
|
||||||
"eslint": "^10.2.0",
|
"eslint": "^10.2.0",
|
||||||
"fs-extra": "^11.3.4",
|
"fs-extra": "^11.3.4",
|
||||||
"globals": "^17.5.0",
|
"globals": "^17.5.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"jsdom": "^29.0.2",
|
"jsdom": "^29.0.2",
|
||||||
"typescript": "~5.8",
|
"typescript": "~6.0",
|
||||||
"typescript-eslint": "^8.58.2",
|
"typescript-eslint": "^8.58.2",
|
||||||
"vite": "^6.4.2",
|
"vite": "^8.0.8",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
|
||||||
"vitest": "^4.1.4"
|
"vitest": "^4.1.4"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
|
|
|
||||||
48
webclient/src/__test-utils__/globalGuards.ts
Normal file
48
webclient/src/__test-utils__/globalGuards.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Shared lifecycle helpers for test files that need to mutate global state.
|
||||||
|
//
|
||||||
|
// The root `setupTests.ts` guards catch leaks even when callers forget to
|
||||||
|
// clean up, but opt-in helpers make intent explicit at the call site and
|
||||||
|
// avoid piling cleanup logic onto the shared safety net.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporarily override fields on `window.location` and return a restore fn.
|
||||||
|
*
|
||||||
|
* `Object.defineProperty(window, 'location', ...)` is not a `vi.spyOn` target,
|
||||||
|
* so `vi.restoreAllMocks()` will NOT undo it. Always pair with the returned
|
||||||
|
* `restore` callback (ideally in `afterEach`).
|
||||||
|
*/
|
||||||
|
export function withMockLocation(overrides: Partial<Location>): () => void {
|
||||||
|
const originalDescriptor = Object.getOwnPropertyDescriptor(window, 'location');
|
||||||
|
|
||||||
|
Object.defineProperty(window, 'location', {
|
||||||
|
value: { ...window.location, ...overrides },
|
||||||
|
writable: true,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (originalDescriptor) {
|
||||||
|
Object.defineProperty(window, 'location', originalDescriptor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push an entry onto a shared event-handler registry array and return a
|
||||||
|
* teardown function that removes exactly that entry.
|
||||||
|
*
|
||||||
|
* Used by ProtobufService specs which install temporary handlers into the
|
||||||
|
* (mocked) `GameEvents` / `RoomEvents` / `SessionEvents` arrays. Manual
|
||||||
|
* `.push()`/`.pop()` inside a test body corrupts the array if an assertion
|
||||||
|
* throws between them — this helper makes the teardown safe to run in
|
||||||
|
* `afterEach`.
|
||||||
|
*/
|
||||||
|
export function withEventRegistry<T>(registry: T[], entry: T): () => void {
|
||||||
|
registry.push(entry);
|
||||||
|
return () => {
|
||||||
|
const index = registry.lastIndexOf(entry);
|
||||||
|
if (index !== -1) {
|
||||||
|
registry.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
1
webclient/src/__test-utils__/index.ts
Normal file
1
webclient/src/__test-utils__/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { withMockLocation, withEventRegistry } from './globalGuards';
|
||||||
|
|
@ -1,42 +1,40 @@
|
||||||
import { Component, CElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
import Grid from '@mui/material/Grid';
|
import Grid from '@mui/material/Grid';
|
||||||
|
|
||||||
import './ThreePaneLayout.css';
|
import './ThreePaneLayout.css';
|
||||||
|
|
||||||
// @DEPRECATED
|
// @DEPRECATED
|
||||||
// This component sucks balls, dont use it. It will be removed sooner than later.
|
// This component sucks balls, dont use it. It will be removed sooner than later.
|
||||||
class ThreePaneLayout extends Component<ThreePaneLayoutProps> {
|
function ThreePaneLayout(props: ThreePaneLayoutProps) {
|
||||||
render() {
|
return (
|
||||||
return (
|
<div className="three-pane-layout">
|
||||||
<div className="three-pane-layout">
|
<Grid container rowSpacing={0} columnSpacing={2} className="grid">
|
||||||
<Grid container rowSpacing={0} columnSpacing={2} className="grid">
|
<Grid size={{ xs: 12, md: 9, lg: 10 }} className="grid-main">
|
||||||
<Grid size={{ xs: 12, md: 9, lg: 10 }} className="grid-main">
|
<Grid className={
|
||||||
<Grid className={
|
'grid-main__top'
|
||||||
'grid-main__top'
|
+ (props.fixedHeight ? ' fixedHeight' : '')
|
||||||
+ (this.props.fixedHeight ? ' fixedHeight' : '')
|
}>
|
||||||
}>
|
{props.top}
|
||||||
{this.props.top}
|
|
||||||
</Grid>
|
|
||||||
<Grid className={
|
|
||||||
'grid-main__bottom'
|
|
||||||
+ (this.props.fixedHeight ? ' fixedHeight' : '')
|
|
||||||
}>
|
|
||||||
{this.props.bottom}
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid size={{ md: 3, lg: 2 }} sx={{ display: { xs: 'none', md: 'block' } }} className="grid-side">
|
<Grid className={
|
||||||
{this.props.side}
|
'grid-main__bottom'
|
||||||
|
+ (props.fixedHeight ? ' fixedHeight' : '')
|
||||||
|
}>
|
||||||
|
{props.bottom}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
<Grid size={{ md: 3, lg: 2 }} sx={{ display: { xs: 'none', md: 'block' } }} className="grid-side">
|
||||||
);
|
{props.side}
|
||||||
}
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ThreePaneLayoutProps {
|
interface ThreePaneLayoutProps {
|
||||||
top: CElement<any, any>,
|
top: ReactElement,
|
||||||
bottom: CElement<any, any>,
|
bottom: ReactElement,
|
||||||
side?: CElement<any, any>,
|
side?: ReactElement,
|
||||||
fixedHeight?: boolean,
|
fixedHeight?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import { createPortal } from 'react-dom'
|
||||||
|
|
||||||
import Alert from '@mui/material/Alert';
|
import Alert from '@mui/material/Alert';
|
||||||
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||||
|
|
@ -46,7 +46,7 @@ function Toast(props) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReactDOM.createPortal(
|
return createPortal(
|
||||||
node,
|
node,
|
||||||
rootElemRef.current
|
rootElemRef.current
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, Suspense } from 'react';
|
import { Suspense, useEffect } from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { MemoryRouter as Router } from 'react-router-dom';
|
import { MemoryRouter as Router } from 'react-router-dom';
|
||||||
import CssBaseline from '@mui/material/CssBaseline';
|
import CssBaseline from '@mui/material/CssBaseline';
|
||||||
|
|
@ -10,33 +10,31 @@ import './AppShell.css';
|
||||||
|
|
||||||
import { ToastProvider } from '@app/components'
|
import { ToastProvider } from '@app/components'
|
||||||
|
|
||||||
class AppShell extends Component {
|
function AppShell() {
|
||||||
componentDidMount() {
|
useEffect(() => {
|
||||||
// @TODO (1)
|
// @TODO (1)
|
||||||
window.onbeforeunload = () => true;
|
window.onbeforeunload = () => true;
|
||||||
}
|
}, []);
|
||||||
|
|
||||||
handleContextMenu(event) {
|
const handleContextMenu = (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
return (
|
||||||
return (
|
<Suspense fallback="loading">
|
||||||
<Suspense fallback="loading">
|
<Provider store={store}>
|
||||||
<Provider store={store}>
|
<CssBaseline />
|
||||||
<CssBaseline />
|
<ToastProvider>
|
||||||
<ToastProvider>
|
<div className="AppShell" onContextMenu={handleContextMenu}>
|
||||||
<div className="AppShell" onContextMenu={this.handleContextMenu}>
|
<Router>
|
||||||
<Router>
|
<FeatureDetection />
|
||||||
<FeatureDetection />
|
<Routes />
|
||||||
<Routes />
|
</Router>
|
||||||
</Router>
|
</div>
|
||||||
</div>
|
</ToastProvider>
|
||||||
</ToastProvider>
|
</Provider>
|
||||||
</Provider>
|
</Suspense>
|
||||||
</Suspense>
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AppShell;
|
export default AppShell;
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,15 @@
|
||||||
// eslint-disable-next-line
|
|
||||||
import React, { Component } from "react";
|
|
||||||
|
|
||||||
import { AuthGuard } from '@app/components';
|
import { AuthGuard } from '@app/components';
|
||||||
import Layout from '../Layout/Layout';
|
import Layout from '../Layout/Layout';
|
||||||
|
|
||||||
import './Decks.css';
|
import './Decks.css';
|
||||||
|
|
||||||
class Decks extends Component {
|
function Decks() {
|
||||||
render() {
|
return (
|
||||||
return (
|
<Layout>
|
||||||
<Layout>
|
<AuthGuard />
|
||||||
<AuthGuard />
|
<span>"Decks"</span>
|
||||||
<span>"Decks"</span>
|
</Layout>
|
||||||
</Layout>
|
);
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Decks;
|
export default Decks;
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,15 @@
|
||||||
// eslint-disable-next-line
|
|
||||||
import React, { Component } from "react";
|
|
||||||
|
|
||||||
import { AuthGuard } from '@app/components';
|
import { AuthGuard } from '@app/components';
|
||||||
import Layout from '../Layout/Layout';
|
import Layout from '../Layout/Layout';
|
||||||
|
|
||||||
import './Game.css';
|
import './Game.css';
|
||||||
|
|
||||||
class Game extends Component {
|
function Game() {
|
||||||
render() {
|
return (
|
||||||
return (
|
<Layout>
|
||||||
<Layout>
|
<AuthGuard />
|
||||||
<AuthGuard />
|
<span>"Game"</span>
|
||||||
<span>"Game"</span>
|
</Layout>
|
||||||
</Layout>
|
);
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Game;
|
export default Game;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import Menu from '@mui/material/Menu';
|
||||||
import MenuItem from '@mui/material/MenuItem';
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import MailOutlineRoundedIcon from '@mui/icons-material/MailOutline';
|
import MailOutlineRoundedIcon from '@mui/icons-material/MailOutlineRounded';
|
||||||
import MenuRoundedIcon from '@mui/icons-material/MenuRounded';
|
import MenuRoundedIcon from '@mui/icons-material/MenuRounded';
|
||||||
|
|
||||||
import { AuthenticationService, RoomsService } from '@app/api';
|
import { AuthenticationService, RoomsService } from '@app/api';
|
||||||
|
|
@ -56,7 +56,7 @@ const LeftNav = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleMenuItemClick = (option: string) => {
|
const handleMenuItemClick = (option: string) => {
|
||||||
const route = RouteEnum[option.toUpperCase()];
|
const route = App.RouteEnum[option.toUpperCase()];
|
||||||
navigate(generatePath(route));
|
navigate(generatePath(route));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,10 +149,12 @@ const LeftNav = () => {
|
||||||
keepMounted
|
keepMounted
|
||||||
open={!!state.anchorEl}
|
open={!!state.anchorEl}
|
||||||
onClose={() => handleMenuClose()}
|
onClose={() => handleMenuClose()}
|
||||||
PaperProps={{
|
slotProps={{
|
||||||
style: {
|
paper: {
|
||||||
marginTop: '32px',
|
style: {
|
||||||
width: '20ch',
|
marginTop: '32px',
|
||||||
|
width: '20ch',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
// eslint-disable-next-line
|
|
||||||
import React, { Component } from "react";
|
|
||||||
import Layout from '../Layout/Layout';
|
import Layout from '../Layout/Layout';
|
||||||
|
|
||||||
import { AuthGuard } from '@app/components';
|
import { AuthGuard } from '@app/components';
|
||||||
|
|
||||||
class Player extends Component {
|
function Player() {
|
||||||
render() {
|
return (
|
||||||
return (
|
<Layout>
|
||||||
<Layout>
|
<AuthGuard />
|
||||||
<AuthGuard />
|
<span>"Player"</span>
|
||||||
<span>"Player"</span>
|
</Layout>
|
||||||
</Layout>
|
);
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Player;
|
export default Player;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ File is adapted from https://github.com/Qeepsake/use-redux-effect under MIT Lice
|
||||||
* @description
|
* @description
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useRef, useEffect, DependencyList } from 'react'
|
import { useEffect, useRef, DependencyList } from 'react'
|
||||||
import { useStore } from 'react-redux'
|
import { useStore } from 'react-redux'
|
||||||
import { castArray } from 'lodash'
|
import { castArray } from 'lodash'
|
||||||
|
|
||||||
|
|
@ -14,36 +14,44 @@ import { castArray } from 'lodash'
|
||||||
export type ReduxEffect = (action: any) => void
|
export type ReduxEffect = (action: any) => void
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to redux store events
|
* Subscribes to redux store events.
|
||||||
*
|
*
|
||||||
* @param effect
|
* On mount, synchronously inspects the current `state.action` so an action
|
||||||
* @param type
|
* dispatched between render and effect-commit is still observed — this is
|
||||||
* @param deps
|
* what lets `<Server />` catch a `JOIN_ROOM` that auto-join fired while the
|
||||||
*/
|
* route was transitioning.
|
||||||
|
*/
|
||||||
export function useReduxEffect(
|
export function useReduxEffect(
|
||||||
effect: ReduxEffect,
|
effect: ReduxEffect,
|
||||||
type: string | string[],
|
type: string | string[],
|
||||||
deps: DependencyList = [],
|
deps: DependencyList = [],
|
||||||
): void {
|
): void {
|
||||||
const currentValue = useRef(null);
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
const effectRef = useRef(effect);
|
||||||
|
const typeRef = useRef(type);
|
||||||
|
// Persists across StrictMode's mount → unmount → remount cycle so we
|
||||||
|
// don't re-fire for an action we already handled on the first mount.
|
||||||
|
const lastHandledCountRef = useRef<number>(-1);
|
||||||
|
|
||||||
const handleChange = (): void => {
|
effectRef.current = effect;
|
||||||
const state: any = store.getState();
|
typeRef.current = type;
|
||||||
const action = state.action;
|
|
||||||
const previousValue = currentValue.current;
|
|
||||||
currentValue.current = action.count;
|
|
||||||
|
|
||||||
if (
|
|
||||||
previousValue !== action.count &&
|
|
||||||
castArray(type).includes(action.type)
|
|
||||||
) {
|
|
||||||
effect(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = store.subscribe(handleChange);
|
const check = (): void => {
|
||||||
|
const action = (store.getState() as any).action;
|
||||||
|
if (!action || action.count === lastHandledCountRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastHandledCountRef.current = action.count;
|
||||||
|
if (castArray(typeRef.current).includes(action.type)) {
|
||||||
|
effectRef.current(action);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
check();
|
||||||
|
|
||||||
|
const unsubscribe = store.subscribe(check);
|
||||||
return (): void => unsubscribe();
|
return (): void => unsubscribe();
|
||||||
}, deps)
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, deps);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@ class I18nBackend {
|
||||||
static BASE_URL = `${import.meta.env.BASE_URL}locales`;
|
static BASE_URL = `${import.meta.env.BASE_URL}locales`;
|
||||||
|
|
||||||
read(language, namespace, callback) {
|
read(language, namespace, callback) {
|
||||||
if (!language[App.Language]) {
|
if (!language[App.Language as unknown as string]) {
|
||||||
callback(true, null);
|
callback(true, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch(`${I18nBackend.BASE_URL}/${language[App.Language]}/${namespace}.json`)
|
fetch(`${I18nBackend.BASE_URL}/${language[App.Language as unknown as string]}/${namespace}.json`)
|
||||||
.then(resp => resp.json().then(json => callback(null, json)))
|
.then(resp => resp.json().then(json => callback(null, json)))
|
||||||
.catch(error => callback(error, null));
|
.catch(error => callback(error, null));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,30 @@ import '@testing-library/jest-dom/vitest';
|
||||||
// `mockImplementation`, it should set it in that test's body and rely on
|
// `mockImplementation`, it should set it in that test's body and rely on
|
||||||
// the next test overwriting or the global `clearAllMocks` clearing calls —
|
// the next test overwriting or the global `clearAllMocks` clearing calls —
|
||||||
// it should NOT assume the mock is reset to its factory default automatically.
|
// it should NOT assume the mock is reset to its factory default automatically.
|
||||||
|
//
|
||||||
|
// Global snapshot/restore guards for non-`vi.spyOn` globals that tests mutate
|
||||||
|
// directly. `vi.restoreAllMocks()` only restores `vi.spyOn` targets, so bare
|
||||||
|
// `Object.defineProperty` writes on `window.location` and `globalThis.WebSocket`
|
||||||
|
// reassignments leak between tests unless we explicitly capture and restore them.
|
||||||
|
let _locationDescriptor: PropertyDescriptor | undefined;
|
||||||
|
let _originalWebSocket: typeof globalThis.WebSocket | undefined;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
_locationDescriptor = Object.getOwnPropertyDescriptor(window, 'location');
|
||||||
|
_originalWebSocket = globalThis.WebSocket;
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
vi.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
vi.useRealTimers();
|
vi.useRealTimers();
|
||||||
|
|
||||||
|
const currentLocationDescriptor = Object.getOwnPropertyDescriptor(window, 'location');
|
||||||
|
if (currentLocationDescriptor !== _locationDescriptor && _locationDescriptor) {
|
||||||
|
Object.defineProperty(window, 'location', _locationDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalThis.WebSocket !== _originalWebSocket) {
|
||||||
|
globalThis.WebSocket = _originalWebSocket as typeof globalThis.WebSocket;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
vi.mock('../store', () => ({ store: { dispatch: vi.fn() } }));
|
// Use `vi.hoisted` so the mocked `store.dispatch` reference stays stable across
|
||||||
|
// re-runs of the factory under `isolate: false`. See rooms.dispatch.spec.ts for
|
||||||
|
// the same pattern and rationale.
|
||||||
|
const { mockDispatch } = vi.hoisted(() => ({ mockDispatch: vi.fn() }));
|
||||||
|
vi.mock('../store', () => ({ store: { dispatch: mockDispatch } }));
|
||||||
|
|
||||||
import { create } from '@bufbuild/protobuf';
|
import { create } from '@bufbuild/protobuf';
|
||||||
import { Data } from '@app/types';
|
import { Data } from '@app/types';
|
||||||
import { store } from '..';
|
|
||||||
import { Actions } from './game.actions';
|
import { Actions } from './game.actions';
|
||||||
import { Dispatch } from './game.dispatch';
|
import { Dispatch } from './game.dispatch';
|
||||||
import {
|
import {
|
||||||
|
|
@ -12,31 +15,35 @@ import {
|
||||||
makePlayerProperties,
|
makePlayerProperties,
|
||||||
} from './__mocks__/fixtures';
|
} from './__mocks__/fixtures';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDispatch.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
describe('Dispatch', () => {
|
describe('Dispatch', () => {
|
||||||
it('clearStore dispatches Actions.clearStore()', () => {
|
it('clearStore dispatches Actions.clearStore()', () => {
|
||||||
Dispatch.clearStore();
|
Dispatch.clearStore();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.clearStore());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.clearStore());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gameJoined dispatches Actions.gameJoined()', () => {
|
it('gameJoined dispatches Actions.gameJoined()', () => {
|
||||||
const data = create(Data.Event_GameJoinedSchema, { hostId: 1, playerId: 2 });
|
const data = create(Data.Event_GameJoinedSchema, { hostId: 1, playerId: 2 });
|
||||||
Dispatch.gameJoined(data);
|
Dispatch.gameJoined(data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.gameJoined(data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.gameJoined(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gameLeft dispatches Actions.gameLeft()', () => {
|
it('gameLeft dispatches Actions.gameLeft()', () => {
|
||||||
Dispatch.gameLeft(2);
|
Dispatch.gameLeft(2);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.gameLeft(2));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.gameLeft(2));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gameClosed dispatches Actions.gameClosed()', () => {
|
it('gameClosed dispatches Actions.gameClosed()', () => {
|
||||||
Dispatch.gameClosed(3);
|
Dispatch.gameClosed(3);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.gameClosed(3));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.gameClosed(3));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gameHostChanged dispatches Actions.gameHostChanged()', () => {
|
it('gameHostChanged dispatches Actions.gameHostChanged()', () => {
|
||||||
Dispatch.gameHostChanged(1, 7);
|
Dispatch.gameHostChanged(1, 7);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.gameHostChanged(1, 7));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.gameHostChanged(1, 7));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gameStateChanged dispatches Actions.gameStateChanged()', () => {
|
it('gameStateChanged dispatches Actions.gameStateChanged()', () => {
|
||||||
|
|
@ -44,156 +51,156 @@ describe('Dispatch', () => {
|
||||||
playerList: [], gameStarted: false, activePlayerId: 0, activePhase: 0, secondsElapsed: 0
|
playerList: [], gameStarted: false, activePlayerId: 0, activePhase: 0, secondsElapsed: 0
|
||||||
});
|
});
|
||||||
Dispatch.gameStateChanged(1, data);
|
Dispatch.gameStateChanged(1, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.gameStateChanged(1, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.gameStateChanged(1, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('playerJoined dispatches Actions.playerJoined()', () => {
|
it('playerJoined dispatches Actions.playerJoined()', () => {
|
||||||
const props = makePlayerProperties();
|
const props = makePlayerProperties();
|
||||||
Dispatch.playerJoined(1, props);
|
Dispatch.playerJoined(1, props);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.playerJoined(1, props));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.playerJoined(1, props));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('playerLeft dispatches Actions.playerLeft()', () => {
|
it('playerLeft dispatches Actions.playerLeft()', () => {
|
||||||
Dispatch.playerLeft(1, 2, 3);
|
Dispatch.playerLeft(1, 2, 3);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.playerLeft(1, 2, 3));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.playerLeft(1, 2, 3));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('playerPropertiesChanged dispatches Actions.playerPropertiesChanged()', () => {
|
it('playerPropertiesChanged dispatches Actions.playerPropertiesChanged()', () => {
|
||||||
const props = makePlayerProperties();
|
const props = makePlayerProperties();
|
||||||
Dispatch.playerPropertiesChanged(1, 2, props);
|
Dispatch.playerPropertiesChanged(1, 2, props);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.playerPropertiesChanged(1, 2, props));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.playerPropertiesChanged(1, 2, props));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('kicked dispatches Actions.kicked()', () => {
|
it('kicked dispatches Actions.kicked()', () => {
|
||||||
Dispatch.kicked(1);
|
Dispatch.kicked(1);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.kicked(1));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.kicked(1));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cardMoved dispatches Actions.cardMoved()', () => {
|
it('cardMoved dispatches Actions.cardMoved()', () => {
|
||||||
const data = create(Data.Event_MoveCardSchema, { cardId: 1 });
|
const data = create(Data.Event_MoveCardSchema, { cardId: 1 });
|
||||||
Dispatch.cardMoved(1, 2, data);
|
Dispatch.cardMoved(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.cardMoved(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.cardMoved(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cardFlipped dispatches Actions.cardFlipped()', () => {
|
it('cardFlipped dispatches Actions.cardFlipped()', () => {
|
||||||
const data = create(Data.Event_FlipCardSchema, { cardId: 1 });
|
const data = create(Data.Event_FlipCardSchema, { cardId: 1 });
|
||||||
Dispatch.cardFlipped(1, 2, data);
|
Dispatch.cardFlipped(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.cardFlipped(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.cardFlipped(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cardDestroyed dispatches Actions.cardDestroyed()', () => {
|
it('cardDestroyed dispatches Actions.cardDestroyed()', () => {
|
||||||
const data = create(Data.Event_DestroyCardSchema, { cardId: 1 });
|
const data = create(Data.Event_DestroyCardSchema, { cardId: 1 });
|
||||||
Dispatch.cardDestroyed(1, 2, data);
|
Dispatch.cardDestroyed(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.cardDestroyed(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.cardDestroyed(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cardAttached dispatches Actions.cardAttached()', () => {
|
it('cardAttached dispatches Actions.cardAttached()', () => {
|
||||||
const data = create(Data.Event_AttachCardSchema, { cardId: 1 });
|
const data = create(Data.Event_AttachCardSchema, { cardId: 1 });
|
||||||
Dispatch.cardAttached(1, 2, data);
|
Dispatch.cardAttached(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.cardAttached(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.cardAttached(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('tokenCreated dispatches Actions.tokenCreated()', () => {
|
it('tokenCreated dispatches Actions.tokenCreated()', () => {
|
||||||
const data = create(Data.Event_CreateTokenSchema, { cardId: 1 });
|
const data = create(Data.Event_CreateTokenSchema, { cardId: 1 });
|
||||||
Dispatch.tokenCreated(1, 2, data);
|
Dispatch.tokenCreated(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.tokenCreated(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.tokenCreated(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cardAttrChanged dispatches Actions.cardAttrChanged()', () => {
|
it('cardAttrChanged dispatches Actions.cardAttrChanged()', () => {
|
||||||
const data = create(Data.Event_SetCardAttrSchema, { cardId: 1 });
|
const data = create(Data.Event_SetCardAttrSchema, { cardId: 1 });
|
||||||
Dispatch.cardAttrChanged(1, 2, data);
|
Dispatch.cardAttrChanged(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.cardAttrChanged(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.cardAttrChanged(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cardCounterChanged dispatches Actions.cardCounterChanged()', () => {
|
it('cardCounterChanged dispatches Actions.cardCounterChanged()', () => {
|
||||||
const data = create(Data.Event_SetCardCounterSchema, { cardId: 1 });
|
const data = create(Data.Event_SetCardCounterSchema, { cardId: 1 });
|
||||||
Dispatch.cardCounterChanged(1, 2, data);
|
Dispatch.cardCounterChanged(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.cardCounterChanged(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.cardCounterChanged(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('arrowCreated dispatches Actions.arrowCreated()', () => {
|
it('arrowCreated dispatches Actions.arrowCreated()', () => {
|
||||||
const data = create(Data.Event_CreateArrowSchema, { arrowInfo: makeArrow() });
|
const data = create(Data.Event_CreateArrowSchema, { arrowInfo: makeArrow() });
|
||||||
Dispatch.arrowCreated(1, 2, data);
|
Dispatch.arrowCreated(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.arrowCreated(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.arrowCreated(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('arrowDeleted dispatches Actions.arrowDeleted()', () => {
|
it('arrowDeleted dispatches Actions.arrowDeleted()', () => {
|
||||||
const data = create(Data.Event_DeleteArrowSchema, { arrowId: 3 });
|
const data = create(Data.Event_DeleteArrowSchema, { arrowId: 3 });
|
||||||
Dispatch.arrowDeleted(1, 2, data);
|
Dispatch.arrowDeleted(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.arrowDeleted(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.arrowDeleted(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('counterCreated dispatches Actions.counterCreated()', () => {
|
it('counterCreated dispatches Actions.counterCreated()', () => {
|
||||||
const data = create(Data.Event_CreateCounterSchema, { counterInfo: makeCounter() });
|
const data = create(Data.Event_CreateCounterSchema, { counterInfo: makeCounter() });
|
||||||
Dispatch.counterCreated(1, 2, data);
|
Dispatch.counterCreated(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.counterCreated(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.counterCreated(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('counterSet dispatches Actions.counterSet()', () => {
|
it('counterSet dispatches Actions.counterSet()', () => {
|
||||||
const data = create(Data.Event_SetCounterSchema, { counterId: 1, value: 10 });
|
const data = create(Data.Event_SetCounterSchema, { counterId: 1, value: 10 });
|
||||||
Dispatch.counterSet(1, 2, data);
|
Dispatch.counterSet(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.counterSet(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.counterSet(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('counterDeleted dispatches Actions.counterDeleted()', () => {
|
it('counterDeleted dispatches Actions.counterDeleted()', () => {
|
||||||
const data = create(Data.Event_DelCounterSchema, { counterId: 1 });
|
const data = create(Data.Event_DelCounterSchema, { counterId: 1 });
|
||||||
Dispatch.counterDeleted(1, 2, data);
|
Dispatch.counterDeleted(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.counterDeleted(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.counterDeleted(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cardsDrawn dispatches Actions.cardsDrawn()', () => {
|
it('cardsDrawn dispatches Actions.cardsDrawn()', () => {
|
||||||
const data = create(Data.Event_DrawCardsSchema, { number: 2, cards: [makeCard()] });
|
const data = create(Data.Event_DrawCardsSchema, { number: 2, cards: [makeCard()] });
|
||||||
Dispatch.cardsDrawn(1, 2, data);
|
Dispatch.cardsDrawn(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.cardsDrawn(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.cardsDrawn(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('cardsRevealed dispatches Actions.cardsRevealed()', () => {
|
it('cardsRevealed dispatches Actions.cardsRevealed()', () => {
|
||||||
const data = create(Data.Event_RevealCardsSchema, { zoneName: 'hand', cards: [] });
|
const data = create(Data.Event_RevealCardsSchema, { zoneName: 'hand', cards: [] });
|
||||||
Dispatch.cardsRevealed(1, 2, data);
|
Dispatch.cardsRevealed(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.cardsRevealed(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.cardsRevealed(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('zoneShuffled dispatches Actions.zoneShuffled()', () => {
|
it('zoneShuffled dispatches Actions.zoneShuffled()', () => {
|
||||||
const data = create(Data.Event_ShuffleSchema, { zoneName: 'deck', start: 0, end: 39 });
|
const data = create(Data.Event_ShuffleSchema, { zoneName: 'deck', start: 0, end: 39 });
|
||||||
Dispatch.zoneShuffled(1, 2, data);
|
Dispatch.zoneShuffled(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.zoneShuffled(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.zoneShuffled(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('dieRolled dispatches Actions.dieRolled()', () => {
|
it('dieRolled dispatches Actions.dieRolled()', () => {
|
||||||
const data = create(Data.Event_RollDieSchema, { sides: 6, value: 4, values: [4] });
|
const data = create(Data.Event_RollDieSchema, { sides: 6, value: 4, values: [4] });
|
||||||
Dispatch.dieRolled(1, 2, data);
|
Dispatch.dieRolled(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.dieRolled(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.dieRolled(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('activePlayerSet dispatches Actions.activePlayerSet()', () => {
|
it('activePlayerSet dispatches Actions.activePlayerSet()', () => {
|
||||||
Dispatch.activePlayerSet(1, 3);
|
Dispatch.activePlayerSet(1, 3);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.activePlayerSet(1, 3));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.activePlayerSet(1, 3));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('activePhaseSet dispatches Actions.activePhaseSet()', () => {
|
it('activePhaseSet dispatches Actions.activePhaseSet()', () => {
|
||||||
Dispatch.activePhaseSet(1, 2);
|
Dispatch.activePhaseSet(1, 2);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.activePhaseSet(1, 2));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.activePhaseSet(1, 2));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('turnReversed dispatches Actions.turnReversed()', () => {
|
it('turnReversed dispatches Actions.turnReversed()', () => {
|
||||||
Dispatch.turnReversed(1, true);
|
Dispatch.turnReversed(1, true);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.turnReversed(1, true));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.turnReversed(1, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('zoneDumped dispatches Actions.zoneDumped()', () => {
|
it('zoneDumped dispatches Actions.zoneDumped()', () => {
|
||||||
const data = create(Data.Event_DumpZoneSchema, { zoneOwnerId: 1, zoneName: 'hand', numberCards: 3, isReversed: false });
|
const data = create(Data.Event_DumpZoneSchema, { zoneOwnerId: 1, zoneName: 'hand', numberCards: 3, isReversed: false });
|
||||||
Dispatch.zoneDumped(1, 2, data);
|
Dispatch.zoneDumped(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.zoneDumped(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.zoneDumped(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('zonePropertiesChanged dispatches Actions.zonePropertiesChanged()', () => {
|
it('zonePropertiesChanged dispatches Actions.zonePropertiesChanged()', () => {
|
||||||
const data = create(Data.Event_ChangeZonePropertiesSchema, { zoneName: 'deck', alwaysRevealTopCard: true, alwaysLookAtTopCard: false });
|
const data = create(Data.Event_ChangeZonePropertiesSchema, { zoneName: 'deck', alwaysRevealTopCard: true, alwaysLookAtTopCard: false });
|
||||||
Dispatch.zonePropertiesChanged(1, 2, data);
|
Dispatch.zonePropertiesChanged(1, 2, data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.zonePropertiesChanged(1, 2, data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.zonePropertiesChanged(1, 2, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gameSay dispatches Actions.gameSay()', () => {
|
it('gameSay dispatches Actions.gameSay()', () => {
|
||||||
Dispatch.gameSay(1, 2, 'gg wp');
|
Dispatch.gameSay(1, 2, 'gg wp');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.gameSay(1, 2, 'gg wp'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.gameSay(1, 2, 'gg wp'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -898,17 +898,20 @@ describe('2J: Turn, phase, and chat', () => {
|
||||||
|
|
||||||
it('GAME_SAY → appends message with mocked Date.now() as timeReceived', () => {
|
it('GAME_SAY → appends message with mocked Date.now() as timeReceived', () => {
|
||||||
const state = makeState();
|
const state = makeState();
|
||||||
vi.spyOn(Date, 'now').mockReturnValue(123456789);
|
const dateNowSpy = vi.spyOn(Date, 'now').mockReturnValue(123456789);
|
||||||
const result = gamesReducer(state, {
|
try {
|
||||||
type: Types.GAME_SAY,
|
const result = gamesReducer(state, {
|
||||||
gameId: 1,
|
type: Types.GAME_SAY,
|
||||||
playerId: 2,
|
gameId: 1,
|
||||||
message: 'gg',
|
playerId: 2,
|
||||||
});
|
message: 'gg',
|
||||||
vi.restoreAllMocks();
|
});
|
||||||
|
|
||||||
expect(result.games[1].messages).toHaveLength(1);
|
expect(result.games[1].messages).toHaveLength(1);
|
||||||
expect(result.games[1].messages[0]).toEqual({ playerId: 2, message: 'gg', timeReceived: 123456789 });
|
expect(result.games[1].messages[0]).toEqual({ playerId: 2, message: 'gg', timeReceived: 123456789 });
|
||||||
|
} finally {
|
||||||
|
dateNowSpy.mockRestore();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,12 +55,15 @@ export function makeGame(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeMessage(overrides: Partial<Enriched.Message> = {}): Enriched.Message {
|
export function makeMessage(overrides: Partial<Omit<Enriched.Message, '$typeName' | '$unknown'>> = {}): Enriched.Message {
|
||||||
|
const { timeReceived = 0, ...protoOverrides } = overrides;
|
||||||
return {
|
return {
|
||||||
message: 'hello',
|
...create(Data.Event_RoomSaySchema, {
|
||||||
messageType: 0,
|
message: 'hello',
|
||||||
timeReceived: 0,
|
messageType: 0,
|
||||||
...overrides,
|
...protoOverrides,
|
||||||
|
}),
|
||||||
|
timeReceived,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,84 +1,95 @@
|
||||||
vi.mock('..', () => ({ store: { dispatch: vi.fn() } }));
|
// Use `vi.hoisted` so the mocked `store.dispatch` reference stays stable across
|
||||||
|
// re-runs of the factory under `isolate: false`. Other dispatch specs mock the
|
||||||
|
// same `..` path with their own factories; under the shared module graph, the
|
||||||
|
// cache entry for `..` can flip between competing `vi.fn()` instances. Asserting
|
||||||
|
// against the hoisted `mockDispatch` directly (rather than reaching through
|
||||||
|
// `store.dispatch`) decouples the assertions from whatever the module cache
|
||||||
|
// currently resolves `store` to.
|
||||||
|
const { mockDispatch } = vi.hoisted(() => ({ mockDispatch: vi.fn() }));
|
||||||
|
vi.mock('..', () => ({ store: { dispatch: mockDispatch } }));
|
||||||
|
|
||||||
import { store } from '..';
|
|
||||||
import { Actions } from './rooms.actions';
|
import { Actions } from './rooms.actions';
|
||||||
import { Dispatch } from './rooms.dispatch';
|
import { Dispatch } from './rooms.dispatch';
|
||||||
import { makeGame, makeMessage, makeRoom, makeUser } from './__mocks__/rooms-fixtures';
|
import { makeGame, makeMessage, makeRoom, makeUser } from './__mocks__/rooms-fixtures';
|
||||||
import { App } from '@app/types';
|
import { App } from '@app/types';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDispatch.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
describe('Dispatch', () => {
|
describe('Dispatch', () => {
|
||||||
it('clearStore dispatches Actions.clearStore()', () => {
|
it('clearStore dispatches Actions.clearStore()', () => {
|
||||||
Dispatch.clearStore();
|
Dispatch.clearStore();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.clearStore());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.clearStore());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateRooms dispatches Actions.updateRooms()', () => {
|
it('updateRooms dispatches Actions.updateRooms()', () => {
|
||||||
const rooms = [makeRoom()];
|
const rooms = [makeRoom()];
|
||||||
Dispatch.updateRooms(rooms);
|
Dispatch.updateRooms(rooms);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateRooms(rooms));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateRooms(rooms));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('joinRoom dispatches Actions.joinRoom()', () => {
|
it('joinRoom dispatches Actions.joinRoom()', () => {
|
||||||
const roomInfo = makeRoom({ roomId: 2 });
|
const roomInfo = makeRoom({ roomId: 2 });
|
||||||
Dispatch.joinRoom(roomInfo);
|
Dispatch.joinRoom(roomInfo);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.joinRoom(roomInfo));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.joinRoom(roomInfo));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('leaveRoom dispatches Actions.leaveRoom()', () => {
|
it('leaveRoom dispatches Actions.leaveRoom()', () => {
|
||||||
Dispatch.leaveRoom(3);
|
Dispatch.leaveRoom(3);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.leaveRoom(3));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.leaveRoom(3));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('addMessage with message.name falsy → dispatches only Actions.addMessage()', () => {
|
it('addMessage with message.name falsy → dispatches only Actions.addMessage()', () => {
|
||||||
const message = { ...makeMessage(), name: undefined };
|
const message = { ...makeMessage(), name: undefined };
|
||||||
Dispatch.addMessage(1, message);
|
Dispatch.addMessage(1, message);
|
||||||
expect(store.dispatch).toHaveBeenCalledTimes(1);
|
expect(mockDispatch).toHaveBeenCalledTimes(1);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.addMessage(1, message));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.addMessage(1, message));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('addMessage with message.name truthy → dispatches Actions.addMessage()', () => {
|
it('addMessage with message.name truthy → dispatches Actions.addMessage()', () => {
|
||||||
const message = { ...makeMessage(), name: 'Alice' };
|
const message = { ...makeMessage(), name: 'Alice' };
|
||||||
Dispatch.addMessage(1, message);
|
Dispatch.addMessage(1, message);
|
||||||
expect(store.dispatch).toHaveBeenCalledTimes(1);
|
expect(mockDispatch).toHaveBeenCalledTimes(1);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.addMessage(1, message));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.addMessage(1, message));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateGames dispatches Actions.updateGames()', () => {
|
it('updateGames dispatches Actions.updateGames()', () => {
|
||||||
const games = [makeGame()];
|
const games = [makeGame()];
|
||||||
Dispatch.updateGames(1, games);
|
Dispatch.updateGames(1, games);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateGames(1, games));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateGames(1, games));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('userJoined dispatches Actions.userJoined()', () => {
|
it('userJoined dispatches Actions.userJoined()', () => {
|
||||||
const user = makeUser();
|
const user = makeUser();
|
||||||
Dispatch.userJoined(1, user);
|
Dispatch.userJoined(1, user);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.userJoined(1, user));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.userJoined(1, user));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('userLeft dispatches Actions.userLeft()', () => {
|
it('userLeft dispatches Actions.userLeft()', () => {
|
||||||
Dispatch.userLeft(1, 'Alice');
|
Dispatch.userLeft(1, 'Alice');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.userLeft(1, 'Alice'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.userLeft(1, 'Alice'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sortGames dispatches Actions.sortGames()', () => {
|
it('sortGames dispatches Actions.sortGames()', () => {
|
||||||
Dispatch.sortGames(1, App.GameSortField.START_TIME, App.SortDirection.ASC);
|
Dispatch.sortGames(1, App.GameSortField.START_TIME, App.SortDirection.ASC);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(
|
expect(mockDispatch).toHaveBeenCalledWith(
|
||||||
Actions.sortGames(1, App.GameSortField.START_TIME, App.SortDirection.ASC)
|
Actions.sortGames(1, App.GameSortField.START_TIME, App.SortDirection.ASC)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('removeMessages dispatches Actions.removeMessages()', () => {
|
it('removeMessages dispatches Actions.removeMessages()', () => {
|
||||||
Dispatch.removeMessages(1, 'Alice', 5);
|
Dispatch.removeMessages(1, 'Alice', 5);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.removeMessages(1, 'Alice', 5));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.removeMessages(1, 'Alice', 5));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gameCreated dispatches Actions.gameCreated()', () => {
|
it('gameCreated dispatches Actions.gameCreated()', () => {
|
||||||
Dispatch.gameCreated(2);
|
Dispatch.gameCreated(2);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.gameCreated(2));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.gameCreated(2));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('joinedGame dispatches Actions.joinedGame()', () => {
|
it('joinedGame dispatches Actions.joinedGame()', () => {
|
||||||
Dispatch.joinedGame(1, 5);
|
Dispatch.joinedGame(1, 5);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.joinedGame(1, 5));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.joinedGame(1, 5));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
vi.mock('..', () => ({ store: { dispatch: vi.fn() } }));
|
// Use `vi.hoisted` so the mocked `store.dispatch` reference stays stable across
|
||||||
|
// re-runs of the factory under `isolate: false`. See rooms.dispatch.spec.ts for
|
||||||
|
// the same pattern and rationale.
|
||||||
|
const { mockDispatch } = vi.hoisted(() => ({ mockDispatch: vi.fn() }));
|
||||||
|
vi.mock('..', () => ({ store: { dispatch: mockDispatch } }));
|
||||||
|
|
||||||
import { store } from '..';
|
|
||||||
import { Actions } from './server.actions';
|
import { Actions } from './server.actions';
|
||||||
import { Dispatch } from './server.dispatch';
|
import { Dispatch } from './server.dispatch';
|
||||||
import { App, Data } from '@app/types';
|
import { App, Data } from '@app/types';
|
||||||
|
|
@ -17,378 +20,382 @@ import {
|
||||||
makeWarnListItem,
|
makeWarnListItem,
|
||||||
} from './__mocks__/server-fixtures';
|
} from './__mocks__/server-fixtures';
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockDispatch.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
describe('Dispatch', () => {
|
describe('Dispatch', () => {
|
||||||
it('initialized dispatches Actions.initialized()', () => {
|
it('initialized dispatches Actions.initialized()', () => {
|
||||||
Dispatch.initialized();
|
Dispatch.initialized();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.initialized());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.initialized());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clearStore dispatches Actions.clearStore()', () => {
|
it('clearStore dispatches Actions.clearStore()', () => {
|
||||||
Dispatch.clearStore();
|
Dispatch.clearStore();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.clearStore());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.clearStore());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('connectionAttempted dispatches Actions.connectionAttempted()', () => {
|
it('connectionAttempted dispatches Actions.connectionAttempted()', () => {
|
||||||
Dispatch.connectionAttempted();
|
Dispatch.connectionAttempted();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.connectionAttempted());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.connectionAttempted());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loginSuccessful dispatches Actions.loginSuccessful()', () => {
|
it('loginSuccessful dispatches Actions.loginSuccessful()', () => {
|
||||||
const options = makeLoginSuccessContext();
|
const options = makeLoginSuccessContext();
|
||||||
Dispatch.loginSuccessful(options);
|
Dispatch.loginSuccessful(options);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.loginSuccessful(options));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.loginSuccessful(options));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('loginFailed dispatches Actions.loginFailed()', () => {
|
it('loginFailed dispatches Actions.loginFailed()', () => {
|
||||||
Dispatch.loginFailed();
|
Dispatch.loginFailed();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.loginFailed());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.loginFailed());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('connectionFailed dispatches Actions.connectionFailed()', () => {
|
it('connectionFailed dispatches Actions.connectionFailed()', () => {
|
||||||
Dispatch.connectionFailed();
|
Dispatch.connectionFailed();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.connectionFailed());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.connectionFailed());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('testConnectionSuccessful dispatches Actions.testConnectionSuccessful()', () => {
|
it('testConnectionSuccessful dispatches Actions.testConnectionSuccessful()', () => {
|
||||||
Dispatch.testConnectionSuccessful();
|
Dispatch.testConnectionSuccessful();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.testConnectionSuccessful());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.testConnectionSuccessful());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('testConnectionFailed dispatches Actions.testConnectionFailed()', () => {
|
it('testConnectionFailed dispatches Actions.testConnectionFailed()', () => {
|
||||||
Dispatch.testConnectionFailed();
|
Dispatch.testConnectionFailed();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.testConnectionFailed());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.testConnectionFailed());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateBuddyList dispatches Actions.updateBuddyList()', () => {
|
it('updateBuddyList dispatches Actions.updateBuddyList()', () => {
|
||||||
const list = [makeUser()];
|
const list = [makeUser()];
|
||||||
Dispatch.updateBuddyList(list);
|
Dispatch.updateBuddyList(list);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateBuddyList(list));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateBuddyList(list));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('addToBuddyList dispatches Actions.addToBuddyList()', () => {
|
it('addToBuddyList dispatches Actions.addToBuddyList()', () => {
|
||||||
const user = makeUser();
|
const user = makeUser();
|
||||||
Dispatch.addToBuddyList(user);
|
Dispatch.addToBuddyList(user);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.addToBuddyList(user));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.addToBuddyList(user));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('removeFromBuddyList dispatches Actions.removeFromBuddyList()', () => {
|
it('removeFromBuddyList dispatches Actions.removeFromBuddyList()', () => {
|
||||||
Dispatch.removeFromBuddyList('Alice');
|
Dispatch.removeFromBuddyList('Alice');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.removeFromBuddyList('Alice'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.removeFromBuddyList('Alice'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateIgnoreList dispatches Actions.updateIgnoreList()', () => {
|
it('updateIgnoreList dispatches Actions.updateIgnoreList()', () => {
|
||||||
const list = [makeUser()];
|
const list = [makeUser()];
|
||||||
Dispatch.updateIgnoreList(list);
|
Dispatch.updateIgnoreList(list);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateIgnoreList(list));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateIgnoreList(list));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('addToIgnoreList dispatches Actions.addToIgnoreList()', () => {
|
it('addToIgnoreList dispatches Actions.addToIgnoreList()', () => {
|
||||||
const user = makeUser();
|
const user = makeUser();
|
||||||
Dispatch.addToIgnoreList(user);
|
Dispatch.addToIgnoreList(user);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.addToIgnoreList(user));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.addToIgnoreList(user));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('removeFromIgnoreList dispatches Actions.removeFromIgnoreList()', () => {
|
it('removeFromIgnoreList dispatches Actions.removeFromIgnoreList()', () => {
|
||||||
Dispatch.removeFromIgnoreList('Bob');
|
Dispatch.removeFromIgnoreList('Bob');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.removeFromIgnoreList('Bob'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.removeFromIgnoreList('Bob'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateInfo dispatches Actions.updateInfo({ name, version })', () => {
|
it('updateInfo dispatches Actions.updateInfo({ name, version })', () => {
|
||||||
Dispatch.updateInfo('Servatrice', '2.9');
|
Dispatch.updateInfo('Servatrice', '2.9');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateInfo({ name: 'Servatrice', version: '2.9' }));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateInfo({ name: 'Servatrice', version: '2.9' }));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateStatus dispatches Actions.updateStatus({ state, description })', () => {
|
it('updateStatus dispatches Actions.updateStatus({ state, description })', () => {
|
||||||
Dispatch.updateStatus(App.StatusEnum.CONNECTED, 'ok');
|
Dispatch.updateStatus(App.StatusEnum.CONNECTED, 'ok');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateStatus({ state: App.StatusEnum.CONNECTED, description: 'ok' }));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateStatus({ state: App.StatusEnum.CONNECTED, description: 'ok' }));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateUser dispatches Actions.updateUser()', () => {
|
it('updateUser dispatches Actions.updateUser()', () => {
|
||||||
const user = makeUser();
|
const user = makeUser();
|
||||||
Dispatch.updateUser(user);
|
Dispatch.updateUser(user);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateUser(user));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateUser(user));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateUsers dispatches Actions.updateUsers()', () => {
|
it('updateUsers dispatches Actions.updateUsers()', () => {
|
||||||
const users = [makeUser()];
|
const users = [makeUser()];
|
||||||
Dispatch.updateUsers(users);
|
Dispatch.updateUsers(users);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateUsers(users));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateUsers(users));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('userJoined dispatches Actions.userJoined()', () => {
|
it('userJoined dispatches Actions.userJoined()', () => {
|
||||||
const user = makeUser();
|
const user = makeUser();
|
||||||
Dispatch.userJoined(user);
|
Dispatch.userJoined(user);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.userJoined(user));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.userJoined(user));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('userLeft dispatches Actions.userLeft()', () => {
|
it('userLeft dispatches Actions.userLeft()', () => {
|
||||||
Dispatch.userLeft('Carol');
|
Dispatch.userLeft('Carol');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.userLeft('Carol'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.userLeft('Carol'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('viewLogs dispatches Actions.viewLogs()', () => {
|
it('viewLogs dispatches Actions.viewLogs()', () => {
|
||||||
const logs = [create(Data.ServerInfo_ChatMessageSchema, { targetType: 'room' })];
|
const logs = [create(Data.ServerInfo_ChatMessageSchema, { targetType: 'room' })];
|
||||||
Dispatch.viewLogs(logs);
|
Dispatch.viewLogs(logs);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.viewLogs(logs));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.viewLogs(logs));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clearLogs dispatches Actions.clearLogs()', () => {
|
it('clearLogs dispatches Actions.clearLogs()', () => {
|
||||||
Dispatch.clearLogs();
|
Dispatch.clearLogs();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.clearLogs());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.clearLogs());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('serverMessage dispatches Actions.serverMessage()', () => {
|
it('serverMessage dispatches Actions.serverMessage()', () => {
|
||||||
Dispatch.serverMessage('Welcome!');
|
Dispatch.serverMessage('Welcome!');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.serverMessage('Welcome!'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.serverMessage('Welcome!'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registrationRequiresEmail dispatches correctly', () => {
|
it('registrationRequiresEmail dispatches correctly', () => {
|
||||||
Dispatch.registrationRequiresEmail();
|
Dispatch.registrationRequiresEmail();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.registrationRequiresEmail());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.registrationRequiresEmail());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registrationSuccess dispatches correctly', () => {
|
it('registrationSuccess dispatches correctly', () => {
|
||||||
Dispatch.registrationSuccess();
|
Dispatch.registrationSuccess();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.registrationSuccess());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.registrationSuccess());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registrationFailed passes reason and endTime to action', () => {
|
it('registrationFailed passes reason and endTime to action', () => {
|
||||||
Dispatch.registrationFailed('reason', 999);
|
Dispatch.registrationFailed('reason', 999);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.registrationFailed('reason', 999));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.registrationFailed('reason', 999));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registrationFailed passes reason only when no endTime', () => {
|
it('registrationFailed passes reason only when no endTime', () => {
|
||||||
Dispatch.registrationFailed('plain reason');
|
Dispatch.registrationFailed('plain reason');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.registrationFailed('plain reason', undefined));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.registrationFailed('plain reason', undefined));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registrationEmailError dispatches correctly', () => {
|
it('registrationEmailError dispatches correctly', () => {
|
||||||
Dispatch.registrationEmailError('bad');
|
Dispatch.registrationEmailError('bad');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.registrationEmailError('bad'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.registrationEmailError('bad'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registrationPasswordError dispatches correctly', () => {
|
it('registrationPasswordError dispatches correctly', () => {
|
||||||
Dispatch.registrationPasswordError('weak');
|
Dispatch.registrationPasswordError('weak');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.registrationPasswordError('weak'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.registrationPasswordError('weak'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('registrationUserNameError dispatches correctly', () => {
|
it('registrationUserNameError dispatches correctly', () => {
|
||||||
Dispatch.registrationUserNameError('taken');
|
Dispatch.registrationUserNameError('taken');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.registrationUserNameError('taken'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.registrationUserNameError('taken'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accountAwaitingActivation dispatches correctly', () => {
|
it('accountAwaitingActivation dispatches correctly', () => {
|
||||||
const options = makePendingActivationContext();
|
const options = makePendingActivationContext();
|
||||||
Dispatch.accountAwaitingActivation(options);
|
Dispatch.accountAwaitingActivation(options);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.accountAwaitingActivation(options));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.accountAwaitingActivation(options));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accountActivationSuccess dispatches correctly', () => {
|
it('accountActivationSuccess dispatches correctly', () => {
|
||||||
Dispatch.accountActivationSuccess();
|
Dispatch.accountActivationSuccess();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.accountActivationSuccess());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.accountActivationSuccess());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accountActivationFailed dispatches correctly', () => {
|
it('accountActivationFailed dispatches correctly', () => {
|
||||||
Dispatch.accountActivationFailed();
|
Dispatch.accountActivationFailed();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.accountActivationFailed());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.accountActivationFailed());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resetPassword dispatches correctly', () => {
|
it('resetPassword dispatches correctly', () => {
|
||||||
Dispatch.resetPassword();
|
Dispatch.resetPassword();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.resetPassword());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.resetPassword());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resetPasswordFailed dispatches correctly', () => {
|
it('resetPasswordFailed dispatches correctly', () => {
|
||||||
Dispatch.resetPasswordFailed();
|
Dispatch.resetPasswordFailed();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.resetPasswordFailed());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.resetPasswordFailed());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resetPasswordChallenge dispatches correctly', () => {
|
it('resetPasswordChallenge dispatches correctly', () => {
|
||||||
Dispatch.resetPasswordChallenge();
|
Dispatch.resetPasswordChallenge();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.resetPasswordChallenge());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.resetPasswordChallenge());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('resetPasswordSuccess dispatches correctly', () => {
|
it('resetPasswordSuccess dispatches correctly', () => {
|
||||||
Dispatch.resetPasswordSuccess();
|
Dispatch.resetPasswordSuccess();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.resetPasswordSuccess());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.resetPasswordSuccess());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adjustMod dispatches Actions.adjustMod()', () => {
|
it('adjustMod dispatches Actions.adjustMod()', () => {
|
||||||
Dispatch.adjustMod('Dan', true, false);
|
Dispatch.adjustMod('Dan', true, false);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.adjustMod('Dan', true, false));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.adjustMod('Dan', true, false));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('reloadConfig dispatches correctly', () => {
|
it('reloadConfig dispatches correctly', () => {
|
||||||
Dispatch.reloadConfig();
|
Dispatch.reloadConfig();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.reloadConfig());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.reloadConfig());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shutdownServer dispatches correctly', () => {
|
it('shutdownServer dispatches correctly', () => {
|
||||||
Dispatch.shutdownServer();
|
Dispatch.shutdownServer();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.shutdownServer());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.shutdownServer());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateServerMessage dispatches correctly', () => {
|
it('updateServerMessage dispatches correctly', () => {
|
||||||
Dispatch.updateServerMessage();
|
Dispatch.updateServerMessage();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateServerMessage());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateServerMessage());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accountPasswordChange dispatches correctly', () => {
|
it('accountPasswordChange dispatches correctly', () => {
|
||||||
Dispatch.accountPasswordChange();
|
Dispatch.accountPasswordChange();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.accountPasswordChange());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.accountPasswordChange());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accountEditChanged dispatches correctly', () => {
|
it('accountEditChanged dispatches correctly', () => {
|
||||||
const user = makeUser();
|
const user = makeUser();
|
||||||
Dispatch.accountEditChanged(user);
|
Dispatch.accountEditChanged(user);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.accountEditChanged(user));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.accountEditChanged(user));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('accountImageChanged dispatches correctly', () => {
|
it('accountImageChanged dispatches correctly', () => {
|
||||||
const user = makeUser();
|
const user = makeUser();
|
||||||
Dispatch.accountImageChanged(user);
|
Dispatch.accountImageChanged(user);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.accountImageChanged(user));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.accountImageChanged(user));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getUserInfo dispatches correctly', () => {
|
it('getUserInfo dispatches correctly', () => {
|
||||||
const userInfo = makeUser({ name: 'Frank' });
|
const userInfo = makeUser({ name: 'Frank' });
|
||||||
Dispatch.getUserInfo(userInfo);
|
Dispatch.getUserInfo(userInfo);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.getUserInfo(userInfo));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.getUserInfo(userInfo));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('notifyUser dispatches correctly', () => {
|
it('notifyUser dispatches correctly', () => {
|
||||||
const notification = create(Data.Event_NotifyUserSchema, { type: 1, warningReason: '', customTitle: '', customContent: '' });
|
const notification = create(Data.Event_NotifyUserSchema, { type: 1, warningReason: '', customTitle: '', customContent: '' });
|
||||||
Dispatch.notifyUser(notification);
|
Dispatch.notifyUser(notification);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.notifyUser(notification));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.notifyUser(notification));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('serverShutdown dispatches correctly', () => {
|
it('serverShutdown dispatches correctly', () => {
|
||||||
const data = create(Data.Event_ServerShutdownSchema, { reason: 'maintenance', minutes: 5 });
|
const data = create(Data.Event_ServerShutdownSchema, { reason: 'maintenance', minutes: 5 });
|
||||||
Dispatch.serverShutdown(data);
|
Dispatch.serverShutdown(data);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.serverShutdown(data));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.serverShutdown(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('userMessage dispatches correctly', () => {
|
it('userMessage dispatches correctly', () => {
|
||||||
const messageData = create(Data.Event_UserMessageSchema, { senderName: 'Alice', receiverName: 'Bob', message: 'hey' });
|
const messageData = create(Data.Event_UserMessageSchema, { senderName: 'Alice', receiverName: 'Bob', message: 'hey' });
|
||||||
Dispatch.userMessage(messageData);
|
Dispatch.userMessage(messageData);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.userMessage(messageData));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.userMessage(messageData));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('addToList dispatches correctly', () => {
|
it('addToList dispatches correctly', () => {
|
||||||
Dispatch.addToList('buddyList', 'Grace');
|
Dispatch.addToList('buddyList', 'Grace');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.addToList('buddyList', 'Grace'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.addToList('buddyList', 'Grace'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('removeFromList dispatches correctly', () => {
|
it('removeFromList dispatches correctly', () => {
|
||||||
Dispatch.removeFromList('buddyList', 'Hank');
|
Dispatch.removeFromList('buddyList', 'Hank');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.removeFromList('buddyList', 'Hank'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.removeFromList('buddyList', 'Hank'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('banFromServer dispatches correctly', () => {
|
it('banFromServer dispatches correctly', () => {
|
||||||
Dispatch.banFromServer('Ira');
|
Dispatch.banFromServer('Ira');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.banFromServer('Ira'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.banFromServer('Ira'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('banHistory dispatches correctly', () => {
|
it('banHistory dispatches correctly', () => {
|
||||||
const history = [makeBanHistoryItem()];
|
const history = [makeBanHistoryItem()];
|
||||||
Dispatch.banHistory('Ira', history);
|
Dispatch.banHistory('Ira', history);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.banHistory('Ira', history));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.banHistory('Ira', history));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('warnHistory dispatches correctly', () => {
|
it('warnHistory dispatches correctly', () => {
|
||||||
const history = [makeWarnHistoryItem()];
|
const history = [makeWarnHistoryItem()];
|
||||||
Dispatch.warnHistory('Jack', history);
|
Dispatch.warnHistory('Jack', history);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.warnHistory('Jack', history));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.warnHistory('Jack', history));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('warnListOptions dispatches correctly', () => {
|
it('warnListOptions dispatches correctly', () => {
|
||||||
const list = [makeWarnListItem()];
|
const list = [makeWarnListItem()];
|
||||||
Dispatch.warnListOptions(list);
|
Dispatch.warnListOptions(list);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.warnListOptions(list));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.warnListOptions(list));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('warnUser dispatches correctly', () => {
|
it('warnUser dispatches correctly', () => {
|
||||||
Dispatch.warnUser('Kelly');
|
Dispatch.warnUser('Kelly');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.warnUser('Kelly'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.warnUser('Kelly'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('grantReplayAccess dispatches correctly', () => {
|
it('grantReplayAccess dispatches correctly', () => {
|
||||||
Dispatch.grantReplayAccess(7, 'Moe');
|
Dispatch.grantReplayAccess(7, 'Moe');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.grantReplayAccess(7, 'Moe'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.grantReplayAccess(7, 'Moe'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('forceActivateUser dispatches correctly', () => {
|
it('forceActivateUser dispatches correctly', () => {
|
||||||
Dispatch.forceActivateUser('Ned', 'Moe');
|
Dispatch.forceActivateUser('Ned', 'Moe');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.forceActivateUser('Ned', 'Moe'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.forceActivateUser('Ned', 'Moe'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('getAdminNotes dispatches correctly', () => {
|
it('getAdminNotes dispatches correctly', () => {
|
||||||
Dispatch.getAdminNotes('Ned', 'notes');
|
Dispatch.getAdminNotes('Ned', 'notes');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.getAdminNotes('Ned', 'notes'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.getAdminNotes('Ned', 'notes'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updateAdminNotes dispatches correctly', () => {
|
it('updateAdminNotes dispatches correctly', () => {
|
||||||
Dispatch.updateAdminNotes('Ned', 'updated');
|
Dispatch.updateAdminNotes('Ned', 'updated');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.updateAdminNotes('Ned', 'updated'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.updateAdminNotes('Ned', 'updated'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('replayList dispatches correctly', () => {
|
it('replayList dispatches correctly', () => {
|
||||||
const list = [makeReplayMatch()];
|
const list = [makeReplayMatch()];
|
||||||
Dispatch.replayList(list);
|
Dispatch.replayList(list);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.replayList(list));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.replayList(list));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('replayAdded dispatches correctly', () => {
|
it('replayAdded dispatches correctly', () => {
|
||||||
const match = makeReplayMatch();
|
const match = makeReplayMatch();
|
||||||
Dispatch.replayAdded(match);
|
Dispatch.replayAdded(match);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.replayAdded(match));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.replayAdded(match));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('replayModifyMatch dispatches correctly', () => {
|
it('replayModifyMatch dispatches correctly', () => {
|
||||||
Dispatch.replayModifyMatch(5, true);
|
Dispatch.replayModifyMatch(5, true);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.replayModifyMatch(5, true));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.replayModifyMatch(5, true));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('replayDeleteMatch dispatches correctly', () => {
|
it('replayDeleteMatch dispatches correctly', () => {
|
||||||
Dispatch.replayDeleteMatch(5);
|
Dispatch.replayDeleteMatch(5);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.replayDeleteMatch(5));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.replayDeleteMatch(5));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('backendDecks dispatches correctly', () => {
|
it('backendDecks dispatches correctly', () => {
|
||||||
const deckList = makeDeckList();
|
const deckList = makeDeckList();
|
||||||
Dispatch.backendDecks(deckList);
|
Dispatch.backendDecks(deckList);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.backendDecks(deckList));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.backendDecks(deckList));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deckNewDir dispatches correctly', () => {
|
it('deckNewDir dispatches correctly', () => {
|
||||||
Dispatch.deckNewDir('a/b', 'newFolder');
|
Dispatch.deckNewDir('a/b', 'newFolder');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.deckNewDir('a/b', 'newFolder'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.deckNewDir('a/b', 'newFolder'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deckDelDir dispatches correctly', () => {
|
it('deckDelDir dispatches correctly', () => {
|
||||||
Dispatch.deckDelDir('a/b');
|
Dispatch.deckDelDir('a/b');
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.deckDelDir('a/b'));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.deckDelDir('a/b'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deckUpload dispatches correctly', () => {
|
it('deckUpload dispatches correctly', () => {
|
||||||
const treeItem = makeDeckTreeItem();
|
const treeItem = makeDeckTreeItem();
|
||||||
Dispatch.deckUpload('a/b', treeItem);
|
Dispatch.deckUpload('a/b', treeItem);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.deckUpload('a/b', treeItem));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.deckUpload('a/b', treeItem));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deckDelete dispatches correctly', () => {
|
it('deckDelete dispatches correctly', () => {
|
||||||
Dispatch.deckDelete(42);
|
Dispatch.deckDelete(42);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.deckDelete(42));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.deckDelete(42));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('gamesOfUser dispatches correctly', () => {
|
it('gamesOfUser dispatches correctly', () => {
|
||||||
const response = create(Data.Response_GetGamesOfUserSchema, { roomList: [], gameList: [] });
|
const response = create(Data.Response_GetGamesOfUserSchema, { roomList: [], gameList: [] });
|
||||||
Dispatch.gamesOfUser('alice', response);
|
Dispatch.gamesOfUser('alice', response);
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.gamesOfUser('alice', response));
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.gamesOfUser('alice', response));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('clearRegistrationErrors dispatches correctly', () => {
|
it('clearRegistrationErrors dispatches correctly', () => {
|
||||||
Dispatch.clearRegistrationErrors();
|
Dispatch.clearRegistrationErrors();
|
||||||
expect(store.dispatch).toHaveBeenCalledWith(Actions.clearRegistrationErrors());
|
expect(mockDispatch).toHaveBeenCalledWith(Actions.clearRegistrationErrors());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,14 @@ import {
|
||||||
export function login(options: Omit<Enriched.LoginConnectOptions, 'password'>, password?: string, passwordSalt?: string): void {
|
export function login(options: Omit<Enriched.LoginConnectOptions, 'password'>, password?: string, passwordSalt?: string): void {
|
||||||
const { userName, hashedPassword } = options;
|
const { userName, hashedPassword } = options;
|
||||||
|
|
||||||
const loginConfig: MessageInitShape<typeof Data.Command_LoginSchema> = {
|
const loginConfig = {
|
||||||
...CLIENT_CONFIG,
|
...CLIENT_CONFIG,
|
||||||
clientid: 'webatrice',
|
clientid: 'webatrice',
|
||||||
userName,
|
userName,
|
||||||
...(passwordSalt
|
...(passwordSalt
|
||||||
? { hashedPassword: hashedPassword || hashPassword(passwordSalt, password) }
|
? { hashedPassword: hashedPassword || hashPassword(passwordSalt, password) }
|
||||||
: { password }),
|
: { password }),
|
||||||
};
|
} satisfies MessageInitShape<typeof Data.Command_LoginSchema>;
|
||||||
|
|
||||||
const onLoginError = (message: string, extra?: () => void) => {
|
const onLoginError = (message: string, extra?: () => void) => {
|
||||||
updateStatus(App.StatusEnum.DISCONNECTED, message);
|
updateStatus(App.StatusEnum.DISCONNECTED, message);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { GamePersistence } from '../../persistence';
|
import { GamePersistence } from '../../persistence';
|
||||||
import type { Data, Enriched } from '@app/types';
|
import type { Data, Enriched } from '@app/types';
|
||||||
|
|
||||||
export function joinGame(data: { playerProperties: Data.ServerInfo_PlayerProperties }, meta: Enriched.GameEventMeta): void {
|
export function joinGame(data: Data.Event_Join, meta: Enriched.GameEventMeta): void {
|
||||||
GamePersistence.playerJoined(meta.gameId, data.playerProperties);
|
GamePersistence.playerJoined(meta.gameId, data.playerProperties);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { Data, Enriched } from '@app/types';
|
import type { Data, Enriched } from '@app/types';
|
||||||
import { GamePersistence } from '../../persistence';
|
import { GamePersistence } from '../../persistence';
|
||||||
|
|
||||||
export function playerPropertiesChanged(data: { playerProperties: Data.ServerInfo_PlayerProperties }, meta: Enriched.GameEventMeta): void {
|
export function playerPropertiesChanged(data: Data.Event_PlayerPropertiesChanged, meta: Enriched.GameEventMeta): void {
|
||||||
GamePersistence.playerPropertiesChanged(meta.gameId, meta.playerId, data.playerProperties);
|
GamePersistence.playerPropertiesChanged(meta.gameId, meta.playerId, data.playerProperties);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -204,6 +204,9 @@ describe('addToList', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
|
||||||
});
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
logSpy.mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
it('buddy list → addToBuddyList', () => {
|
it('buddy list → addToBuddyList', () => {
|
||||||
const data = create(Data.Event_AddToListSchema, {
|
const data = create(Data.Event_AddToListSchema, {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
vi.mock('@bufbuild/protobuf', () => ({
|
vi.mock('@bufbuild/protobuf', async (importOriginal) => ({
|
||||||
create: vi.fn((_schema: unknown, fields?: Record<string, unknown>) => ({ ...(fields ?? {}) })),
|
...(await importOriginal<typeof import('@bufbuild/protobuf')>()),
|
||||||
fromBinary: vi.fn(),
|
fromBinary: vi.fn(),
|
||||||
toBinary: vi.fn().mockReturnValue(new Uint8Array()),
|
toBinary: vi.fn().mockReturnValue(new Uint8Array()),
|
||||||
hasExtension: vi.fn().mockReturnValue(false),
|
hasExtension: vi.fn().mockReturnValue(false),
|
||||||
|
|
@ -7,20 +7,6 @@ vi.mock('@bufbuild/protobuf', () => ({
|
||||||
setExtension: vi.fn(),
|
setExtension: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock('../../generated/proto/commands_pb', () => ({
|
|
||||||
CommandContainerSchema: {},
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('../../generated/proto/server_message_pb', () => ({
|
|
||||||
ServerMessageSchema: {},
|
|
||||||
ServerMessage_MessageType: {
|
|
||||||
RESPONSE: 1,
|
|
||||||
ROOM_EVENT: 2,
|
|
||||||
SESSION_EVENT: 3,
|
|
||||||
GAME_EVENT_CONTAINER: 4,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
vi.mock('../events', () => ({
|
vi.mock('../events', () => ({
|
||||||
GameEvents: [],
|
GameEvents: [],
|
||||||
RoomEvents: [],
|
RoomEvents: [],
|
||||||
|
|
@ -40,6 +26,7 @@ import { GameEvents, RoomEvents, SessionEvents } from '../events';
|
||||||
import type { GameExtensionRegistry } from '../events/game';
|
import type { GameExtensionRegistry } from '../events/game';
|
||||||
import type { RoomExtensionRegistry } from '../events/room';
|
import type { RoomExtensionRegistry } from '../events/room';
|
||||||
import type { SessionExtensionRegistry } from '../events/session';
|
import type { SessionExtensionRegistry } from '../events/session';
|
||||||
|
import { withEventRegistry } from '../../__test-utils__';
|
||||||
|
|
||||||
import { Data } from '@app/types';
|
import { Data } from '@app/types';
|
||||||
|
|
||||||
|
|
@ -53,12 +40,20 @@ type ProtobufInternal = ProtobufService & {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mockSocket: { isOpen: ReturnType<typeof vi.fn>; send: ReturnType<typeof vi.fn> };
|
let mockSocket: { isOpen: ReturnType<typeof vi.fn>; send: ReturnType<typeof vi.fn> };
|
||||||
|
let registryTeardowns: Array<() => void>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockSocket = {
|
mockSocket = {
|
||||||
isOpen: vi.fn().mockReturnValue(true),
|
isOpen: vi.fn().mockReturnValue(true),
|
||||||
send: vi.fn(),
|
send: vi.fn(),
|
||||||
};
|
};
|
||||||
|
registryTeardowns = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
while (registryTeardowns.length > 0) {
|
||||||
|
registryTeardowns.pop()!();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ProtobufService', () => {
|
describe('ProtobufService', () => {
|
||||||
|
|
@ -348,8 +343,7 @@ describe('ProtobufService', () => {
|
||||||
const mockExt = {} as GenExtension<Data.GameEvent, unknown>;
|
const mockExt = {} as GenExtension<Data.GameEvent, unknown>;
|
||||||
const payload = { someData: 1 };
|
const payload = { someData: 1 };
|
||||||
|
|
||||||
// Temporarily override GameEvents for this test
|
registryTeardowns.push(withEventRegistry(GameEvents as GameExtensionRegistry, [mockExt, handler]));
|
||||||
(GameEvents as GameExtensionRegistry).push([mockExt, handler]);
|
|
||||||
vi.mocked(hasExtension).mockReturnValue(true);
|
vi.mocked(hasExtension).mockReturnValue(true);
|
||||||
vi.mocked(getExtension).mockReturnValue(payload);
|
vi.mocked(getExtension).mockReturnValue(payload);
|
||||||
|
|
||||||
|
|
@ -359,7 +353,6 @@ describe('ProtobufService', () => {
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(payload, expect.objectContaining({ gameId: 42, playerId: 5 }));
|
expect(handler).toHaveBeenCalledWith(payload, expect.objectContaining({ gameId: 42, playerId: 5 }));
|
||||||
(GameEvents as GameExtensionRegistry).pop();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('defaults gameId and playerId to -1 when undefined', () => {
|
it('defaults gameId and playerId to -1 when undefined', () => {
|
||||||
|
|
@ -368,7 +361,7 @@ describe('ProtobufService', () => {
|
||||||
const mockExt = {} as GenExtension<Data.GameEvent, unknown>;
|
const mockExt = {} as GenExtension<Data.GameEvent, unknown>;
|
||||||
const payload = { someData: 1 };
|
const payload = { someData: 1 };
|
||||||
|
|
||||||
(GameEvents as GameExtensionRegistry).push([mockExt, handler]);
|
registryTeardowns.push(withEventRegistry(GameEvents as GameExtensionRegistry, [mockExt, handler]));
|
||||||
vi.mocked(hasExtension).mockReturnValue(true);
|
vi.mocked(hasExtension).mockReturnValue(true);
|
||||||
vi.mocked(getExtension).mockReturnValue(payload);
|
vi.mocked(getExtension).mockReturnValue(payload);
|
||||||
|
|
||||||
|
|
@ -378,7 +371,6 @@ describe('ProtobufService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(payload, expect.objectContaining({ gameId: -1, playerId: -1 }));
|
expect(handler).toHaveBeenCalledWith(payload, expect.objectContaining({ gameId: -1, playerId: -1 }));
|
||||||
(GameEvents as GameExtensionRegistry).pop();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -405,7 +397,7 @@ describe('ProtobufService', () => {
|
||||||
const mockExt = {} as GenExtension<Data.RoomEvent, unknown>;
|
const mockExt = {} as GenExtension<Data.RoomEvent, unknown>;
|
||||||
const payload = { roomData: 1 };
|
const payload = { roomData: 1 };
|
||||||
|
|
||||||
(RoomEvents as RoomExtensionRegistry).push([mockExt, handler]);
|
registryTeardowns.push(withEventRegistry(RoomEvents as RoomExtensionRegistry, [mockExt, handler]));
|
||||||
vi.mocked(hasExtension).mockReturnValue(true);
|
vi.mocked(hasExtension).mockReturnValue(true);
|
||||||
vi.mocked(getExtension).mockReturnValue(payload);
|
vi.mocked(getExtension).mockReturnValue(payload);
|
||||||
|
|
||||||
|
|
@ -413,7 +405,6 @@ describe('ProtobufService', () => {
|
||||||
(service as ProtobufInternal).processRoomEvent(event);
|
(service as ProtobufInternal).processRoomEvent(event);
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(payload, event);
|
expect(handler).toHaveBeenCalledWith(payload, event);
|
||||||
(RoomEvents as RoomExtensionRegistry).pop();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -431,14 +422,13 @@ describe('ProtobufService', () => {
|
||||||
const mockExt = {} as GenExtension<Data.SessionEvent, unknown>;
|
const mockExt = {} as GenExtension<Data.SessionEvent, unknown>;
|
||||||
const payload = { sessionData: 1 };
|
const payload = { sessionData: 1 };
|
||||||
|
|
||||||
(SessionEvents as SessionExtensionRegistry).push([mockExt, handler]);
|
registryTeardowns.push(withEventRegistry(SessionEvents as SessionExtensionRegistry, [mockExt, handler]));
|
||||||
vi.mocked(hasExtension).mockReturnValue(true);
|
vi.mocked(hasExtension).mockReturnValue(true);
|
||||||
vi.mocked(getExtension).mockReturnValue(payload);
|
vi.mocked(getExtension).mockReturnValue(payload);
|
||||||
|
|
||||||
(service as ProtobufInternal).processSessionEvent({ sessionId: 7 });
|
(service as ProtobufInternal).processSessionEvent({ sessionId: 7 });
|
||||||
|
|
||||||
expect(handler).toHaveBeenCalledWith(payload);
|
expect(handler).toHaveBeenCalledWith(payload, undefined);
|
||||||
(SessionEvents as SessionExtensionRegistry).pop();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ export class ProtobufService {
|
||||||
}
|
}
|
||||||
for (const [ext, handler] of SessionEvents) {
|
for (const [ext, handler] of SessionEvents) {
|
||||||
if (hasExtension(event, ext)) {
|
if (hasExtension(event, ext)) {
|
||||||
handler(getExtension(event, ext));
|
handler(getExtension(event, ext), undefined);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { installMockWebSocket } from '../__mocks__/helpers';
|
import { installMockWebSocket } from '../__mocks__/helpers';
|
||||||
|
import { withMockLocation } from '../../__test-utils__';
|
||||||
import { Mock } from 'vitest';
|
import { Mock } from 'vitest';
|
||||||
|
|
||||||
vi.mock('../WebClient', () => ({
|
vi.mock('../WebClient', () => ({
|
||||||
|
|
@ -37,6 +38,7 @@ let MockWS: Mock;
|
||||||
let mockInstance: ReturnType<typeof installMockWebSocket>['mockInstance'];
|
let mockInstance: ReturnType<typeof installMockWebSocket>['mockInstance'];
|
||||||
let restoreWebSocket: ReturnType<typeof installMockWebSocket>['restore'];
|
let restoreWebSocket: ReturnType<typeof installMockWebSocket>['restore'];
|
||||||
let mockConfig: WebSocketServiceConfig;
|
let mockConfig: WebSocketServiceConfig;
|
||||||
|
let locationRestores: Array<() => void>;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
|
|
@ -49,9 +51,14 @@ beforeEach(() => {
|
||||||
mockConfig = {
|
mockConfig = {
|
||||||
keepAliveFn: vi.fn(),
|
keepAliveFn: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
locationRestores = [];
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
while (locationRestores.length > 0) {
|
||||||
|
locationRestores.pop()!();
|
||||||
|
}
|
||||||
restoreWebSocket();
|
restoreWebSocket();
|
||||||
vi.useRealTimers();
|
vi.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
@ -88,22 +95,14 @@ describe('WebSocketService', () => {
|
||||||
describe('connect', () => {
|
describe('connect', () => {
|
||||||
it('creates a WebSocket with wss protocol by default', () => {
|
it('creates a WebSocket with wss protocol by default', () => {
|
||||||
const service = new WebSocketService(mockConfig);
|
const service = new WebSocketService(mockConfig);
|
||||||
Object.defineProperty(window, 'location', {
|
locationRestores.push(withMockLocation({ hostname: 'example.com' }));
|
||||||
value: { hostname: 'example.com' },
|
|
||||||
writable: true,
|
|
||||||
configurable: true,
|
|
||||||
});
|
|
||||||
service.connect({ host: 'example.com', port: '8080' });
|
service.connect({ host: 'example.com', port: '8080' });
|
||||||
expect(MockWS).toHaveBeenCalledWith('wss://example.com:8080');
|
expect(MockWS).toHaveBeenCalledWith('wss://example.com:8080');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('switches to ws protocol when hostname is localhost', () => {
|
it('switches to ws protocol when hostname is localhost', () => {
|
||||||
const service = new WebSocketService(mockConfig);
|
const service = new WebSocketService(mockConfig);
|
||||||
Object.defineProperty(window, 'location', {
|
locationRestores.push(withMockLocation({ hostname: 'localhost' }));
|
||||||
value: { hostname: 'localhost' },
|
|
||||||
writable: true,
|
|
||||||
configurable: true,
|
|
||||||
});
|
|
||||||
service.connect({ host: 'somehost', port: '1234' });
|
service.connect({ host: 'somehost', port: '1234' });
|
||||||
expect(MockWS).toHaveBeenCalledWith('ws://somehost:1234');
|
expect(MockWS).toHaveBeenCalledWith('ws://somehost:1234');
|
||||||
});
|
});
|
||||||
|
|
@ -243,22 +242,14 @@ describe('WebSocketService', () => {
|
||||||
describe('testConnect', () => {
|
describe('testConnect', () => {
|
||||||
it('creates a test WebSocket with correct URL', () => {
|
it('creates a test WebSocket with correct URL', () => {
|
||||||
const service = new WebSocketService(mockConfig);
|
const service = new WebSocketService(mockConfig);
|
||||||
Object.defineProperty(window, 'location', {
|
locationRestores.push(withMockLocation({ hostname: 'example.com' }));
|
||||||
value: { hostname: 'example.com' },
|
|
||||||
writable: true,
|
|
||||||
configurable: true,
|
|
||||||
});
|
|
||||||
service.testConnect({ host: 'example.com', port: '9000' });
|
service.testConnect({ host: 'example.com', port: '9000' });
|
||||||
expect(MockWS).toHaveBeenCalledWith('wss://example.com:9000');
|
expect(MockWS).toHaveBeenCalledWith('wss://example.com:9000');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses ws protocol on localhost', () => {
|
it('uses ws protocol on localhost', () => {
|
||||||
const service = new WebSocketService(mockConfig);
|
const service = new WebSocketService(mockConfig);
|
||||||
Object.defineProperty(window, 'location', {
|
locationRestores.push(withMockLocation({ hostname: 'localhost' }));
|
||||||
value: { hostname: 'localhost' },
|
|
||||||
writable: true,
|
|
||||||
configurable: true,
|
|
||||||
});
|
|
||||||
service.testConnect({ host: 'h', port: '1' });
|
service.testConnect({ host: 'h', port: '1' });
|
||||||
expect(MockWS).toHaveBeenCalledWith('ws://h:1');
|
expect(MockWS).toHaveBeenCalledWith('ws://h:1');
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ export class WebSocketService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public send(message: Uint8Array): void {
|
public send(message: Uint8Array): void {
|
||||||
this.socket.send(message);
|
this.socket.send(message as unknown as ArrayBufferView);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createWebSocket(url: string): WebSocket {
|
private createWebSocket(url: string): WebSocket {
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,11 @@ import { create, getExtension } from '@bufbuild/protobuf';
|
||||||
|
|
||||||
import { handleResponse } from './command-options';
|
import { handleResponse } from './command-options';
|
||||||
|
|
||||||
beforeEach(() => {
|
// NOTE: do NOT call `vi.resetAllMocks()` here — under `isolate: false` it
|
||||||
vi.resetAllMocks();
|
// resets `vi.fn()` implementations set inside other files' `vi.mock(...)`
|
||||||
});
|
// factories, which breaks any spec that relied on those factory defaults
|
||||||
|
// (e.g. ProtobufService.spec.ts expects `hasExtension` to return `false`).
|
||||||
|
// The root `setupTests.ts` afterEach already calls `vi.clearAllMocks()`.
|
||||||
|
|
||||||
describe('handleResponse', () => {
|
describe('handleResponse', () => {
|
||||||
it('calls onResponse and returns early when provided', () => {
|
it('calls onResponse and returns early when provided', () => {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
vi.mock('../../generated/proto/event_server_identification_pb', () => ({
|
vi.mock('../../generated/proto/event_server_identification_pb', async (importOriginal) => ({
|
||||||
|
...(await importOriginal<typeof import('../../generated/proto/event_server_identification_pb')>()),
|
||||||
Event_ServerIdentification_ServerOptions: { SupportsPasswordHash: 2 },
|
Event_ServerIdentification_ServerOptions: { SupportsPasswordHash: 2 },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react(), tsconfigPaths()],
|
plugins: [react()],
|
||||||
|
resolve: {
|
||||||
|
tsconfigPaths: true,
|
||||||
|
},
|
||||||
publicDir: 'public',
|
publicDir: 'public',
|
||||||
build: {
|
build: {
|
||||||
outDir: 'build',
|
outDir: 'build',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue