构建流程:JS测试-3。执行脚本并发送交易
#javascript #测试 #区块链 #flow

介绍

现在,部署合同都是有趣的,而且游戏很快,除非您可以与它们互动:)

有两种方式可以通过两种方式与流有关的合同和帐户进行交互 - 您可以read data(通过scripts),您可以write data(通过交易)。

最大的区别是 - 执行脚本时,您无法突变链的状态。即使您调用了合同的方法,该方法将修改状态,当脚本返回时,它也不会保留。

让我们从非侵入性交互开始 - 脚本。

先决条件

让我们假设我们正在使用上一部分的相同设置,并且我们已经有了cadence文件夹。后来我们将一些脚本播放到scripts文件夹中。

创建一个新的测试西装文件

npx @onflow/flow-js-testing make interaction

计算器

由于Cadence能够进行基本的数学操作,因此让我们尝试总和两个数字。导入executeScript并在describe块中添加新测试:

test("calculator", async () => {
  const [result] = await executeScript({
    code: `
        pub fun main(a: Int, b: Int): Int{
          return a + b
        }
      `,
    args: ["10", "32"],
  });
  expect(result).toBe("42");
});

请注意,我们正在将数字作为字符串作为字符串,并且脚本返回的最终结果也将是字符串。您可以在闲暇时添加必要的转换,但这就是网络和库在流程上的处理编号

executeScript将返回您一个元组(一个具有2个值的数组)[result, error],您可以

在您的断言中使用。

帐户管理

该框架为您提供了一种干净,简便的操作帐户方式-getAccountAddress函数。
此功能将返回一个地址,您可以将其传递到任何类型的交互中,框架将为您完成其余的工作。例如,您可以将其用作交易签名或其中一个
函数中的参数:

const Alice = await getAccountAddress("Alice");

此方法很酷的是,该特定帐户可以在您的测试中的任何地方使用。因此,您可以创建一个辅助功能,再获取Alice的帐户地址,然后将其
可以解决完全相同的值! -

阅读平衡

计算器很有趣,而且游戏,但让我们做一些更实用的事情。例如,我们可以阅读任何帐户的流量平衡。如果您知道自己的节奏:
很容易

test("read balance", async () => {
  const Alice = await getAccountAddress("Alice");
  const [balance] = await executeScript({
    code: `
        pub fun main(address: Address): UFix64 {
          let account = getAccount(address)
          return account.balance
        }
      `,
    args: [Alice],
  });

  expect(balance).toBe("0.00100000");
});

所有新创建的帐户以0.001的流量开始,因此我们可以断言此值并将其用作将来计算的基线

合同访问

从进口合同中阅读一些东西?很容易!让我们重新部署我们的Message合同,并尝试从中读取message字段:

test("read message", async () => {
  const message = "noice";
  await shallResolve(deployContractByName({ name: "Message", args: [message] }));
  const [contractValue] = await executeScript({
    code: `
      import Message from 0x1

      pub fun main():String{
        return Message.message
      }
    `,
  });

  expect(contractValue).toBe(message);
});

我们可以从任何地址导入合同 - 框架将在将脚本发送给模拟器​​之前解决并分配适当的合同。

简短符号

让我们通过将Cadence代码移至read-message.cdc文件并将其放入scripts文件夹中来缩短该脚本符号。 executeScript有一个速记概念,其中第一个参数是包含脚本的文件的名称。

test("read message - short", async () => {
  const message = "noice";
  await shallResolve(deployContractByName({ name: "Message", args: [message] }));
  const [contractValue] = await executeScript("read-message");

  expect(contractValue).toBe(message);
});

参数可以作为第二个参数传递。让我们添加来自上方代码的read-balance.cdc文件,然后重写我们的余额阅读脚本:

test("balance - short", async () => {
  const Alice = await getAccountAddress("Alice");
  const [balance] = await executeScript("read-balance", [Alice]);

  expect(balance).toBe("0.00100000");
});

noice!

Cadence忍者突变体ð¢

让我们加入一些突变!我们将创建两个帐户,其中一个帐户造成一些令牌,然后将其转移到另一个帐户。这应该很有趣!

为了铸造流,我们将利用mintFlow函数,该功能期望地址和数量作为参数。导入文件顶部的mintFlowsendTransaction

test("FLOW transfer", async () => {
  const Alice = await getAccountAddress("Alice");
  const Bob = await getAccountAddress("Bob");

  await mintFlow(Alice, "42");

  const [aliceBalance] = await executeScript("read-balance", [Alice]);
  expect(aliceBalance).toBe("42.00100000");
});

类似于我们如何使用shallPass部署合同的方式,我们可以在发送交易时使用它。

test("FLOW transfer", async () => {
  const Alice = await getAccountAddress("Alice");
  const Bob = await getAccountAddress("Bob");

  await mintFlow(Alice, "42");

  const [aliceBalance] = await executeScript("read-balance", [Alice]);
  expect(aliceBalance).toBe("42.00100000");

  await shallPass(
    sendTransaction({
      code: `
        import FungibleToken from 0x1

        transaction(receiverAddress: Address, amount: UFix64){
          prepare(sender: AuthAccount){
            let receiver = getAccount(receiverAddress)

            // Withdraw necessary amount into separate vault
            let senderVault <- sender
                .borrow<&{FungibleToken.Provider}>(from: /storage/flowTokenVault)!
                .withdraw(amount: amount)

            // Send to receiver
            getAccount(receiverAddress)
                .getCapability(/public/flowTokenReceiver)!
                .borrow<&{FungibleToken.Receiver}>()!
                .deposit(from: <- senderVault)
          }
        }
      `,
      args: [Bob, "1"],
      signers: [Alice],
    })
  );

  // Let's read updated balances and compare to expected values
  const [newAliceBalance] = await executeScript("read-balance", [Alice]);
  const [bobBalance] = await executeScript("read-balance", [Bob]);

  expect(newAliceBalance).toBe("41.00100000");
  expect(bobBalance).toBe("1.00100000");
});

通过简短符号发送

类似于我们如何使用脚本完成的方式,sendTransaction功能还支持简短的符号:

sendTransaction(
  fileName, // file name in "transactions folder"
  [signers], // {optional) list of signers, even if that's single one
  [arguments] // (optional) list of arguments
);

让我们从上面的示例中将所有Cadence代码移动到send-flow.cdc文件夹下的send-flow.cdc文件中,然后重写我们的测试:

test("FLOW transfer - short", async () => {
  const Alice = await getAccountAddress("Alice");
  const Bob = await getAccountAddress("Bob");

  await mintFlow(Alice, "42");

  const [aliceBalance] = await executeScript("read-balance", [Alice]);
  expect(aliceBalance).toBe("42.00100000");

  const signers = [Alice];

  const recipient = Bob;
  const amount = "1";
  const args = [recipient, amount];

  await shallPass(sendTransaction("send-flow", signers, args));

  // Let's read updated balances and compare to expected values
  const [newAliceBalance] = await executeScript("read-balance", [Alice]);
  const [bobBalance] = await executeScript("read-balance", [Bob]);

  expect(newAliceBalance).toBe("41.00100000");
  expect(bobBalance).toBe("1.00100000");
});

“ Multisig”是从框外支持的,只需指定交易代码中的预期签名数,然后通过signers参数传递相应的地址ð

仅此而已! Next time,我们将研究如何检查帐户存储并确保正确铸造或转移资源。直到下一次! ð