-
-
Notifications
You must be signed in to change notification settings - Fork 10
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
Test suite should capture how we expect the library to be used #219
Comments
I'll start to use |
Hey @pcowgill, I'm working on that on gnosis safe test suites, what do you think? Before (with waiting) it("wallet owner should withdraw some ethers", async () => {
const signers = [anaWallet];
const { address: toAddress } = anaWallet;
const value = ONE;
gnosisSafe.setWallet(anaWallet);
const execTxAction = await gnosisSafe.transferEther(
signers,
toAddress,
value
);
await execTxAction.waitForNonceToUpdate();
const balanceAfterWithdraw = await provider.getBalance(
GNOSIS_SAFE_ADDRESS
);
expect(`${balanceAfterWithdraw}`).to.equal(`${ZERO}`);
}); After (without waiting) it("wallet owner should withdraw some ethers", async () => {
const signers = [anaWallet];
const { address: toAddress } = anaWallet;
const value = ONE;
gnosisSafe.setWallet(anaWallet);
const action = await gnosisSafe.transferEther(signers, toAddress, value);
const onConfirmation = async message => {
const { data } = message;
const { args } = data;
action.unsubscribe();
const balance = await provider.getBalance(GNOSIS_SAFE_ADDRESS);
expect(`${balance}`).to.equal(`${ZERO}`);
};
const onError = message => {
const { error } = message;
console.log(error);
};
await dispatch(action, onConfirmation, onError);
});
const dispatch = async (action, onConfirmation, onError) => {
return new Promise((resolve, reject) => {
action.on("confirmation", async message => {
try {
await onConfirmation(message);
resolve();
} catch (error) {
reject(error);
}
});
action.on("error", message => {
const { error } = message;
onError(message);
reject(error);
});
});
}; Note: |
@marcelomorgado Does this not work? it("wallet owner should withdraw some ethers", (done) => {
const signers = [anaWallet];
const { address: toAddress } = anaWallet;
const value = ONE;
gnosisSafe.setWallet(anaWallet);
const action = await gnosisSafe.transferEther(signers, toAddress, value);
const onConfirmation = async message => {
const { data } = message;
const { args } = data;
action.unsubscribe();
const balance = await provider.getBalance(GNOSIS_SAFE_ADDRESS);
expect(`${balance}`).to.equal(`${ZERO}`);
done();
};
const onError = message => {
const { error } = message;
console.log(error);
done(error);
};
action.send();
}); |
@marcelomorgado Also, since we weren't handling the error case in the async/await version with a try/catch, it's not a 1-1 comparison to include the |
No, not really because sync functions shouldn't have |
@marcelomorgado Oh oops, I missed those await's in there - I meant to write it without any but did it too quickly. |
@marcelomorgado How about this it("wallet owner should withdraw some ethers", (done) => {
const signers = [anaWallet];
const { address: toAddress } = anaWallet;
const value = ONE;
gnosisSafe.setWallet(anaWallet);
// Building actions won't be async anymore in the future
const action = gnosisSafe.transferEther(signers, toAddress, value);
const onConfirmation = message => {
const { data } = message;
const { args } = data;
action.unsubscribe();
// If we expose a blocking, sync version of getBalance as a helper we should be good
// Alternatively convert getBalance to a promise can call done when it resolves?
const balance = provider.getBalance(GNOSIS_SAFE_ADDRESS);
expect(`${balance}`).to.equal(`${ZERO}`);
done();
};
const onError = message => {
const { error } = message;
console.log(error);
done(error);
};
action.send();
}); |
Or as a third alternative, call a function that's async from within the onConfirmation handler and keep the await approach for |
Related: #128 |
Some comments:
// I need to find out how to convert `balance` to string
return expect(balance).eventually.equal(`${ZERO}`);
|
@marcelomorgado That all makes sense and sounds good! |
@pcowgill commented:
|
I'm trying to keep async/await syntax and having event-driven test cases as we want to do on the app. Seems that mocha supports only one of these paths:
Refs: mochajs/mocha#2407 (comment) and mochajs/mocha#2988 (comment) it("should buy an estate", async () => {
const {
assetId,
nftAddress,
seller,
priceInWei,
expiresAt,
} = estateForSale;
await checkAsset(estate, mana, estateForSale, ephemeralAddress);
await expectExactTokenBalances(estate, [ephemeralAddress], [0]);
const fingerprint = await estate.getFingerprint(`${assetId}`);
marketplace.setWallet(ephemeralWallet);
const executeOrderAction = marketplace.safeExecuteOrder(
nftAddress,
`${assetId}`,
`${priceInWei}`,
`${fingerprint}`
);
return new Promise((resolve, reject) => {
const successfulListener = async message => {
const { data } = message;
const { args } = data;
const { buyer } = args;
marketplace.off("OrderSuccessful");
expect(buyer).to.equal(ephemeralAddress);
await expectExactTokenBalances(estate, [ephemeralAddress], [1]);
resolve();
};
const errorListener = message => {
const { error } = message;
reject(error);
};
marketplace.on("OrderSuccessful", successfulListener);
marketplace.on("error", errorListener);
executeOrderAction.send();
});
}); What do you think @pcowgill ? |
@marcelomorgado Would another alternative be using a |
In the current style where the test itself is async, we can't use
|
@marcelomorgado If you want to do it as written above, to perfectly follow the last example here - mochajs/mocha#2988 (comment) - the executeOrderAction.send(); should move outside the promise, right? |
Do you mean using an unnamed async function to the pre-conditions? If is it, I think I'll need to use the
I'm thinking on that but for now I'm not sure how I can do the same as the resolve/reject functions. The advantage of the
Yes, actually the code above works if the I know that you wrote a draft for it before but I think this last one is a good example since we have 3 async calls before the call that we want to test, if you are seeing something that I'm not, a code sample could help me. |
No, I meant in the test itself. Or, what did you mean by pre-conditions here? |
I think async/await with a try catch where you return in either the try or the catch is the same as doing a resolve or a reject, right? |
Yep, we need to find a way to replace that. Just checking if resolve is the only way we can do it. |
Cool. Let's move it then.
Okay - go with this for now, and I'll play around with the options I was suggesting above |
We have these async functions to check if the pre-conditions of the test are satisfied: await checkAsset(estate, mana, estateForSale, ephemeralAddress);
await expectExactTokenBalances(estate, [ephemeralAddress], [0]); And to call the const fingerprint = await estate.getFingerprint(`${assetId}`); |
Right, the difference is how to wait for something to happen. Seems that using |
Yep. So since async/await uses promises under the hood, why not use async/await instead of a promise? |
Ah ok, I see what you mean by pre-conditions now. Thanks.
Yep, that's what I mean if we used the
Hmm, I don't think so. Couldn't this sync function also be in the unnamed async function? Or is |
Wow, I think that I've got it! it.only("should buy an estate", done => {
(async () => {
const {
assetId,
nftAddress,
seller,
priceInWei,
expiresAt,
} = estateForSale;
await checkAsset(estate, mana, estateForSale, ephemeralAddress);
await expectExactTokenBalances(estate, [ephemeralAddress], [0]);
const fingerprint = await estate.getFingerprint(`${assetId}`);
marketplace.setWallet(ephemeralWallet);
const executeOrderAction = marketplace.safeExecuteOrder(
nftAddress,
`${assetId}`,
`${priceInWei}`,
`${fingerprint}`
);
const successfulListener = sinon.fake(async message => {
const { data } = message;
const { args } = data;
const { buyer } = args;
marketplace.off("OrderSuccessful");
expect(buyer).to.equal(ephemeralAddress);
await expectExactTokenBalances(estate, [ephemeralAddress], [1]);
done();
});
const errorListener = sinon.fake(message => {
const { error } = message;
done(error);
});
marketplace.on("OrderSuccessful", successfulListener);
marketplace.on("error", errorListener);
executeOrderAction.send();
})();
}); |
@marcelomorgado Nice!!! Yeah that's just what we want. |
This change should be extended to all test cases of the project? |
I think so, yes. As long as you agree! |
Ok, I agree, because of that I haven't marked this issue to be closed by the PR. |
Great, thanks |
I've removed the |
Good call. Thanks. |
On UX context, our users will dispatch actions that will trigger some UI response for success or failure of the processes.
For now, all of our test suites wasn't written closer that way, we are using in almost all of test cases the
waitForNonceToUpdate
function and we expect that will not be used for our users.The way to write test cases to get closer as we expected that the code will be it to using
mocha
done()
function.Refs:
#207 (comment)
mochajs/mocha#2988 (comment)
https://mochajs.org/#asynchronous-code
The text was updated successfully, but these errors were encountered: