Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add useGame hook #1672

Merged
merged 2 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions packages/frontend/web-ui/src/game/helpers/getGameSlotIndex.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { beforeAll, describe, expect, it } from '@jest/globals';

import { models as apiModels } from '@cornie-js/api-models';

import { getGameSlotIndex } from './getGameSlotIndex';

describe(getGameSlotIndex.name, () => {
describe('having a user and a game without a slot belonging to that user', () => {
let gameFixture: apiModels.GameV1;

let userFixture: apiModels.UserV1;

beforeAll(() => {
gameFixture = {
id: 'id-fixture',
isPublic: true,
state: {
slots: [],
status: 'nonStarted',
},
};

userFixture = {
active: true,
id: 'id-fixture',
name: 'name-fixture',
};
});

describe('when called', () => {
let result: unknown;

beforeAll(() => {
result = getGameSlotIndex(gameFixture, userFixture);
});

it('should return expected result', () => {
expect(result).toBeNull();
});
});
});

describe('having a user and a game with a slot belonging to that user', () => {
let gameFixture: apiModels.GameV1;

let userFixture: apiModels.UserV1;

beforeAll(() => {
userFixture = {
active: true,
id: 'id-fixture',
name: 'name-fixture',
};

gameFixture = {
id: 'id-fixture',
isPublic: true,
state: {
slots: [
{
userId: userFixture.id,
},
],
status: 'nonStarted',
},
};
});

describe('when called', () => {
let result: unknown;

beforeAll(() => {
result = getGameSlotIndex(gameFixture, userFixture);
});

it('should return expected result', () => {
expect(result).toBe('0');
});
});
});
});
23 changes: 23 additions & 0 deletions packages/frontend/web-ui/src/game/helpers/getGameSlotIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { models as apiModels } from '@cornie-js/api-models';

export function getGameSlotIndex(
game: apiModels.GameV1 | undefined,
user: apiModels.UserV1,
): string | null {
if (game === undefined) {
return null;
}

for (let i: number = 0; i < game.state.slots.length; ++i) {
const gameSlot: apiModels.ActiveGameSlotV1 | apiModels.FinishedGameSlotV1 =
game.state.slots[i] as
| apiModels.ActiveGameSlotV1
| apiModels.FinishedGameSlotV1;

if (gameSlot.userId === user.id) {
return i.toString();
}
}

return null;
}
271 changes: 271 additions & 0 deletions packages/frontend/web-ui/src/game/hooks/useGame.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals';

jest.mock('../../common/hooks/useRedirectUnauthorized');
jest.mock('../../common/hooks/useUrlLikeLocation');
jest.mock('../../user/hooks/useGetUserMe');
jest.mock('../helpers/getGameSlotIndex');
jest.mock('./useGameCards');
jest.mock('./useGetGamesV1GameId');
jest.mock('./useGetGamesV1GameIdSlotsSlotIdCards');

import { models as apiModels } from '@cornie-js/api-models';
import { renderHook, RenderHookResult } from '@testing-library/react';

import { useRedirectUnauthorized } from '../../common/hooks/useRedirectUnauthorized';
import { useUrlLikeLocation } from '../../common/hooks/useUrlLikeLocation';
import { UrlLikeLocation } from '../../common/models/UrlLikeLocation';
import { useGetUserMe } from '../../user/hooks/useGetUserMe';
import { getGameSlotIndex } from '../helpers/getGameSlotIndex';
import { useGame, UseGameResult } from './useGame';
import { useGameCards, UseGameCardsResult } from './useGameCards';
import { useGetGamesV1GameId } from './useGetGamesV1GameId';
import { useGetGamesV1GameIdSlotsSlotIdCards } from './useGetGamesV1GameIdSlotsSlotIdCards';

describe(useGame.name, () => {
describe('when called, and queries return null result', () => {
let gameIdFixture: string;
let urlLikeLocationFixture: UrlLikeLocation;
let useGameCardsResultFixture: UseGameCardsResult;

let renderResult: RenderHookResult<UseGameResult, unknown>;

beforeAll(() => {
gameIdFixture = 'game-id-fixture';

urlLikeLocationFixture = {
pathname: '/path',
searchParams: new URLSearchParams(`?gameId=${gameIdFixture}`),
} as Partial<UrlLikeLocation> as UrlLikeLocation;

useGameCardsResultFixture = {
cards: [],
hasNext: false,
hasPrevious: false,
setNext: jest.fn(),
setPrevious: jest.fn(),
};

(
useUrlLikeLocation as jest.Mock<typeof useUrlLikeLocation>
).mockReturnValueOnce(urlLikeLocationFixture);

(useGetUserMe as jest.Mock<typeof useGetUserMe>).mockReturnValueOnce({
result: null,
});

(
useGetGamesV1GameId as jest.Mock<typeof useGetGamesV1GameId>
).mockReturnValueOnce({ result: null });

(
useGetGamesV1GameIdSlotsSlotIdCards as jest.Mock<
typeof useGetGamesV1GameIdSlotsSlotIdCards
>
).mockReturnValueOnce({ result: null });

(useGameCards as jest.Mock<typeof useGameCards>).mockReturnValueOnce(
useGameCardsResultFixture,
);

renderResult = renderHook(() => useGame());
});

afterAll(() => {
jest.clearAllMocks();
});

it('should call useRedirectUnauthorized()', () => {
expect(useRedirectUnauthorized).toHaveBeenCalledTimes(1);
expect(useRedirectUnauthorized).toHaveBeenCalledWith();
});

it('should call useGetUserMe()', () => {
expect(useGetUserMe).toHaveBeenCalledTimes(1);
expect(useGetUserMe).toHaveBeenCalledWith();
});

it('should call useGetGamesV1GameId()', () => {
expect(useGetGamesV1GameId).toHaveBeenCalledTimes(1);
expect(useGetGamesV1GameId).toHaveBeenCalledWith(gameIdFixture);
});

it('should not call getGameSlotIndex()', () => {
expect(getGameSlotIndex).not.toHaveBeenCalled();
});

it('should call useGetGamesV1GameIdSlotsSlotIdCards()', () => {
expect(useGetGamesV1GameIdSlotsSlotIdCards).toHaveBeenCalledTimes(1);
expect(useGetGamesV1GameIdSlotsSlotIdCards).toHaveBeenCalledWith(
gameIdFixture,
null,
);
});

it('should call useGameCards()', () => {
expect(useGameCards).toHaveBeenCalledTimes(1);
expect(useGameCards).toHaveBeenCalledWith([]);
});

it('should retuen expected result', () => {
const expected: UseGameResult = {
currentCard: undefined,
game: undefined,
isPending: true,
useGameCardsResult: useGameCardsResultFixture,
};

expect(renderResult.result.current).toStrictEqual(expected);
});
});

describe('when called, and queries return non null results', () => {
let gameCardsFixture: apiModels.CardArrayV1;
let gameFixture: apiModels.ActiveGameV1;
let gameIdFixture: string;
let gameSlotIndexFixture: string;
let urlLikeLocationFixture: UrlLikeLocation;
let userFixture: apiModels.UserV1;
let useGameCardsResultFixture: UseGameCardsResult;

let renderResult: RenderHookResult<UseGameResult, unknown>;

beforeAll(() => {
gameCardsFixture = [
{
kind: 'wildDraw4',
},
];

gameFixture = {
id: 'game-id-fixture',
isPublic: true,
state: {
currentCard: {
kind: 'wild',
},
currentColor: 'blue',
currentDirection: 'clockwise',
currentPlayingSlotIndex: 0,
currentTurnCardsDrawn: false,
currentTurnCardsPlayed: false,
drawCount: 0,
lastEventId: 'last-event-id-fixture',
slots: [],
status: 'active',
},
};

gameSlotIndexFixture = '0';

userFixture = {
active: true,
id: 'user-id-fixture',
name: 'user-name-fixture',
};

gameIdFixture = gameFixture.id;

urlLikeLocationFixture = {
pathname: '/path',
searchParams: new URLSearchParams(`?gameId=${gameIdFixture}`),
} as Partial<UrlLikeLocation> as UrlLikeLocation;

useGameCardsResultFixture = {
cards: [],
hasNext: false,
hasPrevious: false,
setNext: jest.fn(),
setPrevious: jest.fn(),
};

(
useUrlLikeLocation as jest.Mock<typeof useUrlLikeLocation>
).mockReturnValueOnce(urlLikeLocationFixture);

(useGetUserMe as jest.Mock<typeof useGetUserMe>).mockReturnValueOnce({
result: {
isRight: true,
value: userFixture,
},
});

(
useGetGamesV1GameId as jest.Mock<typeof useGetGamesV1GameId>
).mockReturnValueOnce({
result: {
isRight: true,
value: gameFixture,
},
});

(
useGetGamesV1GameIdSlotsSlotIdCards as jest.Mock<
typeof useGetGamesV1GameIdSlotsSlotIdCards
>
).mockReturnValueOnce({
result: {
isRight: true,
value: gameCardsFixture,
},
});

(
getGameSlotIndex as jest.Mock<typeof getGameSlotIndex>
).mockReturnValueOnce(gameSlotIndexFixture);

(useGameCards as jest.Mock<typeof useGameCards>).mockReturnValueOnce(
useGameCardsResultFixture,
);

renderResult = renderHook(() => useGame());
});

afterAll(() => {
jest.clearAllMocks();
});

it('should call useRedirectUnauthorized()', () => {
expect(useRedirectUnauthorized).toHaveBeenCalledTimes(1);
expect(useRedirectUnauthorized).toHaveBeenCalledWith();
});

it('should call useGetUserMe()', () => {
expect(useGetUserMe).toHaveBeenCalledTimes(1);
expect(useGetUserMe).toHaveBeenCalledWith();
});

it('should call useGetGamesV1GameId()', () => {
expect(useGetGamesV1GameId).toHaveBeenCalledTimes(1);
expect(useGetGamesV1GameId).toHaveBeenCalledWith(gameIdFixture);
});

it('should call getGameSlotIndex()', () => {
expect(getGameSlotIndex).toHaveBeenCalledTimes(1);
expect(getGameSlotIndex).toHaveBeenCalledWith(gameFixture, userFixture);
});

it('should call useGetGamesV1GameIdSlotsSlotIdCards()', () => {
expect(useGetGamesV1GameIdSlotsSlotIdCards).toHaveBeenCalledTimes(1);
expect(useGetGamesV1GameIdSlotsSlotIdCards).toHaveBeenCalledWith(
gameIdFixture,
gameSlotIndexFixture,
);
});

it('should call useGameCards()', () => {
expect(useGameCards).toHaveBeenCalledTimes(1);
expect(useGameCards).toHaveBeenCalledWith(gameCardsFixture);
});

it('should retuen expected result', () => {
const expected: UseGameResult = {
currentCard: gameFixture.state.currentCard,
game: gameFixture,
isPending: false,
useGameCardsResult: useGameCardsResultFixture,
};

expect(renderResult.result.current).toStrictEqual(expected);
});
});
});
Loading