nodewords
Version:
Command line word games
282 lines (233 loc) • 8.97 kB
JavaScript
/* eslint-env jest */
/* eslint-disable no-return-assign, global-require, prefer-destructuring */
const MockHelper = require('../../../../test/helpers/mock-helper');
const PromiseSpy = require('../../../../test/helpers/promise-spy');
const hangmanConstants = require('../hangman-constants');
const gameConstants = require('../../base-game-constants');
const hangmanStages = require('../hangman-stages');
describe('Hangman', () => {
let hangmanGame;
let clearSpy;
let mockChalk;
let mockLogger;
let mockUiHelper;
let mockPrompts;
let mockWordList;
let playResolved;
beforeEach(() => {
MockHelper.mockFiglet();
clearSpy = MockHelper.mockClear();
mockChalk = MockHelper.mockChalk();
mockLogger = MockHelper.mockLogger();
mockUiHelper = MockHelper.mockUiHelper();
mockPrompts = {
promptForGuess: new PromiseSpy(),
promptForLetter: new PromiseSpy(),
promptForAnswer: new PromiseSpy()
};
jest.mock('../hangman-prompts', () => mockPrompts);
jest.mock('../../word-list', () => mockWordList = ['coconut', 'pebble', 'eye']);
jest.spyOn(Math, 'random').mockReturnValue(0);
const HangmanGame = require('../hangman');
hangmanGame = new HangmanGame();
hangmanGame.play().then(() => { playResolved = true; });
});
afterEach(() => {
jest.resetModules();
});
function showLetterPrompt() {
mockPrompts.promptForGuess.onSuccess({ guess: hangmanConstants.LETTER });
}
function showAnswerPrompt() {
mockPrompts.promptForGuess.onSuccess({ guess: hangmanConstants.ANSWER });
}
function guessLetter(letter) {
mockPrompts.promptForLetter.onSuccess({ letter });
}
function guessAnswer(answer) {
mockPrompts.promptForAnswer.onSuccess({ answer });
}
describe('Starting the game', () => {
it('clears the console', () => {
expect(clearSpy).toHaveBeenCalled();
});
it('randomly picks a word', () => {
const expected = mockWordList[0];
expect(hangmanGame.word).toBe(expected);
});
it('displays game title and info', () => {
expect(mockLogger.log).toHaveBeenCalledWith(hangmanConstants.GAME_TITLE);
expect(mockLogger.log).toHaveBeenCalledWith(hangmanConstants.GAME_INFO);
});
it('displays placeholder per letter in word', () => {
const expected = Array(mockWordList[0].length).fill('_').join('');
expect(mockLogger.log).toHaveBeenCalledWith(expected);
});
it('displays prompt asking user what to do', () => {
expect(mockPrompts.promptForGuess).toHaveBeenCalled();
});
});
describe('Select to guess a letter', () => {
beforeEach(() => {
showLetterPrompt();
});
it('prompts user for letter', () => {
expect(mockPrompts.promptForLetter).toHaveBeenCalled();
});
describe('and letter is correct', () => {
it('displays guessed letter in correct place in word', () => {
guessLetter('t');
expect(mockLogger.log).toHaveBeenCalledWith('______t');
});
it('displays multiple guessed letters in correct place if more than one occurence', () => {
guessLetter('c');
expect(mockLogger.log).toHaveBeenCalledWith('c_c____');
});
it('still displays previously correctly guessed letters', () => {
guessLetter('t');
guessLetter('c');
expect(mockLogger.log).toHaveBeenCalledWith('c_c___t');
});
it('displays prompt asking user what to do', () => {
mockPrompts.promptForGuess = new PromiseSpy();
guessLetter('t');
expect(mockPrompts.promptForGuess).toHaveBeenCalled();
});
describe('and user has guessed last letter', () => {
beforeEach(() => {
guessLetter('c');
guessLetter('o');
guessLetter('n');
guessLetter('u');
guessLetter('t');
});
it('shows user answer in green', () => {
expect(mockUiHelper.showAnswer).toHaveBeenCalledWith('coconut');
});
it('shows user winner message', () => {
expect(mockUiHelper.flashWinner).toHaveBeenCalled();
});
it('resolves promise from play() when finished showing winning message', (done) => {
mockUiHelper.flashWinner.onSuccess();
jest.useRealTimers();
setTimeout(() => {
expect(playResolved).toBe(true);
done();
}, 10);
});
});
});
describe('and letter is incorrect', () => {
function checkIncorrectGuess(letter, stage) {
guessLetter(letter);
expect(mockLogger.log).toHaveBeenCalledWith(hangmanStages[stage]);
}
it('draws a line of the hangman image', () => {
const incorrectGuesses = ['z', 'q', 'w', 'e', 'r', 'y', 'i', 'p', 'a', 's'];
incorrectGuesses.forEach((letter, idx) => {
checkIncorrectGuess(letter, idx + 1);
});
});
it('still displays previously correctly guessed letters', () => {
guessLetter('n');
guessLetter('x');
expect(mockLogger.log).toHaveBeenCalledWith('____n__');
});
it('displays prompt asking user what to do', () => {
mockPrompts.promptForGuess = new PromiseSpy();
guessLetter('x');
expect(mockPrompts.promptForGuess).toHaveBeenCalled();
});
describe('and user is on last turn', () => {
beforeEach(() => {
const incorrectGuesses = ['z', 'q', 'w', 'e', 'r', 'y', 'i', 'p', 'a', 's'];
incorrectGuesses.forEach((letter) => {
guessLetter(letter);
});
});
it('stops showing prompt asking user what to do', () => {
mockPrompts.promptForGuess = new PromiseSpy();
guessLetter('d');
expect(mockPrompts.promptForGuess).not.toHaveBeenCalled();
});
it('shows user losing message in red', () => {
guessLetter('d');
expect(mockChalk.red).toHaveBeenCalledWith(gameConstants.GAME_OVER_MSG);
expect(mockLogger.log).toHaveBeenCalledWith(gameConstants.GAME_OVER_MSG);
expect(mockUiHelper.revealAnswer).toHaveBeenCalled();
});
});
});
});
describe('Select to guess answer', () => {
beforeEach(() => {
showAnswerPrompt();
});
it('prompts user for answer', () => {
expect(mockPrompts.promptForAnswer).toHaveBeenCalled();
});
describe('and answer is correct', () => {
beforeEach(() => {
guessAnswer('coconut');
});
it('shows user answer in green', () => {
expect(mockUiHelper.showAnswer).toHaveBeenCalledWith('coconut');
});
it('shows user winner message', () => {
expect(mockUiHelper.flashWinner).toHaveBeenCalled();
});
it('resolves promise from play() when finished showing winning message', (done) => {
mockUiHelper.flashWinner.onSuccess();
jest.useRealTimers();
setTimeout(() => {
expect(playResolved).toBe(true);
done();
}, 10);
});
});
describe('and answer is incorrect', () => {
it('displays incorrect guess message in red', () => {
guessAnswer('banana');
expect(mockChalk.red).toHaveBeenCalledWith(hangmanConstants.INCORRECT_GUESS);
expect(mockLogger.log).toHaveBeenCalledWith(hangmanConstants.INCORRECT_GUESS);
});
it('draws a line of the hangman image', () => {
guessAnswer('kumquat');
expect(mockLogger.log).toHaveBeenCalledWith(hangmanStages[1]);
});
it('still displays previously correctly guessed letters', () => {
showLetterPrompt();
guessLetter('c');
showAnswerPrompt();
guessAnswer('pineapple');
expect(mockLogger.log).toHaveBeenCalledWith('c_c____');
});
it('displays prompt asking user what to do', () => {
mockPrompts.promptForGuess = new PromiseSpy();
guessAnswer('pomegranate');
expect(mockPrompts.promptForGuess).toHaveBeenCalled();
});
describe('and user is on last turn', () => {
beforeEach(() => {
showLetterPrompt();
const incorrectGuesses = ['z', 'q', 'w', 'e', 'r', 'y', 'i', 'p', 'a', 's '];
incorrectGuesses.forEach((letter) => {
guessLetter(letter);
});
showAnswerPrompt();
});
it('stops showing prompt asking user what to do', () => {
mockPrompts.promptForGuess = new PromiseSpy();
guessAnswer('orange');
expect(mockPrompts.promptForGuess).not.toHaveBeenCalled();
});
it('shows user losing message in red', () => {
guessAnswer('orange');
expect(mockChalk.red).toHaveBeenCalledWith(gameConstants.GAME_OVER_MSG);
expect(mockLogger.log).toHaveBeenCalledWith(gameConstants.GAME_OVER_MSG);
expect(mockUiHelper.revealAnswer).toHaveBeenCalled();
});
});
});
});
});