Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 3 additions & 36 deletions sources/contract.spec.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,6 @@
import { toNano } from "@ton/core";
import { Blockchain } from "@ton/sandbox";
import "@ton/test-utils";
import { testContract } from "./contract";
import { SampleTactContract } from "./output/sample_SampleTactContract";

describe("contract", () => {
it("should deploy correctly", async () => {
// Create Sandbox and deploy contract
const system = await Blockchain.create();
const owner = await system.treasury("owner");
const nonOwner = await system.treasury("non-owner");
const contract = system.openContract(await SampleTactContract.fromInit(owner.address, 0n));
const deployResult = await contract.send(owner.getSender(), { value: toNano(1) }, null);
expect(deployResult.transactions).toHaveTransaction({
from: owner.address,
to: contract.address,
deploy: true,
success: true,
});
// Check counter
expect(await contract.getCounter()).toEqual(0n);

// Increment counter
await contract.send(owner.getSender(), { value: toNano(1) }, { $$type: "Increment" });

// Check counter
expect(await contract.getCounter()).toEqual(1n);

// Non-owner
const nonOwnerResult = await contract.send(nonOwner.getSender(), { value: toNano(1) }, { $$type: "Increment" });
const accessDeniedExitCode = 132;
expect(nonOwnerResult.transactions).toHaveTransaction({
from: nonOwner.address,
to: contract.address,
success: false,
exitCode: accessDeniedExitCode,
});
});
describe("SampleTactContract", () => {
testContract();
});
137 changes: 137 additions & 0 deletions sources/contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { toNano, Dictionary } from "@ton/core";
import { Blockchain, SandboxContract } from "@ton/sandbox";
import { updateConfig } from "@ton/sandbox";
import { StoragePrices } from "@ton/sandbox/dist/config/config.tlb-gen";
import "@ton/test-utils";
import { SampleTactContract } from "./output/sample_SampleTactContract";

const globalSetup = async () => {
const blockchain = await Blockchain.create();

// --- Set storage prices to 0 if they are not being tested ---
const storagePricesDict = Dictionary.empty<number, StoragePrices>();

storagePricesDict.set(0, {
kind: "StoragePrices",
utime_since: 0,
bit_price_ps: 0n,
_cell_price_ps: 0n,
mc_bit_price_ps: 0n,
mc_cell_price_ps: 0n,
});

const updatedConfig = updateConfig(blockchain.config, {
kind: "ConfigParam__18",
anon0: storagePricesDict,
});

blockchain.setConfig(updatedConfig);
// ---

const owner = await blockchain.treasury("owner");
const nonOwner = await blockchain.treasury("non-owner");

const contract: SandboxContract<SampleTactContract> = blockchain.openContract(
await SampleTactContract.fromInit(owner.address, 0n)
);

const deployResult = await contract.send(owner.getSender(), { value: toNano(1) }, null);

expect(deployResult.transactions).toHaveTransaction({
from: owner.address,
to: contract.address,
deploy: true,
success: true,
});

return { blockchain, owner, nonOwner, contract };
};

const testDeploy = () => {
describe("test deploy", () => {
const setup = async () => {
return await globalSetup();
};

it("should deploy correctly", async () => {
const { contract } = await setup();

const counter = await contract.getCounter();
expect(counter).toEqual(0n);
});
});
};

const testIncrement = () => {
const setup = async () => {
return await globalSetup();
};

describe("test increment", () => {
it("should increment counter by owner", async () => {
const { owner, contract } = await setup();

// Increment counter
await contract.send(owner.getSender(), { value: toNano(1) }, { $$type: "Increment" });

// Check counter
expect(await contract.getCounter()).toEqual(1n);
});

it("should not increment counter by non-owner", async () => {
const { nonOwner, contract } = await setup();

// Increment counter
const result = await contract.send(nonOwner.getSender(), { value: toNano(1) }, { $$type: "Increment" });

expect(result.transactions).toHaveTransaction({
from: nonOwner.address,
to: contract.address,
success: false,
exitCode: SampleTactContract.errors["Access denied"],
});
});
});
};

const testAdd = () => {
const setup = async () => {
return await globalSetup();
};

describe("test add", () => {
it("should add amount by owner", async () => {
const { owner, contract } = await setup();

// Add amount
await contract.send(owner.getSender(), { value: toNano(10) }, { $$type: "Add", amount: 10n });

// Check counter
expect(await contract.getCounter()).toEqual(10n);
});

it("should not add amount by non-owner", async () => {
const { nonOwner, contract } = await setup();

// Add amount
const result = await contract.send(
nonOwner.getSender(),
{ value: toNano(10) },
{ $$type: "Add", amount: 10n }
);

expect(result.transactions).toHaveTransaction({
from: nonOwner.address,
to: contract.address,
success: false,
exitCode: SampleTactContract.errors["Access denied"],
});
});
});
};

export const testContract = () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, this split into two files isn't justified, as it moves contents from one to another — and now we have two files to take care about. Complexity demon bad :)

Perhaps, it's better to add reusable helper testing utilities to contract.ts, such that it won't be coupled to the given contract AND it'd be easy to use those functions from the *.spec.ts files.

testDeploy();
testIncrement();
testAdd();
};