use ts builder api (#54)

Co-authored-by: Paul Schaaf <paulsimonschaaf@gmail.com>
This commit is contained in:
lucas 2022-04-13 15:09:04 -03:00 committed by GitHub
parent 0099a11a65
commit e6603e3e2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 103 additions and 97 deletions

View File

@ -1,6 +1,6 @@
{
"dependencies": {
"@project-serum/anchor": "^0.23.0"
"@project-serum/anchor": "0.23.0"
},
"devDependencies": {
"@types/mocha": "^9.0.0",

View File

@ -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 {

View File

@ -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);

View File

@ -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==

View File

@ -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);

View File

@ -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);

View File

@ -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);