Skip to content
This repository has been archived by the owner on Jan 15, 2021. It is now read-only.

Playwright wallet connection test #1625

Merged
merged 30 commits into from
Nov 20, 2020

Conversation

Velenir
Copy link
Contributor

@Velenir Velenir commented Nov 17, 2020

  • Adds Wallet injection into playwright browser (window.ethereum)
  • Compilation for browser injects step when needed
  • Integration test for connecting user wallet

To see it perform and to test/debug please run

#serve the app
serve -s -l 8080 dist
#in a different terminal
yarn playwright:debug --testNamePattern=wallet

Actually please just run that so we can check it works on different machines

@gnosis-info
Copy link

Travis automatic deployment:


// WHEN: connected a Wallet
// Click text=/.*Connect Wallet.*/
await page.click('text=/.*Connect Wallet.*/')
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't look like a specific (HTML) selector but rather (regex?) looking for a specific text string. Unless I misunderstand this piece, is it better to scope down to the selectors so that their presence is validated too?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idea is to do testing from user perspective
page.click('text=/.*Connect Wallet.*/') represents

  1. User comes to a page
  2. User sees text, not a selector, not even necessarily link or button
  3. User doesn't care, text looks clickable
  4. User clicks

That's what playwright docs recommend and what some other libraries (like react-testing-lib) advocate for

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Selector presence is for unit (not even integration) testing with libs that like comparing snapshots, like Enzyme
Look up Enzyme vs react-testing-library approaches

Copy link
Contributor

Choose a reason for hiding this comment

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

Does that open up possible collusions/complexity around identical naming conventions for text/labels? Or do you see that as an advantage in terms of enforcing a better user experience for the user? I like the thinking here otherwise, but curious on your thoughts.

Copy link
Contributor

Choose a reason for hiding this comment

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

Although after reading the docs, I wonder if using an actual user-facing attribute like 'aria-label' or 'title' (etc.) would be better. It would thick both the 'selector' and 'user facing attribute/text' boxes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it does, you are completely right. Trade offs are trade offs
That's why I use header >> text=Web3 in another click, for specificity

You can even argue, as you are saying, for better user xp. For example we have Connect Wallet both in header and in TradeOrders component (when disconnected). But they do the same, so we shouldn't care which user clicks

dex dev gnosisdev com_ (1)
dex dev gnosisdev com_ (2)

Copy link
Contributor

Choose a reason for hiding this comment

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

But the test will only click the first found item? E.g. I guess we want to be sure to test all possible instance for working properly as expected?

Copy link
Contributor Author

@Velenir Velenir Nov 17, 2020

Choose a reason for hiding this comment

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

Yep
We want to be sure of the whole user flow
So to properly test we would need to do txs
And not rely on rinkeby random address
So setup ganache and deploy contracts locally and who knows what else

So yes,and no 😉

Copy link
Contributor

Choose a reason for hiding this comment

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

Makes sense.

Comment on lines +18 to +22
// THEN: wallet connected & address available
// XPATH: closest ancestor with 0x* text of element with text "Copy address to clipboard"
const textWithAddress = await page.textContent(
'//*[text()="Copy address to clipboard"]//ancestor::*[starts-with(., "0x")][1]',
)
Copy link
Contributor Author

@Velenir Velenir Nov 17, 2020

Choose a reason for hiding this comment

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

@biocom
This is a good example of playwright approach.
As there aren't better ways to distinguish where the address is, instead of <wallet popup class which is pseudo-random with hash 'cause generated by styled-comps> > text that looks like address
I opted for Copy address to clipboard button > closest parent with address
dex dev gnosisdev com_

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is quite thorough, which is good. As opposed to testing for selectors.

What if there a multiple of these components doing the same thing for some reason? page.Textcontent() only returns the first found item? E.g. would be good to test the validity of any other similar/identical item on page.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Very well may be
Like here

Copy link
Contributor

@anxolin anxolin left a comment

Choose a reason for hiding this comment

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

Do the test take so much time to you?
image

Also, do they fail, I get this error?

image


Edit, running a second time I got them working. Still slow..
image

cypress run it in 1sec with the video enabled. Probably can be accelerated
image

Is it possible is a bit flaky? Why do they’ll take so much time?


beforeAll(async () => {
// launch chrome,headless by default
browser = await chromium.launch({ slowMo })
Copy link
Contributor

Choose a reason for hiding this comment

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

Are we hardcoding the tests to chromium?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we have to hardcode something
can of course do BROWSER=chromium|firefox|webkit and later pick it

Copy link
Contributor

Choose a reason for hiding this comment

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

Also can think about an optional executablePath argument, to use Chromium but use your local installed Chrome browser. Should in theory be the same I suppose (Chromium <-> Chrome) but there can be nuances in practice when testing.

Copy link
Contributor Author

@Velenir Velenir Nov 17, 2020

Choose a reason for hiding this comment

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

Nah, can't count on Chrome extensions not screwing everything up
Because if you just use local Chrome, and have MMask installed, it will conflict with window.ethereum injected by playwright
And if you use local Chrome with --sandbox or whatever no-extension flag, then it's almost the same as Chromium

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess my thinking is:

  • Even having 'expected' extensions like MM, might simulate/catch some side effects/bugs as opposed to run it in a clean env. like Chromium.
  • Same for running Chromium vs Chrome, like you say they are almost the same but I'd regard it as a more realistic test if you know what I mean.

Copy link
Contributor Author

@Velenir Velenir Nov 17, 2020

Choose a reason for hiding this comment

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

Now this is interesting indeed. Can do

BROWSER=chromium EXECUTABLE_PATH=$(which google-chrome) yarn test:playwright

@@ -31,7 +31,8 @@
"cypress": "cypress open",
"cypress:run": "cypress run",
"playwright": "jest --roots playwright --no-cache",
"playwright:debug": "PWDEBUG=1 jest --roots playwright",
"playwright:rebuild": "ts-node ./playwright/utils/build_injects.ts",
"playwright:debug": "PWDEBUG=1 jest --roots playwright --runInBand",
Copy link
Contributor

Choose a reason for hiding this comment

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

Good call creating this script

@Velenir
Copy link
Contributor Author

Velenir commented Nov 17, 2020

Is it possible is a bit flaky? Why do they’ll take so much time?

This is strange. How did you run? what command?
@biocom , @W3stside can you also try
First yarn test:playwright for the whole test
After

#serve the app
serve -s -l 8080 dist
#in a different terminal
yarn playwright:debug --testNamePattern=wallet

@anxolin
Copy link
Contributor

anxolin commented Nov 17, 2020

With test:playwrite is taking less time 8s and succeeding

image

The debug worked too now

@Velenir
Copy link
Contributor Author

Velenir commented Nov 18, 2020

Added BROWSER and EXECUTION_PATH env vars.
Would be cool if you tried

serve -s -l 8080 dist

BROWSER=chromium EXECUTABLE_PATH=$(which google-chrome) yarn playwright #or brave browser
BROWSER=firefox yarn playwright
BROWSER=webkit yarn playwright

webkit doesn't work for me, though, but it worked for @W3stside

@anxolin anxolin mentioned this pull request Nov 19, 2020
Copy link
Contributor

@anxolin anxolin left a comment

Choose a reason for hiding this comment

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

Very good job.
The injection was a bit hacky, I mean. programmatically using webpack to compile the wallet, ...

I haven't gone over all the doc, so not sure if there's simpler way. I would think so, but just glad u found a solution.


// WHEN: connected a Wallet
// Click text=/.*Connect Wallet.*/
await page.click('text=/.*Connect Wallet.*/')
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you use a "pattern", is not needed right? (since text selector already searches for partial text matching)

Also, I think it's more readable the short-form

Copy link
Contributor

Choose a reason for hiding this comment

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

I've try it out here, feel free to merge if u agree #1631

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This pattern was made by playwright itself during playwright:record, I just didn't think twice to change it

jest.setTimeout(30000)
if (isDebug) {
// slow down playright actions
slowMo = 2000
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add a const on top, and explain that artificially delay the test to visually see what is going on

@Velenir Velenir merged commit e2e9d41 into playwright_integration Nov 20, 2020
@Velenir Velenir deleted the playwright_wallet_test branch November 20, 2020 07:34
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants