-
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: [POM] Migrate token tests #29375
Changes from 19 commits
c5367d0
6e9112d
20ba9c4
352dd40
886cf1a
874c128
d00f8e3
5aa73cf
bab4345
073579f
b4d3fec
e8fbb7a
f11c25d
be104ee
faffc73
f8a0e0e
10f2f7a
37cbee3
7f54477
3c2f970
b0febde
86ae434
8ea7007
6be682d
a8ab1ad
c166dff
f678372
c09fd7d
7888d66
e1183f0
15854d4
9f39c02
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 |
---|---|---|
|
@@ -24,6 +24,11 @@ class AssetListPage { | |
|
||
private readonly currentNetworksTotal = `${this.currentNetworkOption} [data-testid="account-value-and-suffix"]`; | ||
|
||
private readonly customTokenModalOption = { | ||
text: 'Custom token', | ||
tag: 'button', | ||
}; | ||
|
||
private readonly hideTokenButton = '[data-testid="asset-options__hide"]'; | ||
|
||
private readonly hideTokenConfirmationButton = | ||
|
@@ -43,16 +48,45 @@ class AssetListPage { | |
|
||
private readonly networksToggle = '[data-testid="sort-by-networks"]'; | ||
|
||
private sortByAlphabetically = '[data-testid="sortByAlphabetically"]'; | ||
|
||
private sortByDecliningBalance = '[data-testid="sortByDecliningBalance"]'; | ||
|
||
private sortByPopoverToggle = '[data-testid="sort-by-popover-toggle"]'; | ||
|
||
private readonly tokenAddressInput = | ||
'[data-testid="import-tokens-modal-custom-address"]'; | ||
|
||
private readonly tokenAmountValue = | ||
'[data-testid="multichain-token-list-item-value"]'; | ||
|
||
private readonly tokenImportedSuccessMessage = { | ||
text: 'Token imported', | ||
tag: 'h6', | ||
}; | ||
|
||
private readonly tokenListItem = | ||
'[data-testid="multichain-token-list-button"]'; | ||
|
||
private readonly tokenOptionsButton = '[data-testid="import-token-button"]'; | ||
|
||
private tokenPercentage(address: string): string { | ||
return `[data-testid="token-increase-decrease-percentage-${address}"]`; | ||
} | ||
|
||
private readonly tokenSearchInput = 'input[placeholder="Search tokens"]'; | ||
|
||
private readonly tokenSymbolInput = | ||
'[data-testid="import-tokens-modal-custom-symbol"]'; | ||
|
||
private readonly modalWarningBanner = 'div.mm-banner-alert--severity-warning'; | ||
|
||
private readonly tokenIncreaseDecreaseValue = | ||
'[data-testid="token-increase-decrease-value"]'; | ||
|
||
private readonly tokenIncreaseDecreasePercentageGeneral = | ||
'[data-testid="token-increase-decrease-percentage"]'; | ||
|
||
constructor(driver: Driver) { | ||
this.driver = driver; | ||
} | ||
|
@@ -103,6 +137,42 @@ class AssetListPage { | |
return assets.length; | ||
} | ||
|
||
async getTokenListNames(): Promise<string[]> { | ||
console.log(`Retrieving the list of token names`); | ||
const tokenElements = await this.driver.findElements(this.tokenListItem); | ||
const tokenNames = await Promise.all( | ||
tokenElements.map(async (element) => { | ||
return await element.getText(); | ||
}), | ||
); | ||
return tokenNames; | ||
} | ||
|
||
async getAssetPercentageIncreaseDecrease( | ||
chloeYue marked this conversation as resolved.
Show resolved
Hide resolved
|
||
assetAddress: string, | ||
): Promise<string> { | ||
console.log( | ||
`Retrieving the percentage increase or decrease for ${assetAddress}`, | ||
); | ||
const percentageElement = await this.driver.findElement( | ||
this.tokenPercentage(assetAddress), | ||
); | ||
const percentage = await percentageElement.getText(); | ||
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. mmm this is an anti-pattern that opens the door to race conditions, where the element is rendered but it does not have yet the value we expect.
What do you think? 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. Good point! I agree with you here. I have used |
||
return percentage; | ||
} | ||
|
||
async sortTokenList( | ||
sortBy: 'alphabetically' | 'decliningBalance', | ||
): Promise<void> { | ||
console.log(`Sorting the token list by ${sortBy}`); | ||
await this.driver.clickElement(this.sortByPopoverToggle); | ||
if (sortBy === 'alphabetically') { | ||
await this.driver.clickElement(this.sortByAlphabetically); | ||
} else if (sortBy === 'decliningBalance') { | ||
await this.driver.clickElement(this.sortByDecliningBalance); | ||
} | ||
} | ||
|
||
/** | ||
* Hides a token by clicking on the token name, and confirming the hide modal. | ||
* | ||
|
@@ -119,6 +189,22 @@ class AssetListPage { | |
); | ||
} | ||
|
||
async importCustomToken(tokenAddress: string, symbol: string): Promise<void> { | ||
console.log(`Creating custom token ${symbol} on homepage`); | ||
await this.driver.clickElement(this.tokenOptionsButton); | ||
await this.driver.clickElement(this.importTokensButton); | ||
await this.driver.waitForSelector(this.importTokenModalTitle); | ||
await this.driver.clickElement(this.customTokenModalOption); | ||
await this.driver.waitForSelector(this.modalWarningBanner); | ||
await this.driver.fill(this.tokenAddressInput, tokenAddress); | ||
await this.driver.fill(this.tokenSymbolInput, symbol); | ||
await this.driver.clickElement(this.importTokensNextButton); | ||
await this.driver.clickElementAndWaitToDisappear( | ||
this.confirmImportTokenButton, | ||
); | ||
await this.driver.waitForSelector(this.tokenImportedSuccessMessage); | ||
} | ||
|
||
async importTokenBySearch(tokenName: string) { | ||
console.log(`Import token ${tokenName} on homepage by search`); | ||
await this.driver.clickElement(this.tokenOptionsButton); | ||
|
@@ -133,6 +219,24 @@ class AssetListPage { | |
); | ||
} | ||
|
||
async importMultipleTokensBySearch(tokenNames: string[]) { | ||
console.log( | ||
`Importing tokens ${tokenNames.join(', ')} on homepage by search`, | ||
); | ||
await this.driver.clickElement(this.tokenOptionsButton); | ||
await this.driver.clickElement(this.importTokensButton); | ||
await this.driver.waitForSelector(this.importTokenModalTitle); | ||
|
||
for (const name of tokenNames) { | ||
await this.driver.fill(this.tokenSearchInput, name); | ||
await this.driver.clickElement({ text: name, tag: 'p' }); | ||
} | ||
await this.driver.clickElement(this.importTokensNextButton); | ||
await this.driver.clickElementAndWaitToDisappear( | ||
this.confirmImportTokenButton, | ||
); | ||
} | ||
|
||
async openNetworksFilter(): Promise<void> { | ||
console.log(`Opening the network filter`); | ||
await this.driver.clickElement(this.networksToggle); | ||
|
@@ -235,6 +339,44 @@ class AssetListPage { | |
`Expected number of token items ${expectedNumber} is displayed.`, | ||
); | ||
} | ||
|
||
/** | ||
* Checks if the token increase/decrease percentage is displayed correctly for a specific token | ||
* | ||
* @param address - The token address to check | ||
* @param expectedPercentage - The expected percentage value (e.g. '+0.02%') | ||
*/ | ||
async check_tokenIncreasePercentage( | ||
address: string, | ||
expectedPercentage: string, | ||
): Promise<void> { | ||
console.log(`Checking token increase percentage for address ${address}`); | ||
const isPresent = await this.driver.isElementPresentAndVisible({ | ||
css: `[data-testid="token-increase-decrease-percentage-${address}"]`, | ||
text: expectedPercentage, | ||
}); | ||
if (!isPresent) { | ||
throw new Error( | ||
`Token increase percentage ${expectedPercentage} not found for address ${address}`, | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Checks if the token increase/decrease value is displayed correctly | ||
* | ||
* @param expectedValue - The expected value (e.g. '+$50.00') | ||
*/ | ||
async check_tokenIncreaseValue(expectedValue: string): Promise<void> { | ||
console.log(`Checking token increase value ${expectedValue}`); | ||
const isPresent = await this.driver.isElementPresentAndVisible({ | ||
css: this.tokenIncreaseDecreaseValue, | ||
text: expectedValue, | ||
}); | ||
if (!isPresent) { | ||
throw new Error(`Token increase value ${expectedValue} not found`); | ||
} | ||
} | ||
} | ||
|
||
export default AssetListPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { Driver } from '../../webdriver/driver'; | ||
|
||
class TokenOverviewPage { | ||
private driver: Driver; | ||
|
||
private readonly sendButton = { | ||
text: 'Send', | ||
css: '.icon-button', | ||
}; | ||
|
||
private readonly receiveButton = { | ||
text: 'Receive', | ||
css: '.icon-button', | ||
}; | ||
|
||
private readonly swapButton = { | ||
text: 'Swap', | ||
css: '.icon-button', | ||
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. A couple of small things:
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. Yes, I also had the same thought. It could make sense (if we keep it text based as I have done here) |
||
}; | ||
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. Using text based selectors here, it's more accessible and means we don't have to create multiple selectors depending on the type of token screen we are looking at. i.e Is the token enabled for swap, bridge, send etc. The other selector would be either |
||
|
||
constructor(driver: Driver) { | ||
this.driver = driver; | ||
} | ||
|
||
async check_pageIsLoaded(): Promise<void> { | ||
try { | ||
await this.driver.waitForMultipleSelectors([ | ||
this.sendButton, | ||
this.swapButton, | ||
]); | ||
} catch (e) { | ||
console.log( | ||
'Timeout while waiting for Token overview page to be loaded', | ||
e, | ||
); | ||
throw e; | ||
} | ||
console.log('Token overview page is loaded'); | ||
} | ||
|
||
async clickSend(): Promise<void> { | ||
await this.driver.clickElement(this.sendButton); | ||
} | ||
|
||
async clickReceive(): Promise<void> { | ||
await this.driver.clickElement(this.receiveButton); | ||
} | ||
|
||
async clickSwap(): Promise<void> { | ||
await this.driver.clickElement(this.swapButton); | ||
} | ||
} | ||
|
||
export default TokenOverviewPage; |
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: maybe we can improve the selector by adding a data test id in the Import Token component (here), like this:
and then use it as the selector