-
Notifications
You must be signed in to change notification settings - Fork 5k
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: migrate simple send spec to POM #22464
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
class HeaderNavbar { | ||
constructor(driver) { | ||
// Selectors | ||
this.driver = driver; | ||
this.btnAccountMenu = '[data-testid="account-menu-icon"]'; | ||
} | ||
|
||
// Methods | ||
async openAccountMenu() { | ||
await this.driver.clickElement(this.btnAccountDetailsMenu); | ||
} | ||
} | ||
|
||
module.exports = HeaderNavbar; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
const HeaderNavbar = require('../components/header-navbar'); | ||
|
||
class BasePage { | ||
constructor(driver) { | ||
this.driver = driver; | ||
this.headerNavbar = new HeaderNavbar(driver); | ||
} | ||
} | ||
|
||
module.exports = BasePage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
const BasePage = require('./base.page'); | ||
|
||
class ConfirmTxPage extends BasePage { | ||
constructor(driver) { | ||
// Selectors | ||
super(driver); | ||
this.btnConfirm = '[data-testid="page-container-footer-next"]'; | ||
} | ||
|
||
// Methods | ||
async confirmTx() { | ||
await this.driver.clickElement(this.btnConfirm); | ||
} | ||
} | ||
|
||
module.exports = ConfirmTxPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
const BasePage = require('./base.page'); | ||
|
||
class HomePage extends BasePage { | ||
constructor(driver) { | ||
// Selectors | ||
super(driver); | ||
this.btnSend = '[data-testid="eth-overview-send"]'; | ||
this.btnActivity = '[data-testid="home__activity-tab"]'; | ||
this.confirmedTx = '.transaction-status-label--confirmed'; | ||
} | ||
|
||
// Methods | ||
async startSendFlow() { | ||
await this.driver.clickElement(this.btnSend); | ||
} | ||
|
||
async goToActivityList() { | ||
await this.driver.clickElement(this.btnActivity); | ||
} | ||
|
||
async isConfirmedTxInActivity() { | ||
return await this.driver.isElementPresent(this.confirmedTx); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. notice here we don't do any assertion, we only return a boolean. As stated in the guidelines, assertions should go on the spec level, not on the page object classes. See below how this method is called in the spec for doing the assertion there There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I propose we consider incorporating assertion methods within our page object. This approach could offer several advantages:
For the class organization: We already have elements and action methods, when we add a section for check methods in the page class, we could consider adopting a naming convention such as check_xxx for assertions and action_xxx for actions. Something like action_ startSendFlow(), This approach would make it easier to locate specific methods within the class, especially when dealing with a large list of class methods
This approach would automatically generate a helpful error message for debugging purposes. In fact, I would recommend that all check methods have their error messages defined within the class. Currently, in our tests, error messages are not always specified in the test spec. By defining error messages within the class, we can ensure that meaningful error messages are consistently used throughout our tests, making it easier for people to create and debug tests. |
||
} | ||
|
||
module.exports = HomePage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
const BasePage = require('./base.page'); | ||
|
||
class LoginPage extends BasePage { | ||
constructor(driver) { | ||
// Selectors | ||
super(driver); | ||
this.inputPassword = '#password'; | ||
this.btnUnlock = '[data-testid="unlock-submit"]'; | ||
} | ||
|
||
// Methods | ||
async addPassword(password) { | ||
await this.driver.fill(this.inputPassword, password); | ||
} | ||
|
||
async unlock() { | ||
await this.driver.clickElement(this.btnUnlock); | ||
} | ||
} | ||
|
||
module.exports = LoginPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
const BasePage = require('./base.page'); | ||
|
||
class SendToPage extends BasePage { | ||
constructor(driver) { | ||
// Selectors | ||
super(driver); | ||
this.inputAmount = '[data-testid="currency-input"]'; | ||
this.btnNext = '[data-testid="page-container-footer-next"]'; | ||
} | ||
|
||
// Methods | ||
async addAmount(amount) { | ||
await this.driver.fill(this.inputAmount, amount); | ||
} | ||
|
||
async goToNextScreen() { | ||
await this.driver.clickElement(this.btnNext); | ||
} | ||
} | ||
|
||
module.exports = SendToPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
const BasePage = require('./base.page'); | ||
|
||
class SendToPage extends BasePage { | ||
constructor(driver) { | ||
// Selectors | ||
super(driver); | ||
this.inputRecipient = '[data-testid="ens-input"]'; | ||
} | ||
|
||
// Methods | ||
async addRecipient(recipientAddress) { | ||
await this.driver.fill(this.inputRecipient, recipientAddress); | ||
} | ||
} | ||
|
||
module.exports = SendToPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const LoginPage = require('../page-objects/login.page'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. processes: are flows that keep repeating across different tests with few variations (captured by params in the functions) |
||
|
||
const unlockWallet = async (driver, password) => { | ||
const loginPage = new LoginPage(driver); | ||
|
||
await driver.navigate(); | ||
await loginPage.addPassword(password); | ||
await loginPage.unlock(); | ||
}; | ||
|
||
module.exports = unlockWallet; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,15 @@ | ||
const { strict: assert } = require('assert'); | ||
const { | ||
defaultGanacheOptions, | ||
withFixtures, | ||
sendTransaction, | ||
logInWithBalanceValidation, | ||
WALLET_PASSWORD, | ||
} = require('../helpers'); | ||
const FixtureBuilder = require('../fixture-builder'); | ||
const ConfirmTxPage = require('../page-objects/confirm-tx.page'); | ||
const HomePage = require('../page-objects/home.page'); | ||
const SendToPage = require('../page-objects/send-to.page'); | ||
const SendAmountPage = require('../page-objects/send-amount.page'); | ||
const unlockWallet = require('../processes/unlock-wallet'); | ||
|
||
describe('Simple send', function () { | ||
it('can send a simple transaction from one account to another', async function () { | ||
|
@@ -14,14 +19,28 @@ describe('Simple send', function () { | |
ganacheOptions: defaultGanacheOptions, | ||
title: this.test.fullTitle(), | ||
}, | ||
async ({ driver, ganacheServer }) => { | ||
await logInWithBalanceValidation(driver, ganacheServer); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this method is at the moment defined in helpers file and it has a flavor of a process - this has been defined as the process |
||
async ({ driver }) => { | ||
// Process | ||
await unlockWallet(driver, WALLET_PASSWORD); | ||
|
||
await sendTransaction( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this method is at the moment defined in The approach of not going over a process here serves as a demo purpose, as we can see here both processes and normal page object actions using their methods in the specs |
||
driver, | ||
// Page Objects and Components | ||
const confirmTxPage = new ConfirmTxPage(driver); | ||
const homePage = new HomePage(driver); | ||
const sendAmountPage = new SendAmountPage(driver); | ||
const sendToPage = new SendToPage(driver); | ||
|
||
// Actions and Assertions | ||
await homePage.startSendFlow(); | ||
await sendToPage.addRecipient( | ||
'0x985c30949c92df7a0bd42e0f3e3d539ece98db24', | ||
'1', | ||
); | ||
await sendAmountPage.addAmount('1'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we want to keep page objects independent, then when we switch page, we don't return the object of the new class. To improve tests stability, i suggest we add waitPageLoaded() method to each class, so when we switch page in test spec, we can call the waitPageLoaded() first to be sure that we are on the expected page and ready for actions.
The advantage is that we don't need to add waitPageLoaded() everywhere in the test body. |
||
await sendAmountPage.goToNextScreen(); | ||
await confirmTxPage.confirmTx(); | ||
await homePage.goToActivityList(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. all the actions we perform in the test should be clear by their name. This can also be seen as documentation of flows. From this test we infer that Simple Send flow basically is:
|
||
|
||
const confirmedTx = await homePage.isConfirmedTxInActivity(); | ||
assert.equal(confirmedTx, true, 'Confirmed tx is not found'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. assertions are always done on the spec level (never on Page Objects) |
||
}, | ||
); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we're migrating to TypeScript, it might be an ideal time to also adopt it when we implementing the POM. I suggest we consider writing our code in TypeScript during this process. |
||
|
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 component is not used in the
simple-send
spec, but is added in order to build the skeleton of the Page Object Model patterns defined in the proposal. It will be used in other specs and can be expanded according to the specific needs.Also more components can be added following this example