-
Notifications
You must be signed in to change notification settings - Fork 37
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
Added Account Integration Tests for Web Client #532
Added Account Integration Tests for Web Client #532
Conversation
@@ -6,107 +6,6 @@ import { testingPage } from "./mocha.global.setup.mjs"; | |||
* @typedef {import("../dist/index").AccountId} AccountId | |||
*/ | |||
|
|||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for each testing file, we'll need setup functions like this that leverage the use of the testingPage
and an actual browser context to perform certain actions in WASM and return certain data to be checked in the actual tests. For that reason, I've started removing these functions from here and replaced them with similar relevant code in each new testing file. As I add more integration tests and more relevant files, I will continue removing stuff from this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this file and replaced it with new_account.test.ts
, and account.test.ts
.
return { | ||
id: newWallet.id().to_string(), | ||
nonce: newWallet.nonce().to_string(), | ||
vault_commitment: newWallet.vault().commitment(), | ||
storage_commitment: newWallet.storage().commitment(), | ||
code_commitment: newWallet.code().commitment(), | ||
is_faucet: newWallet.is_faucet(), | ||
is_regular_account: newWallet.is_regular_account(), | ||
is_updatable: newWallet.is_updatable(), | ||
is_public: newWallet.is_public(), | ||
is_new: newWallet.is_new(), | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add a comment somewhere in the codebase if it helps, but testing the WASM is a bit interesting. Basically, you need puppeteer to create a browser context that loads and uses the WASM. That being said, once you get to the actual unit tests, you don't have access to any WASM things because you no longer have the browser context. So until we figure out a better solution, for now, I'm just extracting any useful information I need from the resulting client calls and referencing this returned data in the unit tests.
window.Account = Account; | ||
window.AccountHeader = AccountHeader; | ||
window.AccountStorageMode = AccountStorageMode; | ||
window.AuthSecretKey = AuthSecretKey |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some checks in which I want to assert that the object returned from WASM is of a specific type. To do this, I have to attach the object type to the window here in the mocha global setup code so that it's accessible in the testingPage.evaluate
scope in the testing files.
declare global { | ||
interface Window { | ||
client: WebClient; | ||
Account: typeof Account; | ||
AccountHeader: typeof AccountHeader; | ||
AccountStorageMode: typeof AccountStorageMode; | ||
AuthSecretKey: typeof AuthSecretKey; | ||
create_client: () => Promise<void>; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is another place I had to modify to make the instanceof
assertions work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea! I was struggling to find a way to type everything cleanly in the .ts mocha context, this is way more straightforward.
crates/web-client/src/new_account.rs
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking advantage while writing these tests to slightly clean up the JS <-> Rust Web Client contracts. In this particular file, there is some better error handling, so type changes to the inputs (actual u8s, u64s, etc. passed as inputs as opposed to strings), and changing the outputs to an actual Account
object.
|
||
#[wasm_bindgen] | ||
impl AssetVault { | ||
pub fn commitment(&self) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just exposed this for now, but can add to it later. Just didn't want to bloat the testing PR much more than I already did with error handling and interface polishing.
crates/web-client/src/account.rs
Outdated
} else { | ||
Err(JsValue::from_str("Client not initialized")) | ||
} | ||
} | ||
|
||
pub async fn get_account(&mut self, account_id: String) -> Result<JsValue, JsValue> { | ||
pub async fn get_account(&mut self, account_id: &str) -> Result<Account, JsValue> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think get_account
is good taking in a &str
, but eventually i want everything else to be AccountId
. But in order to do this, I have to be able to create mock accountIds without actually creating them in the Database so for now just having things take &str
as account Ids.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the idea to be able to just create arbitrary AccountId
s? There's AccountId::from_hex(&str)
or AccountId::try_from(u64)
which you can use with these constants for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, this is awesome! Thanks for linking. I created a TestUtils
, exposed it to the WASM, and added a create_mock_account_id()
method that uses one of these constants to create an AccountId
object. Updated all of the account interfaces to take in AccountId
objects as a result now. Thanks so much for pointing this out!
2821885
to
94e4e60
Compare
94e4e60
to
b1f5494
Compare
4e348d1
to
4cf4c41
Compare
it("returns error attempting to retrieve a non-existing account", async () => { | ||
await expect( | ||
getAccountNoMatch() | ||
).to.be.rejectedWith("Failed to get account: Store error: Account data was not found for Account Id 0x1111111111111111"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any specific Error type that we can check for rather than the string output? I'm guessing not, but would be nice in case any messaging upstream changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good question. I replied here with what I was thinking on this front. Maybe exposing an Errors
struct in rust for WASM that handles conversions between the rust-client errors and transforms them to errors we can actually return. That way, we can change the signature of something like get_accounts
to be something like Result<Vec<AccountHeader>, GetAccountsError>>
or something like this as opposed to Result<Vec<AccountHeader>, JsValue>>
.
} | ||
|
||
const client = window.client; | ||
await client.get_account("0x1111111111111111"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Would be nice to create a "test-data.ts" type file where we can put dummy values that can be used throughout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So for this line specifically, I actually went with @igamigo's suggestion here and exposed a TestUtils
struct in Rust for WASM. This lets us leverage any mocking capabilities that the rust-client exposes for the purpose of those tests, and we in turn can create functions that let us take advantage of this in WASM. For this example specifically, I can now call window.TestUtils.create_mock_account_id
to create a fake value that can be parsed into an AccountId
.
In general, though, definitely agree that if we find ourselves needing things that are useful across all the tests like dummy values or functions like isValidAddress
, then a test-data.ts
or test-utils.ts
file definitely makes sense 👍
// new_wallet tests | ||
// ======================================================================================================= | ||
|
||
export const createNewWallet = async ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not blocking for this PR.
I agree with the choice to move some of the functions out of the utils file, but functions like new wallet and new faucet might be useful to be shared across tests, no? We could make that file a .ts file now too, with your changes to the global window typing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good point! I think the reusable parts of the code in this file are the setup like this
return await testingPage.evaluate(async () => {
if (!window.client) {
await window.create_client();
}
const client = window.client;
but I think beyond that, in every integration test, it shouldn't be too much effort to just call client.new_wallet
once this setup code is in place and then do what we have to do (call mint, consume, sync, etc.) 🤔.
Idk I don't see it quite yet, but you're probably right and need to keep a pulse on this as the integration tests take better shape 👍
}; | ||
|
||
describe("fetch_and_cache_account_auth_by_pub_key tests", () => { | ||
it("retrieves an existing account auth and caches it", async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How are we sure that the account auth was cached?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm.. good point 🤔. So the "caching" for now is a simple JS map that gets maintained in memory when this function gets called. My thinking here was that for the purpose of this test (at least for now), it would be enough to verify that the proper account auth was fetch and returned because it would mean that the full JS query to indexedDB would have succeeded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One question regarding this, the difference between client.get_account_auth
and client.fetch_and_cache_account_auth_by_pub_key
is that the second one caches the result?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving some comments for now! The issue with the CI is related to a bug with clippy which we are "fixing" with this PR: #534
crates/web-client/src/account.rs
Outdated
} else { | ||
Err(JsValue::from_str("Client not initialized")) | ||
} | ||
} | ||
|
||
pub async fn get_account(&mut self, account_id: String) -> Result<JsValue, JsValue> { | ||
pub async fn get_account(&mut self, account_id: &str) -> Result<Account, JsValue> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the idea to be able to just create arbitrary AccountId
s? There's AccountId::from_hex(&str)
or AccountId::try_from(u64)
which you can use with these constants for example.
import { expect } from 'chai'; | ||
import { testingPage } from "./mocha.global.setup.mjs"; | ||
|
||
// get_account tests |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: These are usually written in uppercase
addressOfCreatedAccount: newAccount.id().to_string(), | ||
addressOfGetAccountResult: result.id().to_string(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comparing account hashes might be more complete here, to see that integrity with code, nonce and storage is maintained.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great suggestion! Updated 👍
4cf4c41
to
01fcecb
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, works correctly on my machine. The only thing I would like to mention is that when I purposefully added a throw new Error("...");
in the code, the error message shown by Mocha was Error: the string "..." was thrown, throw an Error :)
. It seems Mocha prefers Error
values instead of strings, we could change them in the future.
* Web Client Account Integration Tests
* Web Client Account Integration Tests
Summary
In order to prevent regressions on the web client as the rust and web-clients develop, we need integration tests that can be run via github workflows to test the basic functionality of the web client. In #498, the infrastructure was added to be able to implement mocha tests for the web client and have them execute via a github action workflow. However, no real tests were added at the time.
This PR adds the first batch of these tests. The code tested are the code under the
new_account.rs
andaccount.rs
files. in the web-client. Incoming in future PRs will be tests fornotes.rs
,sync.rs
, andtransactions.rs
, andnew_transactions.rs
.