Skip to content
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

Improve unit tests #219

Merged
merged 6 commits into from Jul 26, 2022
Merged

Improve unit tests #219

merged 6 commits into from Jul 26, 2022

Conversation

Gudahtt
Copy link
Member

@Gudahtt Gudahtt commented Jul 19, 2022

The mocks used in the external provider unit tests have been rewritten to allow sending and inspecting messages in either direction. They also no longer rely upon mocking out internal methods.

The getInitializedInpageProvider helper function in the inpage provider tests has been updated with method callbacks, to allow tests to setup replies for specific messages. This will be used in a future PR.

One additional test was added to ensure the isMetaMask property is set on the inpage provider.

The mocks used in the external provider unit tests have been rewritten
to allow sending and inspecting messages in either direction. They also
no longer rely upon mocking out internal methods.

The `getInitializedInpageProvider` helper function in the inpage
provider tests has been updated with method callbacks, to allow tests
to setup replies for specific messages. This will be used in a future
PR.

One additional test was added to ensure the `isMetaMask` property is
set on the inpage provider.
import { createExternalExtensionProvider } from './createExternalExtensionProvider';

describe('createExternalExtensionProvider', () => {
beforeEach(() => {
it('can be called and not throw', () => {
(global.chrome.runtime.connect as any).mockImplementation(() => {
Copy link
Member Author

Choose a reason for hiding this comment

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

Technically I didn't need to move this from the beforeEach into the individual tests here, but it's needed in the next PR because it conflicts with some of the setup in later tests.

src/MetaMaskInpageProvider.test.ts Show resolved Hide resolved
src/MetaMaskInpageProvider.test.ts Outdated Show resolved Hide resolved
if (!isInitialized) {
if (
name === 'metamask-provider' &&
data.method === 'metamask_getProviderState'
Copy link
Contributor

Choose a reason for hiding this comment

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

I notice that with MockDuplexStream, we didn't handle checking for metamask_getProviderState. I think I might know the answer to this, but why do we have to do this now?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question! Previously the initial provider state was set by mocking out the request function and returning the initial state directly, bypassing the entire RPC layer. metamask_getProviderState was never really called, and any code past that request call was not run at all.

That mock was removed, and instead now we're using a mock connection instead. As such, now the entire initialization process is being tested, rather than just up to the .request invocation.

This means our mock has to behave roughly like a real connection with the wallet would though, so it's a bit more complex. This mock is setup to handle the initialization call, then pass along all other calls to the configured callbacks.

Copy link
Contributor

Choose a reason for hiding this comment

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

Very cool. I like that!

Copy link
Member Author

Choose a reason for hiding this comment

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

This conversation had me re-thinking this initialization code, and in retrospect I think this protection is unnecessary and potentially harmful. This logic was simplified here, with the explanation for why in the commit message: 8eee8b8

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah okay. Sounds good!

The initialization step of the mock provider has been simplified. The
initialization event is awaited directly rather than using the more
complicated decomposed promise pattern.
The return type of `getInitializedProvider` is now an object rather
than a tuple. This was done to improve readability. Now it's more clear
exactly what each property is without close inspection.

The return type has been improved as well. Beforehand it was inferred
by TypeScript, but now it is explicitly declared as a type and
documented.
A protection measure was setup in the initialized provider helper
function to prevent it from responding to messages before the
initialization was complete This has been removed.

It was originally added during debugging, to rule out before-
initialization messages as an explanation for a bug that was later
fixed I left it in because I thought that it might better match
expectations if messages before initialization were ignored.

But in retrospect, I think this would be both unnecessary and harmful.
It's unnecessary because for most tests, no messages would be sent
until after initialization anyway. And it's potentially harmful because
this doesn't represent how the provider actually behaves. This could
disguise a mistake in a test, or it could get in the way of testing
strange edge cases surrounding initialization.
Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

Nice. Looks good to me!

@Gudahtt Gudahtt merged commit 274c559 into main Jul 26, 2022
@Gudahtt Gudahtt deleted the improve-unit-tests branch July 26, 2022 21:37
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.

None yet

2 participants