anchor-book/programs/tic-tac-toe/tests/tic-tac-toe.ts

395 lines
9.2 KiB
TypeScript

import * as anchor from '@coral-xyz/anchor';
import { AnchorError, Program } from '@coral-xyz/anchor';
import { TicTacToe } from '../target/types/tic_tac_toe';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import { expect } from 'chai';
chai.use(chaiAsPromised);
async function play(program: Program<TicTacToe>, game, player, tile, expectedTurn, expectedGameState, expectedBoard) {
await program.methods
.play(tile)
.accounts({
player: player.publicKey,
game
})
.signers(player instanceof (anchor.Wallet as any) ? [] : [player])
.rpc();
const gameState = await program.account.game.fetch(game);
expect(gameState.turn).to.equal(expectedTurn);
expect(gameState.state).to.eql(expectedGameState);
expect(gameState.board)
.to
.eql(expectedBoard);
}
describe('tic-tac-toe', () => {
// Configure the client to use the local cluster.
anchor.setProvider(anchor.AnchorProvider.env());
const program = anchor.workspace.TicTacToe as Program<TicTacToe>;
const programProvider = program.provider as anchor.AnchorProvider;
it('setup game!', async() => {
const gameKeypair = anchor.web3.Keypair.generate();
const playerOne = programProvider.wallet;
const playerTwo = anchor.web3.Keypair.generate();
await program.methods
.setupGame(playerTwo.publicKey)
.accounts({
game: gameKeypair.publicKey,
playerOne: playerOne.publicKey,
})
.signers([gameKeypair])
.rpc();
let gameState = await program.account.game.fetch(gameKeypair.publicKey);
expect(gameState.turn).to.equal(1);
expect(gameState.players)
.to
.eql([playerOne.publicKey, playerTwo.publicKey]);
expect(gameState.state).to.eql({ active: {} });
expect(gameState.board)
.to
.eql([[null,null,null],[null,null,null],[null,null,null]]);
});
it('player one wins!', async () => {
const gameKeypair = anchor.web3.Keypair.generate();
const playerOne = programProvider.wallet;
const playerTwo = anchor.web3.Keypair.generate();
await program.methods
.setupGame(playerTwo.publicKey)
.accounts({
game: gameKeypair.publicKey,
playerOne: playerOne.publicKey,
})
.signers([gameKeypair])
.rpc();
let gameState = await program.account.game.fetch(gameKeypair.publicKey);
expect(gameState.turn).to.equal(1);
expect(gameState.players)
.to
.eql([playerOne.publicKey, playerTwo.publicKey]);
expect(gameState.state).to.eql({ active: {} });
expect(gameState.board)
.to
.eql([[null,null,null],[null,null,null],[null,null,null]]);
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 0, column: 0},
2,
{ active: {}, },
[
[{x:{}},null,null],
[null,null,null],
[null,null,null]
]
);
try {
await play(
program,
gameKeypair.publicKey,
playerOne, // same player in subsequent turns
// change sth about the tx because
// duplicate tx that come in too fast
// after each other may get dropped
{row: 1, column: 0},
2,
{ active: {}, },
[
[{x:{}},null,null],
[null,null,null],
[null,null,null]
]
);
chai.assert(false, "should've failed but didn't ");
} catch (_err) {
expect(_err).to.be.instanceOf(AnchorError);
const err: AnchorError = _err;
expect(err.error.errorCode.code).to.equal("NotPlayersTurn");
expect(err.error.errorCode.number).to.equal(6003);
expect(err.program.equals(program.programId)).is.true;
expect(err.error.comparedValues).to.deep.equal([playerTwo.publicKey, playerOne.publicKey]);
}
await play(
program,
gameKeypair.publicKey,
playerTwo,
{row: 1, column: 0},
3,
{ active: {}, },
[
[{x:{}},null,null],
[{o:{}},null,null],
[null,null,null]
]
);
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 0, column: 1},
4,
{ active: {}, },
[
[{x:{}},{x: {}},null],
[{o:{}},null,null],
[null,null,null]
]
);
try {
await play(
program,
gameKeypair.publicKey,
playerTwo,
{row: 5, column: 1}, // out of bounds row
4,
{ active: {}, },
[
[{x:{}},{x: {}},null],
[{o:{}},null,null],
[null,null,null]
]
);
chai.assert(false, "should've failed but didn't ");
} catch (_err) {
expect(_err).to.be.instanceOf(AnchorError);
const err: AnchorError = _err;
expect(err.error.errorCode.number).to.equal(6000);
expect(err.error.errorCode.code).to.equal("TileOutOfBounds");
}
await play(
program,
gameKeypair.publicKey,
playerTwo,
{row: 1, column: 1},
5,
{ active: {}, },
[
[{x:{}},{x: {}},null],
[{o:{}},{o:{}},null],
[null,null,null]
]
);
try {
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 0, column: 0},
5,
{ active: {}, },
[
[{x:{}},{x: {}},null],
[{o:{}},{o:{}},null],
[null,null,null]
]
);
chai.assert(false, "should've failed but didn't ");
} catch (_err) {
expect(_err).to.be.instanceOf(AnchorError);
const err: AnchorError = _err;
expect(err.error.errorCode.number).to.equal(6001);
}
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 0, column: 2},
5,
{ won: { winner: playerOne.publicKey }, },
[
[{x:{}},{x: {}},{x: {}}],
[{o:{}},{o:{}},null],
[null,null,null]
]
);
try {
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 0, column: 2},
5,
{ won: { winner: playerOne.publicKey }, },
[
[{x:{}},{x: {}},{x: {}}],
[{o:{}},{o:{}},null],
[null,null,null]
]
);
chai.assert(false, "should've failed but didn't ");
} catch (_err) {
expect(_err).to.be.instanceOf(AnchorError);
const err: AnchorError = _err;
expect(err.error.errorCode.number).to.equal(6002);
}
})
it('tie', async () => {
const gameKeypair = anchor.web3.Keypair.generate();
const playerOne = programProvider.wallet;
const playerTwo = anchor.web3.Keypair.generate();
await program.methods
.setupGame(playerTwo.publicKey)
.accounts({
game: gameKeypair.publicKey,
playerOne: playerOne.publicKey,
})
.signers([gameKeypair])
.rpc();
let gameState = await program.account.game.fetch(gameKeypair.publicKey);
expect(gameState.turn).to.equal(1);
expect(gameState.players)
.to
.eql([playerOne.publicKey, playerTwo.publicKey]);
expect(gameState.state).to.eql({ active: {} });
expect(gameState.board)
.to
.eql([[null,null,null],[null,null,null],[null,null,null]]);
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 0, column: 0},
2,
{ active: {}, },
[
[{x:{}},null,null],
[null,null,null],
[null,null,null]
]
);
await play(
program,
gameKeypair.publicKey,
playerTwo,
{row: 1, column: 1},
3,
{ active: {}, },
[
[{x:{}},null,null],
[null,{o:{}},null],
[null,null,null]
]
);
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 2, column: 0},
4,
{ active: {}, },
[
[{x:{}},null,null],
[null,{o:{}},null],
[{x:{}},null,null]
]
);
await play(
program,
gameKeypair.publicKey,
playerTwo,
{row: 1, column: 0},
5,
{ active: {}, },
[
[{x:{}},null,null],
[{o:{}},{o:{}},null],
[{x:{}},null,null]
]
);
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 1, column: 2},
6,
{ active: {}, },
[
[{x:{}},null,null],
[{o:{}},{o:{}},{x:{}}],
[{x:{}},null,null]
]
);
await play(
program,
gameKeypair.publicKey,
playerTwo,
{row: 0, column: 1},
7,
{ active: {}, },
[
[{x:{}},{o:{}},null],
[{o:{}},{o:{}},{x:{}}],
[{x:{}},null,null]
]
);
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 2, column: 1},
8,
{ active: {}, },
[
[{x:{}},{o:{}},null],
[{o:{}},{o:{}},{x:{}}],
[{x:{}},{x:{}},null]
]
);
await play(
program,
gameKeypair.publicKey,
playerTwo,
{row: 2, column: 2},
9,
{ active: {}, },
[
[{x:{}},{o:{}},null],
[{o:{}},{o:{}},{x:{}}],
[{x:{}},{x:{}},{o:{}}]
]
);
await play(
program,
gameKeypair.publicKey,
playerOne,
{row: 0, column: 2},
9,
{ tie: {}, },
[
[{x:{}},{o:{}},{x:{}}],
[{o:{}},{o:{}},{x:{}}],
[{x:{}},{x:{}},{o:{}}]
]
);
})
});