use ts builder api (#54)
Co-authored-by: Paul Schaaf <paulsimonschaaf@gmail.com>
This commit is contained in:
parent
0099a11a65
commit
e6603e3e2a
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@project-serum/anchor": "^0.23.0"
|
||||
"@project-serum/anchor": "0.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^9.0.0",
|
||||
|
|
|
@ -2,7 +2,6 @@ use crate::errors::TicTacToeError;
|
|||
use anchor_lang::prelude::*;
|
||||
use num_derive::*;
|
||||
use num_traits::*;
|
||||
use std::mem;
|
||||
|
||||
#[account]
|
||||
pub struct Game {
|
||||
|
|
|
@ -6,14 +6,15 @@ import chaiAsPromised from 'chai-as-promised';
|
|||
import { expect } from 'chai';
|
||||
chai.use(chaiAsPromised);
|
||||
|
||||
async function play(program, game, player, tile, expectedTurn, expectedGameState, expectedBoard) {
|
||||
await program.rpc.play(tile, {
|
||||
accounts: {
|
||||
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]
|
||||
});
|
||||
})
|
||||
.signers(player instanceof (anchor.Wallet as any) ? [] : [player])
|
||||
.rpc();
|
||||
|
||||
const gameState = await program.account.game.fetch(game);
|
||||
expect(gameState.turn).to.equal(expectedTurn);
|
||||
|
@ -33,14 +34,14 @@ describe('tic-tac-toe', () => {
|
|||
const gameKeypair = anchor.web3.Keypair.generate();
|
||||
const playerOne = program.provider.wallet;
|
||||
const playerTwo = anchor.web3.Keypair.generate();
|
||||
await program.rpc.setupGame(playerTwo.publicKey, {
|
||||
accounts: {
|
||||
await program.methods
|
||||
.setupGame(playerTwo.publicKey)
|
||||
.accounts({
|
||||
game: gameKeypair.publicKey,
|
||||
playerOne: playerOne.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId
|
||||
},
|
||||
signers: [gameKeypair]
|
||||
});
|
||||
})
|
||||
.signers([gameKeypair])
|
||||
.rpc();
|
||||
|
||||
let gameState = await program.account.game.fetch(gameKeypair.publicKey);
|
||||
expect(gameState.turn).to.equal(1);
|
||||
|
@ -57,14 +58,14 @@ describe('tic-tac-toe', () => {
|
|||
const gameKeypair = anchor.web3.Keypair.generate();
|
||||
const playerOne = program.provider.wallet;
|
||||
const playerTwo = anchor.web3.Keypair.generate();
|
||||
await program.rpc.setupGame(playerTwo.publicKey, {
|
||||
accounts: {
|
||||
await program.methods
|
||||
.setupGame(playerTwo.publicKey)
|
||||
.accounts({
|
||||
game: gameKeypair.publicKey,
|
||||
playerOne: playerOne.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId
|
||||
},
|
||||
signers: [gameKeypair]
|
||||
});
|
||||
})
|
||||
.signers([gameKeypair])
|
||||
.rpc();
|
||||
|
||||
let gameState = await program.account.game.fetch(gameKeypair.publicKey);
|
||||
expect(gameState.turn).to.equal(1);
|
||||
|
@ -243,14 +244,14 @@ describe('tic-tac-toe', () => {
|
|||
const gameKeypair = anchor.web3.Keypair.generate();
|
||||
const playerOne = program.provider.wallet;
|
||||
const playerTwo = anchor.web3.Keypair.generate();
|
||||
await program.rpc.setupGame(playerTwo.publicKey, {
|
||||
accounts: {
|
||||
await program.methods
|
||||
.setupGame(playerTwo.publicKey)
|
||||
.accounts({
|
||||
game: gameKeypair.publicKey,
|
||||
playerOne: playerOne.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId
|
||||
},
|
||||
signers: [gameKeypair]
|
||||
});
|
||||
})
|
||||
.signers([gameKeypair])
|
||||
.rpc();
|
||||
|
||||
let gameState = await program.account.game.fetch(gameKeypair.publicKey);
|
||||
expect(gameState.turn).to.equal(1);
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
"@ethersproject/logger" "^5.5.0"
|
||||
hash.js "1.1.7"
|
||||
|
||||
"@project-serum/anchor@^0.23.0":
|
||||
"@project-serum/anchor@0.23.0":
|
||||
version "0.23.0"
|
||||
resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.23.0.tgz#2b2eb6b51601b073e8db26663aa2d6c2f2841771"
|
||||
integrity sha512-LV2/ifZOJVFTZ4GbEloXln3iVfCvO1YM8i7BBCrUm4tehP7irMx4nr4/IabHWOzrQcQElsxSP/lb1tBp+2ff8A==
|
||||
|
|
|
@ -152,21 +152,22 @@ describe('puppet', () => {
|
|||
const puppetKeypair = Keypair.generate();
|
||||
|
||||
it('Does CPI!', async () => {
|
||||
await puppetProgram.rpc.initialize({
|
||||
accounts: {
|
||||
puppet: puppetKeypair.publicKey,
|
||||
user: anchor.getProvider().wallet.publicKey,
|
||||
systemProgram: SystemProgram.programId
|
||||
},
|
||||
signers: [puppetKeypair]
|
||||
});
|
||||
await puppetProgram.methods
|
||||
.initialize()
|
||||
.accounts({
|
||||
puppet: puppetKeypair.publicKey,
|
||||
user: anchor.getProvider().wallet.publicKey,
|
||||
})
|
||||
.signers([puppetKeypair])
|
||||
.rpc();
|
||||
|
||||
await puppetMasterProgram.rpc.pullStrings(new anchor.BN(42),{
|
||||
accounts: {
|
||||
puppetProgram: puppetProgram.programId,
|
||||
puppet: puppetKeypair.publicKey
|
||||
}
|
||||
})
|
||||
await puppetMasterProgram.methods
|
||||
.pullStrings(new anchor.BN(42))
|
||||
.accounts({
|
||||
puppetProgram: puppetProgram.programId,
|
||||
puppet: puppetKeypair.publicKey
|
||||
})
|
||||
.rpc();
|
||||
|
||||
expect((await puppetProgram.account.data
|
||||
.fetch(puppetKeypair.publicKey)).data.toNumber()).to.equal(42);
|
||||
|
@ -281,23 +282,24 @@ describe('puppet', () => {
|
|||
const authorityKeypair = Keypair.generate();
|
||||
|
||||
it('Does CPI!', async () => {
|
||||
await puppetProgram.rpc.initialize(authorityKeypair.publicKey, {
|
||||
accounts: {
|
||||
puppet: puppetKeypair.publicKey,
|
||||
user: anchor.getProvider().wallet.publicKey,
|
||||
systemProgram: SystemProgram.programId,
|
||||
},
|
||||
signers: [puppetKeypair]
|
||||
});
|
||||
await puppetProgram.methods
|
||||
.initialize(authorityKeypair.publicKey)
|
||||
.accounts({
|
||||
puppet: puppetKeypair.publicKey,
|
||||
user: anchor.getProvider().wallet.publicKey,
|
||||
})
|
||||
.signers([puppetKeypair])
|
||||
.rpc();
|
||||
|
||||
await puppetMasterProgram.rpc.pullStrings(new anchor.BN(42),{
|
||||
accounts: {
|
||||
puppetProgram: puppetProgram.programId,
|
||||
puppet: puppetKeypair.publicKey,
|
||||
authority: authorityKeypair.publicKey
|
||||
},
|
||||
signers: [authorityKeypair]
|
||||
})
|
||||
await puppetMasterProgram.methods
|
||||
.pullStrings(new anchor.BN(42))
|
||||
.accounts({
|
||||
puppetProgram: puppetProgram.programId,
|
||||
puppet: puppetKeypair.publicKey,
|
||||
authority: authorityKeypair.publicKey
|
||||
})
|
||||
.signers([authorityKeypair])
|
||||
.rpc();
|
||||
|
||||
expect((await puppetProgram.account.data
|
||||
.fetch(puppetKeypair.publicKey)).data.toNumber()).to.equal(42);
|
||||
|
|
|
@ -198,22 +198,23 @@ anchor.setProvider(anchor.Provider.env());
|
|||
program.programId
|
||||
);
|
||||
|
||||
await program.rpc.createUserStats("brian", {
|
||||
accounts: {
|
||||
await program.methods
|
||||
.createUserStats("brian")
|
||||
.accounts({
|
||||
user: anchor.getProvider().wallet.publicKey,
|
||||
userStats: userStatsPDA,
|
||||
systemProgram: SystemProgram.programId
|
||||
}
|
||||
});
|
||||
})
|
||||
.rpc();
|
||||
|
||||
expect((await program.account.userStats.fetch(userStatsPDA)).name).to.equal("brian");
|
||||
|
||||
await program.rpc.changeUserName("tom", {
|
||||
accounts: {
|
||||
await program.methods
|
||||
.changeUserName("tom")
|
||||
.accounts({
|
||||
user: anchor.getProvider().wallet.publicKey,
|
||||
userStats: userStatsPDA
|
||||
}
|
||||
})
|
||||
})
|
||||
.rpc();
|
||||
|
||||
expect((await program.account.userStats.fetch(userStatsPDA)).name).to.equal("tom");
|
||||
});
|
||||
|
@ -305,22 +306,23 @@ describe('puppet', () => {
|
|||
const [puppetMasterPDA, puppetMasterBump] = await PublicKey
|
||||
.findProgramAddress([], puppetMasterProgram.programId);
|
||||
|
||||
await puppetProgram.rpc.initialize(puppetMasterPDA, {
|
||||
accounts: {
|
||||
await puppetProgram.methods
|
||||
.initialize(puppetMasterPDA)
|
||||
.accounts({
|
||||
puppet: puppetKeypair.publicKey,
|
||||
user: anchor.getProvider().wallet.publicKey,
|
||||
systemProgram: SystemProgram.programId,
|
||||
},
|
||||
signers: [puppetKeypair]
|
||||
});
|
||||
})
|
||||
.signers([puppetKeypair])
|
||||
.rpc();
|
||||
|
||||
await puppetMasterProgram.rpc.pullStrings(puppetMasterBump, new anchor.BN(42),{
|
||||
accounts: {
|
||||
await puppetMasterProgram.methods
|
||||
.pullStrings(puppetMasterBump, new anchor.BN(42))
|
||||
.accounts({
|
||||
puppetProgram: puppetProgram.programId,
|
||||
puppet: puppetKeypair.publicKey,
|
||||
authority: puppetMasterPDA
|
||||
,
|
||||
}});
|
||||
})
|
||||
.rpc();
|
||||
|
||||
expect((await puppetProgram.account.data
|
||||
.fetch(puppetKeypair.publicKey)).data.toNumber()).to.equal(42);
|
||||
|
|
|
@ -280,14 +280,14 @@ Time to test our code! Head over into the `tests` folder in the root directory.
|
|||
const gameKeypair = anchor.web3.Keypair.generate();
|
||||
const playerOne = program.provider.wallet;
|
||||
const playerTwo = anchor.web3.Keypair.generate();
|
||||
await program.rpc.setupGame(playerTwo.publicKey, {
|
||||
accounts: {
|
||||
await program.methods
|
||||
.setupGame(playerTwo.publicKey)
|
||||
.accounts({
|
||||
game: gameKeypair.publicKey,
|
||||
playerOne: playerOne.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId
|
||||
},
|
||||
signers: [gameKeypair]
|
||||
});
|
||||
})
|
||||
.signers([gameKeypair])
|
||||
.rpc();
|
||||
|
||||
let gameState = await program.account.game.fetch(gameKeypair.publicKey);
|
||||
expect(gameState.turn).to.equal(1);
|
||||
|
@ -310,14 +310,15 @@ import { expect } from 'chai';
|
|||
> This is likely because the test file is looking for types from your program that haven't been generated yet.
|
||||
> To generate them, run `anchor build`. This builds the program and creates the idl and typescript types.
|
||||
|
||||
The test begins by creating some keypairs. Importantly, `playerOne` is not a keypair but the wallet of the program's provider. The provider details are defined in the `Anchor.toml` file in the root of the project.
|
||||
Then, we send the transaction. Because the anchor typescript client has parsed the IDL, all transaction inputs have types. If you remove one of the accounts for example, typescript will complain.
|
||||
The test begins by creating some keypairs. Importantly, `playerOne` is not a keypair but the wallet of the program's provider. The provider details are defined in the `Anchor.toml` file in the root of the project. The provider serves as the keypair that pays for (and therefore signs) all transactions.
|
||||
Then, we send the transaction.
|
||||
The structure of the transaction function is as follows: First come the instruction arguments. For this function, the public key of the second player. Then come the accounts. Lastly, we add a signers array. We have to add the `gameKeypair` here because whenever an account gets created, it has to sign its creation transaction. We don't have to add `playerOne` even though we gave it the `Signer` type in the program because it is the program provider and therefore signs the transaction by default.
|
||||
We did not have to specify the `system_program` account. This is because anchor recognizes this account and is able to infer it. This is also true for other known accounts such as the `token_program` or the `rent` sysvar account.
|
||||
|
||||
After the transaction returns, we can fetch the state of the game account. You can fetch account state using the `program.account` namespace.
|
||||
Finally, we verify the game has been set up properly. Anchor's typescript client deserializes rust enums like this: `{ active: {}}` for a fieldless variant and `{ won: { winner: Pubkey }}` for a variant with fields. The `None` variant of `Option` becomes `null`. The `Some(x)` variant becomes whatever `x` deserializes to.
|
||||
|
||||
Now, run `anchor test`. This starts up (and subsequently shuts down) a local validator (make sure you don't have one running) and runs your tests using the test script defined in `Anchor.toml`.
|
||||
Now, run `anchor test`. This starts up (and subsequently shuts down) a local validator (make sure you don't have one running before) and runs your tests using the test script defined in `Anchor.toml`.
|
||||
|
||||
> If you get the error `Error: Unable to read keypair file` when running the test, you likely need to generate a Solana keypair using `solana-keygen new`.
|
||||
|
||||
|
@ -358,15 +359,16 @@ We've checked in the accounts struct that the `player` account has signed the tr
|
|||
|
||||
Testing the `play` instruction works the exact same way. To avoid repeating yourself, create a helper function at the top of the test file:
|
||||
```typescript
|
||||
async function play(program, game, player,
|
||||
async function play(program: Program<TicTacToe>, game, player,
|
||||
tile, expectedTurn, expectedGameState, expectedBoard) {
|
||||
await program.rpc.play(tile, {
|
||||
accounts: {
|
||||
await program.methods
|
||||
.play(tile)
|
||||
.accounts({
|
||||
player: player.publicKey,
|
||||
game
|
||||
},
|
||||
signers: player instanceof (anchor.Wallet as any) ? [] : [player]
|
||||
});
|
||||
})
|
||||
.signers(player instanceof (anchor.Wallet as any) ? [] : [player])
|
||||
.rpc();
|
||||
|
||||
const gameState = await program.account.game.fetch(game);
|
||||
expect(gameState.turn).to.equal(expectedTurn);
|
||||
|
@ -383,14 +385,14 @@ it('player one wins', async() => {
|
|||
const gameKeypair = anchor.web3.Keypair.generate();
|
||||
const playerOne = program.provider.wallet;
|
||||
const playerTwo = anchor.web3.Keypair.generate();
|
||||
await program.rpc.setupGame(playerTwo.publicKey, {
|
||||
accounts: {
|
||||
await program.methods
|
||||
.setupGame(playerTwo.publicKey)
|
||||
.accounts({
|
||||
game: gameKeypair.publicKey,
|
||||
playerOne: playerOne.publicKey,
|
||||
systemProgram: anchor.web3.SystemProgram.programId
|
||||
},
|
||||
signers: [gameKeypair]
|
||||
});
|
||||
})
|
||||
.signers([gameKeypair])
|
||||
.rpc();
|
||||
|
||||
let gameState = await program.account.game.fetch(gameKeypair.publicKey);
|
||||
expect(gameState.turn).to.equal(1);
|
||||
|
|
Loading…
Reference in New Issue