介绍
在我们史诗般的旅程的previous episode中,我们发现了如何通过发送交易和执行脚本来与流仿真器进行交互。今天,我们将继续探索可用的功能,以帮助我们快速,易于阅读的Cadence合同测试。
即使您手动编写所有Cadence代码,从合同和帐户中读取简单的值也很容易。但是,确保帐户在其集合中具有适当的路径设置或特定项目可能很乏味。
该框架提供了几种方法来快速,无痛地检查帐户存储。
让我们首先创建另一个测试西服:
npx @onflow/flow-js-testing make storage-inspection
检查可用的路径
要在帐户上收集所有可用路径,我们将调用getPaths
函数,该函数将返回包含三个集的对象:
-
publicPaths
-
privatePaths
storagePaths
您可以像其他任何集合一样检查它们。
让我们确认Alice
具有操作流动令牌的所有必要位(所有新帐户都可以,但这将简化该过程)。
test("get paths", async () => {
const Alice = await getAccountAddress("Alice");
const { publicPaths, privatePaths, storagePaths } = await getPaths(Alice);
// Newly created account shall have 2 public and 1 storage slot occupied for FLOW Vault
expect(publicPaths.size).toBe(2);
expect(publicPaths.has("flowTokenBalance")).toBe(true);
expect(publicPaths.has("flowTokenReceiver")).toBe(true);
// Newly created account doesn't have any private paths
expect(privatePaths.size).toBe(0);
// And it should have single storage path for FLOW token vault
expect(storagePaths.size).toBe(1);
expect(storagePaths.has("flowTokenVault")).toBe(true);
});
在路径上获得类型限制
一个常见的情况是确保帐户在其帐户中具有特定的能力,并确保对其具有特定类型的限制,以确认交易可以正常工作。我们可以通过getPathsWithType
:
获得有关路径的扩展版本,并提供有关它们的额外信息
test("read path types", async () => {
const { publicPaths } = await getPathsWithType("Alice");
const refTokenBalance = publicPaths.flowTokenBalance;
expect(refTokenBalance).not.toBe(undefined);
expect(refTokenBalance.restrictionsList.has("A.ee82856bf20e2aa6.FungibleToken.Balance")).toBe(
true
);
expect(refTokenBalance.restrictionsList.size).toBe(1);
expect(refTokenBalance.haveRestrictions("FungibleToken.Balance")).toBe(true);
});
您可以评论这些expect
语句,并使用console.log(refTokenBalance)
查看所有可用的选项,您可以使用它的正确性。
读取存储值
现在,让我们在爱丽丝的存储中存储一个值,然后尝试通过getStorageValue
读取它。我们需要传递帐户名(即"Alice"
)或我们用getAccountAddress
和存储路径解决的地址
test("read storage", async () => {
const Alice = await getAccountAddress("Alice");
await shallPass(
sendTransaction({
code: `
transaction{
prepare(signer: AuthAccount){
signer.save(42, to: /storage/answer)
}
}
`,
signers: [Alice],
})
);
const { storagePaths } = await getPaths(Alice);
const answer = await getStorageValue(Alice, "answer");
expect(answer).toBe("42");
expect(storagePaths.has("answer")).toBe(true);
// We can also try to read non-existing value, which shall be resolved to null
// Notice that we pass string here ;)
const empty = await getStorageValue("Alice", "empty");
expect(empty).toBe(null);
});
存储统计
在帐户检查期间您可以透露的另一种有用的方法是getStorageStats
-如果您认为用户可能会持有庞大的收藏并检查其将占用多少存储,则可能需要一种:
test("Read storage stats", async () => {
const { capacity, used } = await getStorageStats("Alice");
expect(capacity).toBe(100000);
expect(used > 0).toBe(true);
});
有帮助者
最后但并非最不重要的一点是,有几个开玩笑的帮助者可以简化检查过程并缩短测试。
shallHavePath(account, pathName)
此功能将允许快速确认在帐户中存在路径。请注意,第二个参数包含一个完整的路径,包括域
test("get paths", async () => {
const Alice = await getAccountAddress("Alice");
await shallHavePath(Alice, "/public/flowTokenBalance");
await shallHavePath(Alice, "/public/flowTokenReceiver");
});
shallHaveStorageValue(account, {props})
使用此功能,我们可以快速检查复杂和简单的存储值。让我们从简单开始:
test("read storage", async () => {
const Alice = await getAccountAddress("Alice");
await shallPass(
sendTransaction({
code: `
transaction{
prepare(signer: AuthAccount){
signer.save(42, to: /storage/answer)
}
}
`,
signers: [Alice],
})
);
// This time we only need to path path in storage domain
await shallHaveStorageValue(Alice, {
pathName: "answer",
expect: "42",
});
});
或者如果我们知道存储中的值很复杂 - 假设一些NFT或VAULT,那么我们可以为如何访问它并检查我们的期望提供关键:
test("compare complex storage value", async () => {
const Alice = await getAccountAddress("Alice");
// We will read "balance" field of the value stored in "/storage/flowTokenVault" slot
await shallHaveStorageValue(Alice, {
pathName: "flowTokenVault",
key: "balance",
expect: "0.00100000",
});
});
今天就是这样! ð
如果您认为我们错过了一些有价值的例子ð
祝你好运,玩得开心! ð