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

test: E2E Mocking Setup For Detox Tests #11144

Merged
merged 32 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3456031
First mocking test final branch
Andepande Sep 10, 2024
d67511f
Added suggestedGasApi.mock.spec.js to core test suite
SamuelSalas Sep 11, 2024
b597ee2
Upddate timeout for waitAndTap
SamuelSalas Sep 11, 2024
ceff9de
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 11, 2024
322c948
Added logic to handle previous tapEstimatedGasLink functionality
SamuelSalas Sep 11, 2024
8c64453
Update waitAndTap timeout
SamuelSalas Sep 11, 2024
6bfe335
Tweak Gestures.waitAndTap
Andepande Sep 11, 2024
f83dbeb
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 11, 2024
c968860
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 11, 2024
c4a9386
Restore yarn.lock to support mockttp
SamuelSalas Sep 11, 2024
2972872
fix mockttp on yarn.lock
SamuelSalas Sep 11, 2024
f822a23
fix lint issue
SamuelSalas Sep 11, 2024
1f40222
Fix if statement
SamuelSalas Sep 11, 2024
327e4eb
Added logic to dismiss account modal for either ios or android
SamuelSalas Sep 11, 2024
2376f9f
Add wait for Account list modal to not be displayed
SamuelSalas Sep 12, 2024
c606995
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 12, 2024
0559292
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 12, 2024
d88e324
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 13, 2024
12c5acb
Resolve comments
SamuelSalas Sep 13, 2024
330c226
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 13, 2024
7bb39e8
Merge branch 'main' into test-first-mock-e2e-test
Andepande Sep 17, 2024
157c68e
Remove unnecessary comments and added variables
SamuelSalas Sep 17, 2024
d32cb52
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 17, 2024
8778b43
move mock server port to the mockUrlCollection.js file
SamuelSalas Sep 17, 2024
f2ddf88
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 17, 2024
3c39153
Remove the hardcoded pause
SamuelSalas Sep 17, 2024
b15e39d
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 17, 2024
bcd18fc
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 18, 2024
4545a94
Solve deduplicate in yarn.lock
SamuelSalas Sep 18, 2024
58b2b10
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 18, 2024
d1f42bc
Change mockServer.js file name. Move the urls to a json file. Update …
SamuelSalas Sep 18, 2024
bd79e42
Merge branch 'main' into test-first-mock-e2e-test
SamuelSalas Sep 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions e2e/mockserver/mockUrlCollection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const mockUrlCollection = {
SUGGESTED_GAS_API_MAINNET_URL: 'https://gas.api.cx.metamask.io/networks/1/suggestedGasFees',
DEFAULT_PORT: 8000,
};
41 changes: 41 additions & 0 deletions e2e/mockserver/mockserver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* eslint-disable no-console */
import { getLocal } from 'mockttp';
import { mockUrlCollection } from './mockUrlCollection';

const mockServer = getLocal();
const defaultMockPort = 8000;

export const startMockServer = async ({
NicolasMassart marked this conversation as resolved.
Show resolved Hide resolved
mockUrl,
responseCode = 500,
responseBody = {},
port = mockUrlCollection.DEFAULT_PORT,
}) => {
if (!mockUrl) throw new Error('The mockUrl parameter is required');

await mockServer.start(port);
console.log(`Mockttp server running at http://localhost:${port}`);

await mockServer
.forGet('/health-check')
.thenReply(200, 'Mock server is running');

await mockServer
.forGet('/proxy')
.withQuery({ url: mockUrl })
.thenReply(responseCode, JSON.stringify(responseBody));

await mockServer.forUnmatchedRequest().thenPassThrough({
beforeRequest: async ({ url, method }) => {
console.log(`Forwarding request to: ${method} ${url}`);
return { url: new URL(url).searchParams.get('url') || url };
},
});

return mockServer;
};

export const stopMockServer = async () => {
await mockServer.stop();
console.log('Mockttp server stopped');
};
11 changes: 8 additions & 3 deletions e2e/pages/Send/TransactionConfirmView.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ class TransactionConfirmationView {
return Matchers.getElementByText(EditGasViewSelectorsText.ADVANCE_OPTIONS);
}

get editPriorityModal() {
return Matchers.getElementByText(
TransactionConfirmViewSelectorsText.EDIT_PRIORITY_MODAL,
);
}

async tapConfirmButton() {
await Gestures.waitAndTap(this.confirmButton);
}
Expand All @@ -79,10 +85,9 @@ class TransactionConfirmationView {
await Gestures.waitAndTap(this.cancelButton);
}

async tapEstimatedGasLink() {
async tapEstimatedGasLink(index = 0) {
await Gestures.swipe(this.transactionAmount, 'up', 'fast');

await Gestures.waitAndTap(this.estimatedGasLink);
await Gestures.TapAtIndex(this.estimatedGasLink, index);
}

async tapLowPriorityGasOption() {
Expand Down
1 change: 1 addition & 0 deletions e2e/selectors/TransactionConfirmView.selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const TransactionConfirmViewSelectorsIDs = {

export const TransactionConfirmViewSelectorsText = {
CANCEL_BUTTON: enContent.transaction.cancel,
EDIT_PRIORITY_MODAL: enContent.edit_gas_fee_eip1559.edit_priority,
};
89 changes: 89 additions & 0 deletions e2e/specs/wallet/suggestedGasApi.mock.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
'use strict';
import { loginToApp } from '../../viewHelper.js';
import { SmokeCore } from '../../tags.js';
import TabBarComponent from '../../pages/TabBarComponent.js';
import WalletActionsModal from '../../pages/modals/WalletActionsModal.js';
import SendView from '../../pages/Send/SendView.js';
import AmountView from '../../pages/Send/AmountView.js';
import TransactionConfirmView from '../../pages/Send/TransactionConfirmView.js';
import { startMockServer, stopMockServer } from '../../mockserver/mockserver.js';
import WalletView from '../../pages/wallet/WalletView.js';
import Assertions from '../../utils/Assertions.js';
import AccountListView from '../../pages/AccountListView.js';
import AddAccountModal from '../../pages/modals/AddAccountModal.js';
import ImportAccountView from '../../pages/ImportAccountView.js';
import Accounts from '../../../wdio/helpers/Accounts.js';
import { withFixtures } from '../../fixtures/fixture-helper.js';
import FixtureBuilder from '../../fixtures/fixture-builder.js';
import TestHelpers from '../../helpers.js';
import { mockUrlCollection } from '../../mockserver/mockUrlCollection.js';

describe(SmokeCore('Mock suggestedGasApi fallback to legacy gas endpoint when EIP1559 endpoint is down'), () => {
let mockServer;
beforeAll(async () => {
jest.setTimeout(150000);
await TestHelpers.reverseServerPort();

mockServer = await startMockServer({ // Configure mock server
mockUrl: mockUrlCollection.SUGGESTED_GAS_API_MAINNET_URL,
responseCode: 500,
responseBody: { error: 'Internal server error' },
});
});

// Because we stop the server within the test, a try catch block here would stop the server if the test fails midway
afterAll(async () => {
if (mockServer) {
try {
await stopMockServer(); // Stop the mock server if it's running
} catch (error) {
// eslint-disable-next-line no-console
console.log('Mock server already stopped or encountered an error:', error);
}
}
});

const RECIPIENT = '0x1FDb169Ef12954F20A15852980e1F0C122BfC1D6';
const AMOUNT = '0.0003';
const validPrivateKey = Accounts.getAccountPrivateKey();

it('should fallback to legacy gas endpoint & legacy modal when EIP1559 endpoint is down', async () => {
await withFixtures(
{
fixture: new FixtureBuilder().build(),
restartDevice: true,
},
async () => {
await loginToApp();
await WalletView.tapIdenticon();
await Assertions.checkIfVisible(AccountListView.accountList);
await AccountListView.tapAddAccountButton();
await AddAccountModal.tapImportAccount();
await ImportAccountView.isVisible();
await ImportAccountView.enterPrivateKey(validPrivateKey.keys);
await ImportAccountView.isImportSuccessSreenVisible();
await ImportAccountView.tapCloseButtonOnImportSuccess();
if (device.getPlatform() === 'ios') {
await AccountListView.swipeToDismissAccountsModal();
await Assertions.checkIfNotVisible(AccountListView.title);
} else {
await WalletView.tapIdenticon();
}
await TabBarComponent.tapActions();
await WalletActionsModal.tapSendButton();
await SendView.inputAddress(RECIPIENT);
await SendView.tapNextButton();
await AmountView.typeInTransactionAmount(AMOUNT);
await AmountView.tapNextButton();
await TransactionConfirmView.tapEstimatedGasLink(1);
await Assertions.checkIfVisible(
TransactionConfirmView.editPriorityModal,
);
await stopMockServer(); //stop mock server to reinstate suggested gas api service
await Assertions.checkIfVisible(
TransactionConfirmView.editPriorityFeeSheetContainer, 30000
);
},
);
});
});
13 changes: 13 additions & 0 deletions e2e/utils/Gestures.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ class Gestures {
await element.tap();
}

/**
* Wait for an element at a specific index to be visible and then tap it.
*
* @param {Promise<Detox.IndexableNativeElement>} elementID - ID of the element to tap
* @param {number} index - Index of the element to tap
* @param {number} timeout - Timeout for waiting (default: 15000ms)
*/
static async TapAtIndex(elementID, index, timeout = 15000) {
const element = (await elementID).atIndex(index);
await waitFor(element).toBeVisible().withTimeout(timeout);
await element.tap();
}

/**
* Wait for an element to be visible and then tap it.
*
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@
"lodash": "^4.17.21",
"lottie-ios": "3.4.1",
"lottie-react-native": "5.1.5",
"mockttp": "^3.15.2",
"multihashes": "0.4.14",
"number-to-bn": "1.7.0",
"obs-store": "4.0.3",
Expand Down
25 changes: 25 additions & 0 deletions shim.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/* eslint-disable import/no-nodejs-modules */
/* global Platform */
import { decode, encode } from 'base-64';
import {
FIXTURE_SERVER_PORT,
isTest,
testConfig,
} from './app/util/test/utils.js';
import { LaunchArguments } from 'react-native-launch-arguments';
import { mockUrlCollection } from './e2e/mockserver/mockUrlCollection';

// In a testing environment, assign the fixtureServerPort to use a deterministic port
if (isTest) {
Expand Down Expand Up @@ -56,3 +58,26 @@ if (typeof localStorage !== 'undefined') {
// If using the crypto shim, uncomment the following line to ensure
// crypto is loaded first, so it can populate global.crypto
// require('crypto')

if (isTest) {
(async () => {
const { fetch: originalFetch } = global;
const MOCKTTP_URL = `http://${
Platform.OS === 'ios' ? 'localhost' : '10.0.2.2'
}:${mockUrlCollection.DEFAULT_PORT}`;

const isMockServerAvailable = await originalFetch(
`${MOCKTTP_URL}/health-check`,
)
.then((res) => res.ok)
.catch(() => false);
// if mockserver is off we route to original destination
global.fetch = async (url, options) =>
NicolasMassart marked this conversation as resolved.
Show resolved Hide resolved
isMockServerAvailable
? originalFetch(
`${MOCKTTP_URL}/proxy?url=${encodeURIComponent(url)}`,
options,
).catch(() => originalFetch(url, options))
: originalFetch(url, options);
})();
}
Loading
Loading