Skip to content

feat: adds a new fixture to disable STX #17461

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

Merged
merged 18 commits into from
Jul 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions e2e/fixtures/fixture-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,17 @@ class FixtureBuilder {
return this.ensureSolanaModalSuppressed();
}

/**
* Disables smart transactions
* @returns FixtureBuilder
*/
withDisabledSmartTransactions() {
merge(this.fixture.state.engine.backgroundState.PreferencesController, {
smartTransactionsOptInStatus: false,
});
return this;
}

withPreferencesController(data) {
merge(
this.fixture.state.engine.backgroundState.PreferencesController,
Expand Down
11 changes: 11 additions & 0 deletions e2e/framework/fixtures/FixtureBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,17 @@ class FixtureBuilder {
return this.ensureSolanaModalSuppressed();
}

/**
* Disables smart transactions
* @returns FixtureBuilder
*/
withDisabledSmartTransactions() {
merge(this.fixture.state.engine.backgroundState.PreferencesController, {
smartTransactionsOptInStatus: false,
});
return this;
}

withPreferencesController(data: Record<string, unknown>) {
merge(
this.fixture.state.engine.backgroundState.PreferencesController,
Expand Down
32 changes: 30 additions & 2 deletions e2e/framework/fixtures/FixtureHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,20 +344,42 @@ export async function withFixtures(
},
],
testSpecificMock,
mockServerInstance,
launchArgs,
languageAndLocale,
permissions = {},
endTestfn,
} = options;

if (mockServerInstance && testSpecificMock) {
throw new Error(
'Cannot use both mockServerInstance and testSpecificMock at the same time. Please use only one.',
);
}

// Prepare android devices for testing to avoid having this in all tests
await TestHelpers.reverseServerPort();

// Handle mock server
let mockServer;
let mockServerPort = DEFAULT_MOCKSERVER_PORT;
if (testSpecificMock) {

if (mockServerInstance && !testSpecificMock) {
mockServer = mockServerInstance;
mockServerPort = mockServer.port;
logger.debug(
`Mock server started from mockServerInstance on port ${mockServerPort}`,
);
const endpoints = await mockServer.getMockedEndpoints();
logger.debug(`Mocked endpoints: ${endpoints.length}`);
}

if (testSpecificMock && !mockServerInstance) {
mockServerPort = getMockServerPort();
mockServer = await startMockServer(testSpecificMock, mockServerPort);
logger.debug(
`Mock server started from testSpecificMock on port ${mockServerPort}`,
);
}

// Handle local nodes
Expand Down Expand Up @@ -421,6 +443,12 @@ export async function withFixtures(
logger.error('Error in withFixtures:', error);
throw error;
} finally {
if (endTestfn) {
// Pass the mockServer to the endTestfn if it exists as we may want
// to capture events before cleanup
await endTestfn({ mockServer });
}

// Clean up all local nodes
if (localNodes && localNodes.length > 0) {
await handleLocalNodeCleanup(localNodes);
Expand All @@ -430,7 +458,7 @@ export async function withFixtures(
await handleDappCleanup(dapps, dappServer);
}

if (testSpecificMock) {
if (mockServer) {
await stopMockServer(mockServer);
}

Expand Down
2 changes: 2 additions & 0 deletions e2e/framework/fixtures/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ describe('My Test Suite', () => {
| `launcArgs` | `LaunchArgs` | `false` | `-` | Allows sending arbitrary launchArgs such as the fixtureServerPort |
| `languageAndLocale` | `LanguageAndLocale` | `false` | - | Set the device Language and Locale of the device |
| `permissions` | `object` | `false` | - | Allows setting specific device permissions |
| `mockServerInstance` | `Mockttp` | `false` | - | Allows providing a mock server instance instead of having one created automatically. Should not be used together with `testSpecificMock` |
| `endTestfn` | `fn()` | `false` | - | Allows providing a function that is executed at the end of the test before the cleanup |

## Migration from Legacy Options

Expand Down
5 changes: 5 additions & 0 deletions e2e/framework/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ export interface MockApiEndpoint {
* @param {Partial<LaunchArgs>} [launchArgs] - The launch arguments to use for the test.
* @param {LanguageAndLocale} [languageAndLocale] - The language and locale to use for the test.
* @param {Record<string, unknown>} [permissions] - The permissions to set for the device.
* @param {Mockttp} [mockServerInstance] - The mock server instance to use for the test. Useful when a custom setup of the mock server is needed.
* @param {() => Promise<void>} [endTestfn] - The function to execute after the test is finished.
*/
export interface WithFixturesOptions {
fixture: FixtureBuilder;
Expand All @@ -182,4 +184,7 @@ export interface WithFixturesOptions {
launchArgs?: Partial<LaunchArgs>;
languageAndLocale?: LanguageAndLocale;
permissions?: Record<string, unknown>;
mockServerInstance?: Mockttp;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
endTestfn?: (...args: any[]) => Promise<void>;
}
29 changes: 17 additions & 12 deletions e2e/pages/Bridge/QuoteView.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Matchers from '../../utils/Matchers';
import Gestures from '../../utils/Gestures';
import Matchers from '../../framework/Matchers';
import Gestures from '../../framework/Gestures';
import {
QuoteViewSelectorIDs,
QuoteViewSelectorText,
Expand Down Expand Up @@ -48,7 +48,7 @@ class QuoteView {
async enterAmount(amount: string): Promise<void> {
for (const digit of amount) {
const button = Matchers.getElementByText(digit);
await Gestures.waitAndTap(button, { delayBeforeTap: 500 });
await Gestures.waitAndTap(button, { delay: 500 });
}
}

Expand All @@ -57,32 +57,35 @@ class QuoteView {
}

async tapBridgeTo(): Promise<void> {
await Gestures.waitAndTap(this.bridgeTo, { delayBeforeTap: 1000 });
await Gestures.waitAndTap(this.bridgeTo, { delay: 1000 });
}

async tapToken(chainId: string, symbol: string): Promise<void> {
await Gestures.waitAndTap(this.token(chainId, symbol), {
delayBeforeTap: 1000,
});
await Gestures.waitAndTap(
this.token(chainId, symbol) as unknown as DetoxElement,
{
delay: 1000,
},
);
}

async tapSourceToken(): Promise<void> {
const token = Matchers.getElementByText('ETH');
await Gestures.waitAndTap(token, { delayBeforeTap: 1000 });
await Gestures.waitAndTap(token, { delay: 1000 });
}

async tapDestToken(): Promise<void> {
const token = Matchers.getElementByText('USDC');
await Gestures.waitAndTap(token, { delayBeforeTap: 1000 });
await Gestures.waitAndTap(token, { delay: 1000 });
}

async tapSwapTo(): Promise<void> {
await Gestures.waitAndTap(this.swapTo, { delayBeforeTap: 1000 });
await Gestures.waitAndTap(this.swapTo, { delay: 1000 });
}

async selectNetwork(network: string): Promise<void> {
const networkElement = Matchers.getElementByText(network);
await Gestures.waitAndTap(networkElement, { delayBeforeTap: 1000 });
await Gestures.waitAndTap(networkElement, { delay: 1000 });
}

async typeSearchToken(symbol: string): Promise<void> {
Expand All @@ -94,7 +97,9 @@ class QuoteView {
}

async tapConfirmSwap(): Promise<void> {
await Gestures.waitAndTap(this.confirmSwap);
await Gestures.waitAndTap(this.confirmSwap, {
delay: 1300,
});
}

async tapOnCancelButton() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,97 +2,109 @@ import {
ActivitiesViewSelectorsIDs,
ActivitiesViewSelectorsText,
} from '../../selectors/Transactions/ActivitiesView.selectors';
import Matchers from '../../utils/Matchers';
import Gestures from '../../utils/Gestures';
import Matchers from '../../framework/Matchers';
import Gestures from '../../framework/Gestures';

class ActivitiesView {
get title() {
get title(): DetoxElement {
return Matchers.getElementByText(ActivitiesViewSelectorsText.TITLE);
}

get container() {
get container(): DetoxElement {
return Matchers.getElementByID(ActivitiesViewSelectorsIDs.CONTAINER);
}

get confirmedLabel() {
get confirmedLabel(): DetoxElement {
return Matchers.getElementByText(ActivitiesViewSelectorsText.CONFIRM_TEXT);
}

get stakeDepositedLabel() {
get stakeDepositedLabel(): DetoxElement {
return Matchers.getElementByText(ActivitiesViewSelectorsText.STAKE_DEPOSIT);
}

get stakeMoreDepositedLabel() {
get stakeMoreDepositedLabel(): DetoxElement {
return Matchers.getElementByText(
ActivitiesViewSelectorsText.STAKE_DEPOSIT,
0,
);
}

get unstakeLabel() {
get unstakeLabel(): DetoxElement {
return Matchers.getElementByText(ActivitiesViewSelectorsText.UNSTAKE);
}

get stackingClaimLabel() {
get stackingClaimLabel(): DetoxElement {
return Matchers.getElementByText(ActivitiesViewSelectorsText.STAKING_CLAIM);
}

transactionStatus(row) {
transactionStatus(row: number): DetoxElement {
return Matchers.getElementByID(`transaction-status-${row}`);
}

transactionItem(row) {
transactionItem(row: number): DetoxElement {
return Matchers.getElementByID(`transaction-item-${row}`);
}

generateSwapActivityLabel(sourceToken, destinationToken) {
generateSwapActivityLabel(
sourceToken: string,
destinationToken: string,
): string {
let title = ActivitiesViewSelectorsText.SWAP;
title = title.replace('{{sourceToken}}', sourceToken);
title = title.replace('{{destinationToken}}', destinationToken);
return title;
}

generateBridgeActivityLabel(destNetwork) {
generateBridgeActivityLabel(destNetwork: string): string {
let title = ActivitiesViewSelectorsText.BRIDGE;
title = title.replace('{{chainName}}', destNetwork);
return title;
}

generateApprovedTokenActivityLabel(sourceToken) {
generateApprovedTokenActivityLabel(sourceToken: string): string {
let title = ActivitiesViewSelectorsText.APPROVE;
title = title.replace('{{sourceToken}}', sourceToken);
title = title.replace('{{upTo}}', '.*');
return new RegExp(`^${title}`);
return `^${title}`;
}

swapActivityTitle(sourceToken, destinationToken) {
swapActivityTitle(
sourceToken: string,
destinationToken: string,
): DetoxElement {
return Matchers.getElementByText(
this.generateSwapActivityLabel(sourceToken, destinationToken),
);
}

bridgeActivityTitle(destNetwork) {
bridgeActivityTitle(destNetwork: string): DetoxElement {
return Matchers.getElementByText(
this.generateBridgeActivityLabel(destNetwork),
);
}
tokenApprovalActivity(sourceToken) {
tokenApprovalActivity(sourceToken: string): DetoxElement {
return Matchers.getElementByText(
this.generateApprovedTokenActivityLabel(sourceToken),
);
}

async tapOnSwapActivity(sourceToken, destinationToken) {
const element = this.swapActivityTitle(sourceToken, destinationToken);
await Gestures.waitAndTap(element);
async tapOnSwapActivity(
sourceToken: string,
destinationToken: string,
): Promise<void> {
const el = this.swapActivityTitle(sourceToken, destinationToken);
await Gestures.waitAndTap(el);
}
async tapConfirmedTransaction() {
async tapConfirmedTransaction(): Promise<void> {
await Gestures.waitAndTap(this.confirmedLabel);
}
async swipeDown() {
await Gestures.swipe(this.container, 'down', 'slow', 0.5);
async swipeDown(): Promise<void> {
await Gestures.swipe(this.container, 'down', {
speed: 'slow',
percentage: 0.5,
});
}
async tapOnTransactionItem(row) {
async tapOnTransactionItem(row: number): Promise<void> {
await Gestures.waitAndTap(this.transactionItem(row));
}
}
Expand Down
2 changes: 1 addition & 1 deletion e2e/pages/wallet/TokenOverview.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
TokenOverviewSelectorsIDs,
TokenOverviewSelectorsText,
} from '../../selectors/wallet/TokenOverview.selectors';
import { WalletActionsBottomSheetSelectorsIDs } from '../../selectors/wallet/WalletActionsBottomSheet.selectors.js';
import { WalletActionsBottomSheetSelectorsIDs } from '../../selectors/wallet/WalletActionsBottomSheet.selectors';
import { WalletViewSelectorsIDs } from '../../selectors/wallet/WalletView.selectors';
import { CommonSelectorsIDs } from '../../selectors/Common.selectors';

Expand Down
Loading
Loading