diff --git a/components/level/game.tsx b/components/level/game.tsx index e71ae11ee..83a42a71a 100644 --- a/components/level/game.tsx +++ b/components/level/game.tsx @@ -1,3 +1,4 @@ +import Direction, { directionToPosition, getDirectionFromCode } from '@root/constants/direction'; import { GameContext } from '@root/contexts/gameContext'; import { CheckpointState, convertFromCheckpointState, convertToCheckpointState, isValidCheckpointState } from '@root/helpers/checkpointHelpers'; import isPro from '@root/helpers/isPro'; @@ -18,7 +19,7 @@ import BlockState from '../../models/blockState'; import Control from '../../models/control'; import Level, { EnrichedLevel } from '../../models/db/level'; import Move from '../../models/move'; -import Position, { getDirectionFromCode } from '../../models/position'; +import Position from '../../models/position'; import SquareState from '../../models/squareState'; import GameLayout from './gameLayout'; @@ -128,7 +129,7 @@ export default function Game({ onStatsSuccess, }: GameProps) { const [gameState, setGameState] = useState(initGameState(level.data)); - const [lastCodes, setLastCodes] = useState([]); + const lastDirections = useRef([]); const levelContext = useContext(LevelContext); const [localSessionRestored, setLocalSessionRestored] = useState(false); const [madeMove, setMadeMove] = useState(false); @@ -224,13 +225,13 @@ export default function Game({ fetchPlayAttempt(); }, [disablePlayAttempts, fetchPlayAttempt, gameState.actionCount, madeMove]); - const trackStats = useCallback((codes: string[], levelId: string, maxRetries: number) => { + const trackStats = useCallback((directions: Direction[], levelId: string, maxRetries: number) => { if (disableStats) { return; } - // if codes array is identical to lastCodes array, don't PUT stats - if (codes.length === lastCodes.length && codes.every((code, index) => code === lastCodes[index])) { + // if directions array is identical to lastDirections array, don't PUT stats + if (directions.length === lastDirections.current.length && directions.every((direction, index) => direction === lastDirections.current[index])) { return; } @@ -239,7 +240,7 @@ export default function Game({ fetch('/api/stats', { method: 'PUT', body: JSON.stringify({ - codes: codes, + directions: directions, levelId: levelId, matchId: matchId, }), @@ -263,7 +264,7 @@ export default function Game({ onStatsSuccess(); } - setLastCodes(codes); + lastDirections.current = directions; } else if (res.status === 500) { throw res.text(); } else { @@ -276,17 +277,17 @@ export default function Game({ }).catch(async err => { const error = JSON.parse(await err)?.error; - console.error(`Error updating stats: { codes: ${codes}, levelId: ${levelId} }`, error); + console.error(`Error updating stats: { directions: ${directions}, levelId: ${levelId} }`, error); toast.dismiss(); toast.error(`Error updating stats: ${error}`, { duration: 3000 }); if (maxRetries > 0) { - trackStats(codes, levelId, maxRetries - 1); + trackStats(directions, levelId, maxRetries - 1); } }).finally(() => { NProgress.done(); }); - }, [disableStats, lastCodes, matchId, mutateLevel, mutateProStatsLevel, mutateUser, onStatsSuccess]); + }, [disableStats, matchId, mutateLevel, mutateProStatsLevel, mutateUser, onStatsSuccess]); const saveCheckpoint = useCallback((slot: number) => { if (slot !== BEST_CHECKPOINT_INDEX) { @@ -583,9 +584,8 @@ export default function Game({ // undo the block push if (prevMove.blockId !== undefined) { const block = getBlockById(blocks, prevMove.blockId); - const direction = getDirectionFromCode(prevMove.code); - if (!block || !direction) { + if (!block) { return prevGameState; } @@ -596,7 +596,7 @@ export default function Game({ } // move the block back to its original position - block.pos = block.pos.sub(direction); + block.pos = block.pos.sub(directionToPosition(prevMove.direction)); } const newGameState: GameState = { @@ -613,19 +613,19 @@ export default function Game({ return newGameState; } - function makeMove(direction: Position) { + function makeMove(direction: Direction) { // if the position didn't change or the new position is invalid if (!isPlayerPositionValid(board, prevGameState.height, pos, prevGameState.width)) { return prevGameState; } const blockIndex = getBlockIndexAtPosition(blocks, pos); - const move = new Move(code, prevGameState.pos); + const move = new Move(direction, prevGameState.pos); // if there is a block at the new position if (blockIndex !== -1) { const block = blocks[blockIndex]; - const blockPos = block.pos.add(direction); + const blockPos = block.pos.add(directionToPosition(direction)); // if the block is not allowed to move this direction or the new position is invalid if (!block.canMoveTo(blockPos) || @@ -656,7 +656,7 @@ export default function Game({ const moveCount = prevGameState.moveCount + 1; if (board[pos.y][pos.x].tileType === TileType.End) { - trackStats(moves.map(move => move.code), level._id.toString(), 3); + trackStats(moves.map(move => move.direction), level._id.toString(), 3); } const newGameState: GameState = { @@ -705,7 +705,7 @@ export default function Game({ } // calculate the target tile to move to - const pos = prevGameState.pos.add(direction); + const pos = prevGameState.pos.add(directionToPosition(direction)); // before making a move, check if undo is a better choice function checkForFreeUndo() { diff --git a/components/tutorial.tsx b/components/tutorial.tsx index 8d6559876..cec14fdef 100644 --- a/components/tutorial.tsx +++ b/components/tutorial.tsx @@ -1,6 +1,7 @@ /* istanbul ignore file */ import { createPopper, Instance, Placement } from '@popperjs/core'; +import { directionToPosition } from '@root/constants/direction'; import TileType from '@root/constants/tileType'; import classNames from 'classnames'; import { Types } from 'mongoose'; @@ -10,7 +11,7 @@ import { AppContext } from '../contexts/appContext'; import { TimerUtil } from '../helpers/getTs'; import Control from '../models/control'; import Level from '../models/db/level'; -import Position, { getDirectionFromCode } from '../models/position'; +import Position from '../models/position'; import DismissToast from './dismissToast'; import BasicLayout from './level/basicLayout'; import Controls from './level/controls'; @@ -421,9 +422,9 @@ export default function Tutorial() { // notify the user to undo if they have gone past the exit (too far right or down) // or if they have gone left or up at any point if (gameState.pos.x > 4 || gameState.pos.y > 3 || gameState.moves.some(move => { - const direction = getDirectionFromCode(move.code); + const pos = directionToPosition(move.direction); - return direction?.equals(new Position(-1, 0)) || direction?.equals(new Position(0, -1)); + return pos.equals(new Position(-1, 0)) || pos.equals(new Position(0, -1)); })) { undoButton?.classList.add(styles['highlight-red']); } else { diff --git a/constants/direction.ts b/constants/direction.ts new file mode 100644 index 000000000..8e44351ad --- /dev/null +++ b/constants/direction.ts @@ -0,0 +1,37 @@ +import Position from '@root/models/position'; + +enum Direction { + LEFT = 1, + UP, + RIGHT, + DOWN, +} + +export function getDirectionFromCode(code: string) { + if (code === 'ArrowLeft' || code === 'KeyA') { + return Direction.LEFT; + } else if (code === 'ArrowUp' || code === 'KeyW') { + return Direction.UP; + } else if (code === 'ArrowRight' || code === 'KeyD') { + return Direction.RIGHT; + } else if (code === 'ArrowDown' || code === 'KeyS') { + return Direction.DOWN; + } else { + return undefined; + } +} + +export function directionToPosition(direction: Direction) { + switch (direction) { + case Direction.LEFT: + return new Position(-1, 0); + case Direction.UP: + return new Position(0, -1); + case Direction.RIGHT: + return new Position(1, 0); + case Direction.DOWN: + return new Position(0, 1); + } +} + +export default Direction; diff --git a/helpers/checkpointHelpers.ts b/helpers/checkpointHelpers.ts index 1302d6b90..13401d8ba 100644 --- a/helpers/checkpointHelpers.ts +++ b/helpers/checkpointHelpers.ts @@ -1,8 +1,9 @@ import { GameState } from '@root/components/level/game'; +import Direction, { directionToPosition, getDirectionFromCode } from '@root/constants/direction'; import TileType from '@root/constants/tileType'; import BlockState from '@root/models/blockState'; import Move from '@root/models/move'; -import Position, { getDirectionFromCode } from '@root/models/position'; +import Position from '@root/models/position'; import SquareState from '@root/models/squareState'; interface CheckpointSquareState { @@ -53,6 +54,19 @@ export function isValidCheckpointState(value: unknown) { return true; } +function directionToCode(direction: Direction) { + switch (direction) { + case Direction.LEFT: + return 'ArrowLeft'; + case Direction.UP: + return 'ArrowUp'; + case Direction.RIGHT: + return 'ArrowRight'; + case Direction.DOWN: + return 'ArrowDown'; + } +} + export function convertToCheckpointState(gameState: GameState) { const blocks = gameState.blocks.map(block => BlockState.clone(block)); const checkpointState: CheckpointState = { @@ -72,17 +86,16 @@ export function convertToCheckpointState(gameState: GameState) { moveCount: gameState.moveCount, moves: gameState.moves.map(move => { const checkpointMove: CheckpointMove = { - code: move.code, + code: directionToCode(move.direction), pos: move.pos.clone(), }; if (move.blockId !== undefined) { const block = blocks.find(b => b.id === move.blockId); - const direction = getDirectionFromCode(move.code); - if (block && direction) { + if (block) { checkpointMove.block = block.clone(); - checkpointMove.block.pos = checkpointMove.block.pos.sub(direction); + checkpointMove.block.pos = checkpointMove.block.pos.sub(directionToPosition(move.direction)); if (block.inHole) { checkpointMove.block.inHole = false; @@ -110,8 +123,14 @@ export function convertFromCheckpointState(checkpointState: CheckpointState) { height: checkpointState.height, moveCount: checkpointState.moveCount, moves: checkpointState.moves.map(checkpointMove => { + const direction = getDirectionFromCode(checkpointMove.code); + + if (!direction) { + throw new Error(`Invalid checkpoint code ${checkpointMove.code}`); + } + return new Move( - checkpointMove.code, + direction, new Position(checkpointMove.pos.x, checkpointMove.pos.y), checkpointMove.block?.id, ); diff --git a/helpers/validateSolution.ts b/helpers/validateSolution.ts index f93b7ddd7..cf388a375 100644 --- a/helpers/validateSolution.ts +++ b/helpers/validateSolution.ts @@ -1,9 +1,10 @@ +import Direction, { directionToPosition } from '@root/constants/direction'; import TileType from '@root/constants/tileType'; import TileTypeHelper from '@root/helpers/tileTypeHelper'; import Level from '../models/db/level'; -import Position, { getDirectionFromCode } from '../models/position'; +import Position from '../models/position'; -export default function validateSolution(codes: string[], level: Level) { +export default function validateSolution(directions: Direction[], level: Level) { const data = level.data.replace(/\n/g, '').split('') as TileType[]; const endIndices = []; const posIndex = data.indexOf(TileType.Start); @@ -14,20 +15,21 @@ export default function validateSolution(codes: string[], level: Level) { endIndices.push(endIndex); } - for (let i = 0; i < codes.length; i++) { + for (let i = 0; i < directions.length; i++) { // cannot continue moving if already on an exit if (data[pos.y * level.width + pos.x] === TileType.End) { return false; } - const direction = getDirectionFromCode(codes[i]); + const direction = directions[i]; - if (!direction) { + // account for bad user input from the API + if (!(direction in Direction)) { return false; } // validate and update position with direction - pos = pos.add(direction); + pos = pos.add(directionToPosition(direction)); if (pos.x < 0 || pos.x >= level.width || pos.y < 0 || pos.y >= level.height) { return false; @@ -45,15 +47,15 @@ export default function validateSolution(codes: string[], level: Level) { // if a block is being moved if (TileTypeHelper.canMove(tileTypeAtPos)) { // validate block is allowed to move in this direction - if ((direction.equals(new Position(-1, 0)) && !TileTypeHelper.canMoveLeft(tileTypeAtPos)) || - (direction.equals(new Position(0, -1)) && !TileTypeHelper.canMoveUp(tileTypeAtPos)) || - (direction.equals(new Position(1, 0)) && !TileTypeHelper.canMoveRight(tileTypeAtPos)) || - (direction.equals(new Position(0, 1)) && !TileTypeHelper.canMoveDown(tileTypeAtPos))) { + if ((direction === Direction.LEFT && !TileTypeHelper.canMoveLeft(tileTypeAtPos)) || + (direction === Direction.UP && !TileTypeHelper.canMoveUp(tileTypeAtPos)) || + (direction === Direction.RIGHT && !TileTypeHelper.canMoveRight(tileTypeAtPos)) || + (direction === Direction.DOWN && !TileTypeHelper.canMoveDown(tileTypeAtPos))) { return false; } // validate and update block position with direction - const blockPos = pos.add(direction); + const blockPos = pos.add(directionToPosition(direction)); if (blockPos.x < 0 || blockPos.x >= level.width || blockPos.y < 0 || blockPos.y >= level.height) { return false; diff --git a/models/move.ts b/models/move.ts index b98a32772..268be516d 100644 --- a/models/move.ts +++ b/models/move.ts @@ -1,22 +1,22 @@ +import Direction from '@root/constants/direction'; import Position from './position'; export default class Move { - // keycode of the move direction - code: string; + direction: Direction; // position before the move pos: Position; // the id of the block pushed during this move blockId?: number; - constructor(code: string, pos: Position, blockId?: number) { - this.code = code; + constructor(direction: Direction, pos: Position, blockId?: number) { + this.direction = direction; this.pos = pos.clone(); this.blockId = blockId; } static clone(move: Move) { return new Move( - move.code, + move.direction, new Position(move.pos.x, move.pos.y), move.blockId, ); @@ -24,7 +24,7 @@ export default class Move { clone() { return new Move( - this.code, + this.direction, this.pos, this.blockId, ); diff --git a/models/position.ts b/models/position.ts index e639a048b..cdc1a8c4b 100644 --- a/models/position.ts +++ b/models/position.ts @@ -32,17 +32,3 @@ export default class Position { ); } } - -export function getDirectionFromCode(code: string) { - if (code === 'ArrowLeft' || code === 'KeyA') { - return new Position(-1, 0); - } else if (code === 'ArrowUp' || code === 'KeyW') { - return new Position(0, -1); - } else if (code === 'ArrowRight' || code === 'KeyD') { - return new Position(1, 0); - } else if (code === 'ArrowDown' || code === 'KeyS') { - return new Position(0, 1); - } else { - return undefined; - } -} diff --git a/pages/api/stats/index.ts b/pages/api/stats/index.ts index 6a70812ed..f5ed05062 100644 --- a/pages/api/stats/index.ts +++ b/pages/api/stats/index.ts @@ -1,4 +1,5 @@ import AchievementInfo from '@root/constants/achievementInfo'; +import Direction, { getDirectionFromCode } from '@root/constants/direction'; import getDifficultyEstimate from '@root/helpers/getDifficultyEstimate'; import User from '@root/models/db/user'; import { AttemptContext } from '@root/models/schemas/playAttemptSchema'; @@ -34,7 +35,8 @@ export default withAuth({ GET: {}, PUT: { body: { - codes: ValidArray(), + codes: ValidArray(false), + directions: ValidArray(false), levelId: ValidObjectId(), matchId: ValidType('string', false), } @@ -45,7 +47,16 @@ export default withAuth({ return res.status(200).json(stats); } else if (req.method === 'PUT') { - const { codes, levelId, matchId } = req.body; + const { codes, directions, levelId, matchId } = req.body; + + if (!directions && !codes) { + return res.status(400).json({ + error: 'No directions or codes provided', + }); + } + + const dirs: Direction[] = directions ?? codes.map((code: string) => getDirectionFromCode(code)); + const ts = TimerUtil.getTs(); const session = await mongoose.startSession(); // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -67,13 +78,13 @@ export default withAuth({ throw new Error(resTrack.json.error); } - if (!validateSolution(codes, level)) { + if (!validateSolution(dirs, level)) { resTrack.status = 400; resTrack.json.error = `Invalid solution provided for level ${levelId}`; throw new Error(resTrack.json.error); } - const moves = codes.length; + const moves = dirs.length; // ensure no stats are saved for draft levels if (level.isDraft || level.leastMoves === 0) { diff --git a/tests/models/models.test.ts b/tests/models/models.test.ts index 842687a69..826ab8b29 100644 --- a/tests/models/models.test.ts +++ b/tests/models/models.test.ts @@ -1,3 +1,4 @@ +import Direction, { getDirectionFromCode } from '@root/constants/direction'; import TileType from '@root/constants/tileType'; import TestId from '../../constants/testId'; import dbConnect, { dbDisconnect } from '../../lib/dbConnect'; @@ -6,7 +7,7 @@ import Control from '../../models/control'; import User from '../../models/db/user'; import { LevelModel, UserModel } from '../../models/mongoose'; import Move from '../../models/move'; -import Position, { getDirectionFromCode } from '../../models/position'; +import Position from '../../models/position'; import { calcPlayAttempts } from '../../models/schemas/levelSchema'; import SelectOptionStats from '../../models/selectOptionStats'; import SquareState from '../../models/squareState'; @@ -73,7 +74,7 @@ describe('models/*.ts', () => { expect(getDirectionFromCode('KeyB')).toBe(undefined); }); test('Move', () => { - const move = new Move('code', new Position(1, 1), 0); + const move = new Move(Direction.LEFT, new Position(1, 1), 0); const move2 = move.clone(); const move3 = Move.clone(move); diff --git a/tests/pages/api/level/edit_levels.test.ts b/tests/pages/api/level/edit_levels.test.ts index 01af0cf05..0cd83f182 100644 --- a/tests/pages/api/level/edit_levels.test.ts +++ b/tests/pages/api/level/edit_levels.test.ts @@ -1,3 +1,4 @@ +import Direction from '@root/constants/direction'; import { enableFetchMocks } from 'jest-fetch-mock'; import { Types, UpdateQuery } from 'mongoose'; import { testApiHandler } from 'next-test-api-route-handler'; @@ -369,15 +370,15 @@ describe('Editing levels should work correctly', () => { }, body: { levelId: level_id_1, - codes: [ - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', + directions: [ + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, ], }, headers: { @@ -502,15 +503,15 @@ describe('Editing levels should work correctly', () => { }, body: { levelId: level_id_1, - codes: [ - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', + directions: [ + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, ], }, headers: { diff --git a/tests/pages/api/level/level.byid.test.ts b/tests/pages/api/level/level.byid.test.ts index 0b6009d79..cd94668f7 100644 --- a/tests/pages/api/level/level.byid.test.ts +++ b/tests/pages/api/level/level.byid.test.ts @@ -1,3 +1,4 @@ +import Direction from '@root/constants/direction'; import { enableFetchMocks } from 'jest-fetch-mock'; import { Types } from 'mongoose'; import { testApiHandler } from 'next-test-api-route-handler'; @@ -744,7 +745,7 @@ describe('pages/api/level/index.ts', () => { token: getTokenCookieValue(TestId.USER_B), }, body: { - codes: ['ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowDown', 'ArrowDown'], + directions: [Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.DOWN, Direction.DOWN], levelId: test_level_id_delete }, headers: { diff --git a/tests/pages/api/match/matchCreateJoinAndPlay.test.ts b/tests/pages/api/match/matchCreateJoinAndPlay.test.ts index c7b280246..70e36b8a2 100644 --- a/tests/pages/api/match/matchCreateJoinAndPlay.test.ts +++ b/tests/pages/api/match/matchCreateJoinAndPlay.test.ts @@ -1,3 +1,4 @@ +import Direction from '@root/constants/direction'; import { enableFetchMocks } from 'jest-fetch-mock'; import MockDate from 'mockdate'; import { testApiHandler } from 'next-test-api-route-handler'; @@ -203,7 +204,7 @@ describe('matchCreateJoinAndPlay', () => { token: getTokenCookieValue(TestId.USER), }, body: { - codes: ['ArrowRight'], + directions: [Direction.RIGHT], levelId: levels[0]._id, matchId: matchId, // Here we go }, diff --git a/tests/pages/api/match/matchUnpublishLevelInMatch.test.ts b/tests/pages/api/match/matchUnpublishLevelInMatch.test.ts index fb8f4eb00..5134e44d1 100644 --- a/tests/pages/api/match/matchUnpublishLevelInMatch.test.ts +++ b/tests/pages/api/match/matchUnpublishLevelInMatch.test.ts @@ -1,3 +1,4 @@ +import Direction from '@root/constants/direction'; import { enableFetchMocks } from 'jest-fetch-mock'; import MockDate from 'mockdate'; import { testApiHandler } from 'next-test-api-route-handler'; @@ -207,7 +208,7 @@ describe('matchCreateJoinAndPlay', () => { token: getTokenCookieValue(TestId.USER), }, body: { - codes: ['ArrowRight'], + directions: [Direction.RIGHT], levelId: levels[0]._id, matchId: matchId, // Here we go }, diff --git a/tests/pages/api/play-attempt/play-attempt.test.ts b/tests/pages/api/play-attempt/play-attempt.test.ts index 312cbb757..9b266ae54 100644 --- a/tests/pages/api/play-attempt/play-attempt.test.ts +++ b/tests/pages/api/play-attempt/play-attempt.test.ts @@ -1,3 +1,4 @@ +import Direction from '@root/constants/direction'; import { enableFetchMocks } from 'jest-fetch-mock'; import { Types } from 'mongoose'; import { testApiHandler } from 'next-test-api-route-handler'; @@ -535,27 +536,27 @@ describe('Testing stats api', () => { }, body: { levelId: t.levelId, - codes: [ - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowDown', + directions: [ + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.DOWN, ], }, headers: { @@ -582,17 +583,17 @@ describe('Testing stats api', () => { }, body: { levelId: t.levelId, - codes: [ - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowDown', + directions: [ + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.DOWN, ], }, headers: { @@ -621,15 +622,15 @@ describe('Testing stats api', () => { }, body: { levelId: t.levelId, - codes: [ - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', + directions: [ + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, ], }, headers: { @@ -919,27 +920,27 @@ describe('Testing stats api', () => { }, body: { levelId: level._id, - codes: [ - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowRight', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowUp', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', - 'ArrowDown', + directions: [ + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.RIGHT, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.UP, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, + Direction.DOWN, ], }, headers: { diff --git a/tests/pages/api/stats/stats.race.test.ts b/tests/pages/api/stats/stats.race.test.ts index 7bb173842..40ca06b72 100644 --- a/tests/pages/api/stats/stats.race.test.ts +++ b/tests/pages/api/stats/stats.race.test.ts @@ -1,3 +1,4 @@ +import Direction from '@root/constants/direction'; import { enableFetchMocks } from 'jest-fetch-mock'; import { testApiHandler } from 'next-test-api-route-handler'; import TestId from '../../../../constants/testId'; @@ -18,10 +19,10 @@ afterAll(async () => { }); enableFetchMocks(); -const SOL_14 = ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowLeft', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown']; -const SOL_12 = ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'ArrowDown']; +const SOL_14 = [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.UP, Direction.LEFT, Direction.LEFT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN]; +const SOL_12 = [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.LEFT, Direction.UP, Direction.DOWN, Direction.DOWN]; -async function sendStat(user: string, solution: string[]) { +async function sendStat(user: string, solution: Direction[]) { await testApiHandler({ handler: async (_, res) => { const req: NextApiRequestWithAuth = { @@ -31,7 +32,7 @@ async function sendStat(user: string, solution: string[]) { }, body: { - codes: solution, + directions: solution, levelId: TestId.LEVEL }, headers: { diff --git a/tests/pages/api/stats/stats.test.ts b/tests/pages/api/stats/stats.test.ts index 824b5c33b..4407b5b58 100644 --- a/tests/pages/api/stats/stats.test.ts +++ b/tests/pages/api/stats/stats.test.ts @@ -1,3 +1,4 @@ +import Direction from '@root/constants/direction'; import Stat from '@root/models/db/stat'; import { enableFetchMocks } from 'jest-fetch-mock'; import { Types } from 'mongoose'; @@ -130,7 +131,7 @@ describe('Testing stats api', () => { const res = await fetch(); const response = await res.json(); - expect(response.error).toBe('Invalid body.codes, body.levelId'); + expect(response.error).toBe('Invalid body.levelId'); expect(res.status).toBe(400); }, }); @@ -146,7 +147,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER), }, body: { - codes: '12345', + directions: '12345', levelId: TestId.LEVEL }, headers: { @@ -160,7 +161,7 @@ describe('Testing stats api', () => { const res = await fetch(); const response = await res.json(); - expect(response.error).toBe('Invalid body.codes'); + expect(response.error).toBe('Invalid body.directions'); expect(res.status).toBe(400); }, }); @@ -177,7 +178,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER), }, body: { - codes: ['ArrowRight'], + directions: [Direction.RIGHT], levelId: levelId, }, headers: { @@ -200,14 +201,14 @@ describe('Testing stats api', () => { jest.spyOn(logger, 'error').mockImplementation(() => ({} as Logger)); const codeTests = [ - ['ArrowLeft'], // test left border - ['WRONG', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowRight'], // test invalid - ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowLeft'], // tries to go over hole - ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowDown', 'ArrowDown'], // tries to push directional movable where it cant be pushed - ['ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowRight'], // tries to push directional movable where it cant be pushed because of edge - ['ArrowDown'], // run into wall - ['ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowRight'], // tries to push directional movable where it cant be pushed because something in way - ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowLeft'], // push movable into wall + [Direction.LEFT], // test left border + [5, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT], // test invalid + [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.LEFT, Direction.LEFT], // tries to go over hole + [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.DOWN, Direction.DOWN], // tries to push directional movable where it cant be pushed + [Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT], // tries to push directional movable where it cant be pushed because of edge + [Direction.DOWN], // run into wall + [Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.RIGHT], // tries to push directional movable where it cant be pushed because something in way + [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.LEFT], // push movable into wall ]; for (const codeTest of codeTests) { @@ -219,7 +220,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER), }, body: { - codes: codeTest, + directions: codeTest, levelId: TestId.LEVEL }, headers: { @@ -260,7 +261,7 @@ describe('Testing stats api', () => { }, body: { - codes: ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowLeft', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown'], + directions: [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.UP, Direction.LEFT, Direction.LEFT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: { @@ -296,7 +297,7 @@ describe('Testing stats api', () => { }, body: { - codes: ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowLeft', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown'], + directions: [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.UP, Direction.LEFT, Direction.LEFT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: { @@ -333,7 +334,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER_B), }, body: { - codes: ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowLeft', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown'], + directions: [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.UP, Direction.LEFT, Direction.LEFT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL, }, headers: { @@ -373,7 +374,7 @@ describe('Testing stats api', () => { }, body: { - codes: ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'ArrowDown'], + directions: [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.LEFT, Direction.UP, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: { @@ -441,7 +442,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER_B), }, body: { - codes: ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowLeft', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown'], + directions: [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.UP, Direction.LEFT, Direction.LEFT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: { @@ -479,7 +480,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER_B), }, body: { - codes: ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowUp', 'ArrowLeft', 'ArrowLeft', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown'], + directions: [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.UP, Direction.LEFT, Direction.LEFT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: { @@ -521,7 +522,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER_B), }, body: { - codes: ['ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'ArrowDown'], + directions: [Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.LEFT, Direction.UP, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: { @@ -564,7 +565,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER_B), }, body: { - codes: [ 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowDown'], + directions: [ Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: { @@ -617,7 +618,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER_C), }, body: { - codes: [ 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowDown'], + directions: [ Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: { @@ -676,7 +677,7 @@ describe('Testing stats api', () => { token: getTokenCookieValue(TestId.USER_B), }, body: { - codes: [ 'ArrowRight', 'ArrowDown', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowDown', 'ArrowDown', 'ArrowDown'], + directions: [ Direction.RIGHT, Direction.DOWN, Direction.RIGHT, Direction.RIGHT, Direction.RIGHT, Direction.DOWN, Direction.DOWN, Direction.DOWN], levelId: TestId.LEVEL }, headers: {