Skip to content

Commit

Permalink
Merge pull request #863 from Synthetixio/dev
Browse files Browse the repository at this point in the history
Promote `dev` to `master`
  • Loading branch information
duckception authored Sep 8, 2023
2 parents d3544f9 + c2c840e commit 618473c
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 0 deletions.
116 changes: 116 additions & 0 deletions commands/metamask.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const log = require('debug')('synpress:metamask');
const playwright = require('./playwright');
const sleep = require('util').promisify(setTimeout);

const {
onboardingWelcomePageElements,
Expand Down Expand Up @@ -1180,6 +1181,70 @@ const metamask = {
log('[confirmTransaction] Transaction confirmed!');
return txData;
},
async confirmTransactionAndWaitForMining(gasConfig) {
// Before we switch to MetaMask tab we have to make sure the notification window has opened.
//
// Chaining `confirmTransactionAndWaitForMining` results in quick tabs switching
// which breaks MetaMask and the notification window does not open
// until we switch back to the "Cypress" tab.
await playwright.switchToMetamaskNotification();

await switchToMetamaskIfNotActive();
await playwright
.metamaskWindow()
.locator(mainPageElements.tabs.activityButton)
.click();

let retries = 0;
const retiresLimit = 600;

// 120 seconds
while (retries < retiresLimit) {
const unapprovedTxs = await playwright
.metamaskWindow()
.getByText('Unapproved')
.count();
if (unapprovedTxs === 1) {
break;
}
await sleep(200);
retries++;
}

if (retries === retiresLimit) {
throw new Error(
'New unapproved transaction was not detected in 120 seconds.',
);
}

const txData = await module.exports.confirmTransaction(gasConfig);

// 120 seconds
while (retries < retiresLimit) {
const pendingTxs = await playwright // TODO rename
.metamaskWindow()
.getByText('Pending')
.count();
const queuedTxs = await playwright // TODO rename
.metamaskWindow()
.getByText('Queued')
.count();
if (pendingTxs === 0 && queuedTxs === 0) {
break;
}
await sleep(200);
retries++;
}

if (retries === retiresLimit) {
throw new Error('Transaction was not mined in 120 seconds.');
}

await switchToCypressIfNotActive();

log('[confirmTransactionAndWaitForMining] Transaction confirmed!');
return txData;
},
async rejectTransaction() {
const notificationPage = await playwright.switchToMetamaskNotification();
await playwright.waitAndClick(
Expand All @@ -1189,6 +1254,57 @@ const metamask = {
);
return true;
},
async openTransactionDetails(txIndex) {
await switchToMetamaskIfNotActive();
await playwright
.metamaskWindow()
.locator(mainPageElements.tabs.activityButton)
.click();

let visibleTxs = await playwright
.metamaskWindow()
.locator(
`${mainPageElements.activityTab.completedTransactionsList} > div`,
)
.filter({ hasNotText: 'History' })
.filter({ hasNotText: 'View more' })
.all();

while (txIndex >= visibleTxs.length) {
try {
await playwright.metamaskWindow().getByText('View more').click();
} catch (error) {
log('[openTransactionDetails] Clicking "View more" failed!');
throw new Error(
`Transaction with index ${txIndex} is not found. There are only ${visibleTxs.length} transactions.`,
);
}

visibleTxs = await playwright
.metamaskWindow()
.locator(
`${mainPageElements.activityTab.completedTransactionsList} > div`,
)
.filter({ hasNotText: 'History' })
.filter({ hasNotText: 'View more' })
.all();
}

await visibleTxs[txIndex].click();

await playwright
.metamaskWindow()
.locator(mainPageElements.popup.container)
.waitFor({ state: 'visible', timeout: 10000 });

return true;
},
async closeTransactionDetailsPopup() {
await switchToMetamaskIfNotActive();
await module.exports.closePopupAndTooltips();
await switchToCypressIfNotActive();
return true;
},
async confirmEncryptionPublicKeyRequest() {
const notificationPage = await playwright.switchToMetamaskNotification();
await playwright.waitAndClick(
Expand Down
24 changes: 24 additions & 0 deletions docs/synpress-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,14 @@ Confirm metamask transaction (auto-detects eip-1559 and legacy transactions).
confirmMetamaskTransaction(gasConfig?: object | string): Chainable<Subject>;
```

#### `cy.confirmMetamaskTransactionAndWaitForMining()`

Confirm metamask transaction (auto-detects eip-1559 and legacy transactions) and wait for ALL pending transactions to be mined.

```ts
confirmMetamaskTransactionAndWaitForMining(gasConfig?: object | string): Chainable<Subject>;
```

#### `cy.rejectMetamaskTransaction()`

Reject metamask transaction.
Expand All @@ -376,6 +384,22 @@ Reject metamask transaction.
rejectMetamaskTransaction(): Chainable<Subject>;
```

#### `cy.openMetamaskTransactionDetails()`

Open metamask transaction details based on the index of the transaction in the list on the activity tab.

```ts
openMetamaskTransactionDetails(txIndex: number): Chainable<Subject>;
```

#### `cy.closeMetamaskTransactionDetailsPopup()`

Close currently open transaction details popup.

```ts
closeMetamaskTransactionDetailsPopup(): Chainable<Subject>;
```

#### `cy.allowMetamaskToAddNetwork()`

Allow site to add new network in metamask.
Expand Down
3 changes: 3 additions & 0 deletions pages/metamask/main-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ const tabs = {
const transactionList = '.transaction-list__transactions';
const pendingTransactionsList = `${transactionList} .transaction-list__pending-transactions`;
const completedTransactionsList = `${transactionList} .transaction-list__completed-transactions`;
const completedTransaction = txIndex =>
`${completedTransactionsList} > div:nth-child(${txIndex + 1})`;
const activityTab = {
transactionList,
pendingTransactionsList,
completedTransactionsList,
completedTransaction,
unconfirmedTransaction: `${pendingTransactionsList} .transaction-list-item--unconfirmed`,
confirmedTransaction: `${completedTransactionsList} .transaction-list-item`,
};
Expand Down
4 changes: 4 additions & 0 deletions plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,11 @@ module.exports = (on, config) => {
acceptMetamaskAccess: metamask.acceptAccess,
rejectMetamaskAccess: metamask.rejectAccess,
confirmMetamaskTransaction: metamask.confirmTransaction,
confirmMetamaskTransactionAndWaitForMining:
metamask.confirmTransactionAndWaitForMining,
rejectMetamaskTransaction: metamask.rejectTransaction,
openMetamaskTransactionDetails: metamask.openTransactionDetails,
closeMetamaskTransactionDetailsPopup: metamask.closeTransactionDetailsPopup,
allowMetamaskToAddNetwork: async ({ waitForEvent }) =>
await metamask.allowToAddNetwork({ waitForEvent }),
rejectMetamaskToAddNetwork: metamask.rejectToAddNetwork,
Expand Down
15 changes: 15 additions & 0 deletions support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,25 @@ Cypress.Commands.add('confirmMetamaskTransaction', gasConfig => {
return cy.task('confirmMetamaskTransaction', gasConfig);
});

Cypress.Commands.add(
'confirmMetamaskTransactionAndWaitForMining',
gasConfig => {
return cy.task('confirmMetamaskTransactionAndWaitForMining', gasConfig);
},
);

Cypress.Commands.add('rejectMetamaskTransaction', () => {
return cy.task('rejectMetamaskTransaction');
});

Cypress.Commands.add('openMetamaskTransactionDetails', txIndex => {
return cy.task('openMetamaskTransactionDetails', txIndex);
});

Cypress.Commands.add('closeMetamaskTransactionDetailsPopup', () => {
return cy.task('closeMetamaskTransactionDetailsPopup');
});

Cypress.Commands.add('rejectMetamaskPermisionToApproveAll', () => {
return cy.task('rejectMetamaskPermisionToApproveAll');
});
Expand Down
37 changes: 37 additions & 0 deletions support/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,12 +334,49 @@ declare namespace Cypress {
| 'aggressive'
| 'site',
): Chainable<Subject>;
/**
* Confirm metamask transaction (auto-detects eip-1559 and legacy transactions) and wait for ALL pending transactions to be mined
* @example
* cy.confirmMetamaskTransactionAndWaitForMining()
* cy.confirmMetamaskTransactionAndWaitForMining({ gasLimit: 1000000, baseFee: 20, priorityFee: 20 }) // eip-1559
* cy.confirmMetamaskTransactionAndWaitForMining({ gasLimit: 1000000, gasPrice: 20 }) // legacy
* cy.confirmMetamaskTransactionAndWaitForMining('aggressive') // eip-1559 only! => available options: 'low', 'market', 'aggressive', 'site' (site is usually by default)
*/
confirmMetamaskTransactionAndWaitForMining(
gasConfig?:
| {
gasLimit?: number;
baseFee?: number;
priorityFee?: number;
}
| {
gasLimit?: number;
gasPrice?: number;
}
| 'low'
| 'market'
| 'aggressive'
| 'site',
): Chainable<Subject>;
/**
* Reject metamask transaction
* @example
* cy.rejectMetamaskTransaction()
*/
rejectMetamaskTransaction(): Chainable<boolean>;
/**
* Open metamask transaction details based on the index of the transaction in the list on the activity tab
* @example
* cy.openMetamaskTransactionDetails(0)
* cy.openMetamaskTransactionDetails(1)
*/
openMetamaskTransactionDetails(txIndex: number): Chainable<Subject>;
/**
* Close metamask transaction details popup
* @example
* cy.closeMetamaskTransactionDetailsPopup()
*/
closeMetamaskTransactionDetailsPopup(): Chainable<boolean>;
/**
* Allow site to add new network in metamask
* @example
Expand Down
61 changes: 61 additions & 0 deletions tests/e2e/specs/metamask-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,60 @@ describe('Metamask', () => {
expect(txData.confirmed).to.be.true;
});
});
it(`confirmMetamaskTransactionAndWaitForMining should confirm legacy transaction and wait for it to be mined`, () => {
cy.get('#sendButton').click();
cy.confirmMetamaskTransactionAndWaitForMining().then(txData => {
expect(txData.recipientPublicAddress).to.be.not.empty;
expect(txData.networkName).to.be.not.empty;
expect(txData.customNonce).to.be.not.empty;
expect(txData.confirmed).to.be.true;
});
});
it(`confirmMetamaskTransactionAndWaitForMining should confirm eip-1559 transaction and wait for it to be mined`, () => {
cy.get('#sendEIP1559Button').click();
cy.confirmMetamaskTransactionAndWaitForMining().then(txData => {
expect(txData.recipientPublicAddress).to.be.not.empty;
expect(txData.networkName).to.be.not.empty;
expect(txData.customNonce).to.be.not.empty;
expect(txData.confirmed).to.be.true;
});
});
it(`chaining confirmMetamaskTransactionAndWaitForMining should work as expected`, () => {
cy.get('#sendEIP1559Button').click();
cy.confirmMetamaskTransactionAndWaitForMining().then(txData => {
expect(txData.confirmed).to.be.true;
});
cy.get('#sendEIP1559Button').click();
cy.confirmMetamaskTransactionAndWaitForMining().then(txData => {
expect(txData.confirmed).to.be.true;
});
cy.get('#sendEIP1559Button').click();
cy.confirmMetamaskTransactionAndWaitForMining().then(txData => {
expect(txData.confirmed).to.be.true;
});
cy.get('#sendEIP1559Button').click();
cy.confirmMetamaskTransactionAndWaitForMining().then(txData => {
expect(txData.confirmed).to.be.true;
});
});
it(`openMetamaskTransactionDetails should open transaction details popup`, () => {
// Cannot be tested further with Cypress 😔
cy.openMetamaskTransactionDetails(0).then(
opened => expect(opened).to.be.true,
);
});
it(`closeMetamaskTransactionDetailsPopup should close transaction details popup`, () => {
cy.closeMetamaskTransactionDetailsPopup().then(
closed => expect(closed).to.be.true,
);
});
it(`openMetamaskTransactionDetails should click "View more" button enough times to open correct transaction details popup`, () => {
// Cannot be tested further with Cypress 😔
cy.openMetamaskTransactionDetails(14);
cy.closeMetamaskTransactionDetailsPopup().then(
closed => expect(closed).to.be.true,
);
});
it(`confirmMetamaskTransaction should confirm transaction for token creation (contract deployment) and check tx data`, () => {
cy.get('#createToken').click();
cy.confirmMetamaskTransaction().then(txData => {
Expand All @@ -402,6 +456,13 @@ describe('Metamask', () => {
.invoke('text')
.then(text => cy.log('Token hash: ' + text));
});
it(`openMetamaskTransactionDetails should open correct transaction details popup when there is a pending tx`, () => {
// Cannot be tested further with Cypress 😔
cy.openMetamaskTransactionDetails(0);
cy.closeMetamaskTransactionDetailsPopup().then(
closed => expect(closed).to.be.true,
);
});
it(`rejectMetamaskAddToken should cancel importing a token`, () => {
cy.get('#watchAsset').click();
cy.rejectMetamaskAddToken().then(rejected => {
Expand Down

0 comments on commit 618473c

Please sign in to comment.