Skip to content

feat: add test stub generation #3342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 34 commits into
base: main
Choose a base branch
from

Conversation

skywardboundd
Copy link
Contributor

Closes #3287

@skywardboundd skywardboundd linked an issue Jun 2, 2025 that may be closed by this pull request
@skywardboundd skywardboundd marked this pull request as ready for review June 2, 2025 14:20
@skywardboundd skywardboundd requested a review from a team as a code owner June 2, 2025 14:20
@skywardboundd
Copy link
Contributor Author

skywardboundd commented Jun 2, 2025

Example

// !!THIS FILE IS GENERATED BY TACT. THIS FILE IS REGENERATED EVERY TIME, COPY IT TO YOUR PROJECT MANUALLY!!
// https://docs.tact-lang.org/book/debug/

import { Escrow } from './escrow_Escrow';
import { Blockchain, createShardAccount } from "@ton/sandbox";

export type FromInitEscrow = typeof Escrow.fromInit;

export type TestCase = (fromInit: FromInitEscrow) => void;

export const testEscrow = (fromInit: FromInitEscrow) => {
    describe("Escrow Contract", () => {
        // Test receivers
        testInternalMessageFunding(fromInit);
        testInternalMessageUpdateJettonWalletCode(fromInit);
        testInternalMessageJettonNotification(fromInit);
        testInternalMessageApprove(fromInit);
        testInternalMessageCancel(fromInit);
        testInternalMessageProvideEscrowData(fromInit);
        // Test getters
        getterTestcalculateRoyaltyAmount(fromInit);
        getterTestwalletAddress(fromInit);
        getterTestescrowInfo(fromInit);
    });
};

const globalSetup = async (fromInit: FromInitEscrow) => {
    const blockchain = await Blockchain.create();
    // @ts-ignore
    const contract = await blockchain.openContract(await fromInit(
        // TODO: implement default values
    ));
        
    // Universal method for deploy contract without sending message
    await blockchain.setShardAccount(contract.address, createShardAccount({
        address: contract.address,
        code: contract.init!.code,
        data: contract.init!.data,
        balance: 0n,
        workchain: 0
    }));
        
    const owner = await blockchain.treasury("owner");
    const notOwner = await blockchain.treasury("notOwner");
    
    return { blockchain, contract, owner, notOwner };
};

const testInternalMessageFunding: TestCase = (fromInit) => {
    describe("InternalMessageFunding", () => {
        const setup = async () => {
            return await globalSetup(fromInit);
        };
        
        // !!THIS FILE IS GENERATED BY TACT. THIS FILE IS REGENERATED EVERY TIME, COPY IT TO YOUR PROJECT MANUALLY!!
        // TODO: You can write tests for InternalMessageFunding here
        
        it("should perform correctly", async () => {
            const { blockchain, contract, owner, notOwner } = await setup();
        });
    });
};
...

Copy link
Contributor

@Kaladin13 Kaladin13 left a comment

Choose a reason for hiding this comment

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

I like the idea behind the PR, it's very fresh and could be useful

However, I think we should discuss the end result more, because all Tact users would be affected by such test template generation, so it needs to be polished

One way is to move it to CLI instead of default build pipeline, or maybe add flag to the tact.config

@xpyctumo
Copy link
Contributor

xpyctumo commented Jun 2, 2025

I think maintaining a template file will be clearer and easier than generating it on-fly with many f.write functions

// !!THIS FILE IS GENERATED BY TACT. COPY IT TO YOUR PROJECT MANUALLY!!
// https://docs.tact-lang.org/book/debug/

{{#imports}}
import {{.}};
{{/imports}}

export type FromInit{{contractName}} = typeof {{contractName}}.fromInit;
export type TestCase = (fromInit: FromInit{{contractName}}) => void;

export const test{{contractName}} = (fromInit: FromInit{{contractName}}) => {
    describe("{{contractName}} Contract", () => {
        // Test receivers
        {{#receivers}}
        test{{.}}(fromInit);
        {{/receivers}}

        // Test getters
        {{#getters}}
        getterTest{{.}}(fromInit);
        {{/getters}}
    });
};

const globalSetup = async (fromInit: FromInit{{contractName}}) => {
    const blockchain = await Blockchain.create();
    // @ts-ignore
    const contract = await blockchain.openContract(await fromInit(
        // TODO: implement default values
    ));

    // Universal deploy without message
    await blockchain.setShardAccount(contract.address, createShardAccount({
        address: contract.address,
        code: contract.init!.code,
        data: contract.init!.data,
        balance: 0n,
        workchain: 0,
    }));

    const owner = await blockchain.treasury("owner");
    const notOwner = await blockchain.treasury("notOwner");

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

{{#receiverBlocks}}
{{{.}}}
{{/receiverBlocks}}

{{#getterBlocks}}
{{{.}}}
{{/getterBlocks}}

// entry point
test{{contractName}}({{contractName}}.fromInit.bind({{contractName}}));

@skywardboundd skywardboundd marked this pull request as draft June 5, 2025 11:45
@Kaladin13 Kaladin13 requested review from novusnota and Kaladin13 June 6, 2025 09:40
Kaladin13
Kaladin13 previously approved these changes Jun 6, 2025
Copy link
Contributor

@Kaladin13 Kaladin13 left a comment

Choose a reason for hiding this comment

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

Great work here! PR approved, please fix small nitpicks :shipit:

Copy link
Member

@novusnota novusnota left a comment

Choose a reason for hiding this comment

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

Nice work! Left a couple of nitpicks to resolve altogether

Copy link
Member

@novusnota novusnota left a comment

Choose a reason for hiding this comment

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

Whoops, chose the wrong radio button :)

skywardboundd and others added 11 commits June 6, 2025 15:51
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
Co-authored-by: Novus Nota <68142933+novusnota@users.noreply.github.com>
@skywardboundd skywardboundd marked this pull request as ready for review June 6, 2025 12:53
Copy link
Member

@novusnota novusnota left a comment

Choose a reason for hiding this comment

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

yay!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

We should generate test template as wrappers
4 participants