Skip to content

Commit

Permalink
Revert "Revert "Brody/swap v2 e2e (#5915)" (#5987)" (#5988)
Browse files Browse the repository at this point in the history
* Revert "Revert "Brody/swap v2 e2e (#5915)" (#5987)"

This reverts commit fdcdd09.

* fix test

* Revert "fix test"

This reverts commit a7f5b1c.

* fix

* fix test

* typecast to fix lint

* matthew :D

* test this

* Revert "test this"

This reverts commit ab6b11d.

* fix lint

* fix user assets not working on swaps e2e

* .

* oop

* lint

* lel our @/references folder is fked

* fix some things

* fix user assets in testnet mode

* fix up e2e

* readd memo

* .

* revert change to swipeUntilVisible

* re add very long delay

* remove react memo

---------

Co-authored-by: Matthew Wall <[email protected]>
  • Loading branch information
BrodyHughes and walmat authored Aug 25, 2024
1 parent dd030ca commit 4cdc783
Show file tree
Hide file tree
Showing 29 changed files with 501 additions and 106 deletions.
14 changes: 8 additions & 6 deletions e2e/3_homeScreen.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import {
checkIfExists,
checkIfExistsByText,
swipe,
waitAndTap,
afterAllcleanApp,
tap,
delayTime,
} from './helpers';

const RAINBOW_TEST_WALLET = 'rainbowtestwallet.eth';
Expand Down Expand Up @@ -41,19 +42,20 @@ describe('Home Screen', () => {
});

it('tapping "Swap" opens the swap screen', async () => {
await waitAndTap('swap-button');
await tap('swap-button');
await delayTime('long');
await checkIfExists('swap-screen');
await swipe('swap-screen', 'down', 'slow');
await swipe('swap-screen', 'down', 'fast');
});

it('tapping "Send" opens the send screen', async () => {
await waitAndTap('send-button');
await tap('send-button');
await checkIfVisible('send-asset-form-field');
await swipe('send-asset-form-field', 'down');
await swipe('send-asset-form-field', 'down', 'fast');
});

it('tapping "Copy" shows copy address toast', async () => {
await waitAndTap('receive-button');
await tap('receive-button');
await checkIfVisible('address-copied-toast');
});
});
144 changes: 144 additions & 0 deletions e2e/9_swaps.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* // Other tests to consider:
* - Flip assets
* - exchange button onPress
* - disable button states once https://github.com/rainbow-me/rainbow/pull/5785 gets merged
* - swap execution
* - token search (both from userAssets and output token list)
* - custom gas panel
* - flashbots
* - slippage
* - explainer sheets
* - switching wallets inside of swap screen
*/

import {
importWalletFlow,
sendETHtoTestWallet,
checkIfVisible,
beforeAllcleanApp,
afterAllcleanApp,
fetchElementAttributes,
tap,
tapByText,
delayTime,
swipeUntilVisible,
tapAndLongPressByText,
tapAndLongPress,
swipe,
} from './helpers';

import { expect } from '@jest/globals';
import { WALLET_VARS } from './testVariables';

describe('Swap Sheet Interaction Flow', () => {
beforeAll(async () => {
await beforeAllcleanApp({ hardhat: true });
});
afterAll(async () => {
await afterAllcleanApp({ hardhat: true });
});

it('Import a wallet and go to welcome', async () => {
await importWalletFlow(WALLET_VARS.EMPTY_WALLET.PK);
});

it('Should send ETH to test wallet', async () => {
// send 20 eth
await sendETHtoTestWallet();
});

it('Should show Hardhat Toast after pressing Connect To Hardhat', async () => {
await tap('dev-button-hardhat');
await checkIfVisible('testnet-toast-Hardhat');

// doesn't work atm
// validate it has the expected funds of 20 eth
// const attributes = await fetchElementAttributes('fast-coin-info');
// expect(attributes.label).toContain('Ethereum');
// expect(attributes.label).toContain('20');
});

it('Should open swap screen with 50% inputAmount for inputAsset', async () => {
await device.disableSynchronization();
await tap('swap-button');
await delayTime('long');

await swipeUntilVisible('token-to-buy-dai-1', 'token-to-buy-list', 'up', 100);
await swipe('token-to-buy-list', 'up', 'slow', 0.1);

await tap('token-to-buy-dai-1');
await delayTime('medium');
const swapInput = await fetchElementAttributes('swap-asset-input');

expect(swapInput.label).toContain('ETH');
expect(swapInput.label).toContain('10');
});

it('Should be able to go to review and execute a swap', async () => {
await tap('swap-bottom-action-button');
const inputAssetActionButton = await fetchElementAttributes('swap-input-asset-action-button');
const outputAssetActionButton = await fetchElementAttributes('swap-output-asset-action-button');
const holdToSwapButton = await fetchElementAttributes('swap-bottom-action-button');

expect(inputAssetActionButton.label).toBe('ETH 􀆏');
expect(outputAssetActionButton.label).toBe('DAI 􀆏');
expect(holdToSwapButton.label).toBe('􀎽 Hold to Swap');

await tapAndLongPress('swap-bottom-action-button', 1500);

// TODO: This doesn't work so need to figure this out eventually...
// await checkIfVisible('profile-screen');
});

it.skip('Should be able to verify swap is happening', async () => {
// await delayTime('very-long');
// const activityListElements = await fetchElementAttributes('wallet-activity-list');
// expect(activityListElements.label).toContain('ETH');
// expect(activityListElements.label).toContain('DAI');
// await tapByText('Swapping');
// await delayTime('long');
// const transactionSheet = await checkIfVisible('transaction-details-sheet');
// expect(transactionSheet).toBeTruthy();
});

it.skip('Should open swap screen from ProfileActionRowButton with largest user asset', async () => {
/**
* tap swap button
* wait for Swap header to be visible
* grab highest user asset balance from userAssetsStore
* expect inputAsset.uniqueId === highest user asset uniqueId
*/
});

it.skip('Should open swap screen from asset chart with that asset selected', async () => {
/**
* tap any user asset (store const uniqueId here)
* wait for Swap header to be visible
* expect inputAsset.uniqueId === const uniqueId ^^
*/
});

it.skip('Should open swap screen from dapp browser control panel with largest user asset', async () => {
/**
* tap swap button
* wait for Swap header to be visible
* grab highest user asset balance from userAssetsStore
* expect inputAsset.uniqueId === highest user asset uniqueId
*/
});

it.skip('Should not be able to type in output amount if cross-chain quote', async () => {
/**
* tap swap button
* wait for Swap header to be visible
* select different chain in output list chain selector
* select any asset in output token list
* focus output amount
* attempt to type any number in the SwapNumberPad
* attempt to remove a character as well
*
* ^^ expect both of those to not change the outputAmount
*/
});
});
34 changes: 26 additions & 8 deletions e2e/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { JsonRpcProvider } from '@ethersproject/providers';
import { Wallet } from '@ethersproject/wallet';
import { expect, device, element, by, waitFor } from 'detox';
import { parseEther } from '@ethersproject/units';
import { IosElementAttributes, AndroidElementAttributes } from 'detox/detox';

const TESTING_WALLET = '0x3Cb462CDC5F809aeD0558FBEe151eD5dC3D3f608';
const TESTING_WALLET = '0x3637f053D542E6D00Eee42D656dD7C59Fa33a62F';

const DEFAULT_TIMEOUT = 20_000;
const android = device.getPlatform() === 'android';
Expand Down Expand Up @@ -70,6 +71,16 @@ export async function tap(elementId: string | RegExp) {
}
}

interface CustomElementAttributes {
elements: Array<IosElementAttributes | AndroidElementAttributes>;
}

type ElementAttributes = IosElementAttributes & AndroidElementAttributes & CustomElementAttributes;

export const fetchElementAttributes = async (testId: string): Promise<ElementAttributes> => {
return (await element(by.id(testId)).getAttributes()) as ElementAttributes;
};

export async function waitAndTap(elementId: string | RegExp, timeout = DEFAULT_TIMEOUT) {
await delayTime('medium');
try {
Expand Down Expand Up @@ -188,17 +199,17 @@ export async function clearField(elementId: string | RegExp) {
}
}

export async function tapAndLongPress(elementId: string | RegExp) {
export async function tapAndLongPress(elementId: string | RegExp, duration?: number) {
try {
return await element(by.id(elementId)).longPress();
return await element(by.id(elementId)).longPress(duration);
} catch (error) {
throw new Error(`Error long-pressing element by id "${elementId}": ${error}`);
}
}

export async function tapAndLongPressByText(text: string | RegExp) {
export async function tapAndLongPressByText(text: string | RegExp, duration?: number) {
try {
return await element(by.text(text)).longPress();
return await element(by.text(text)).longPress(duration);
} catch (error) {
throw new Error(`Error long-pressing element by text "${text}": ${error}`);
}
Expand Down Expand Up @@ -263,15 +274,22 @@ export async function scrollTo(scrollviewId: string | RegExp, edge: Direction) {
}
}

export async function swipeUntilVisible(elementId: string | RegExp, scrollViewId: string, direction: Direction, pctVisible = 75) {
export async function swipeUntilVisible(
elementId: string | RegExp,
scrollViewId: string,
direction: Direction,
percentageVisible?: number
) {
let stop = false;

while (!stop) {
try {
await waitFor(element(by.id(elementId)))
.toBeVisible(pctVisible)
.toBeVisible(percentageVisible)
.withTimeout(500);

stop = true;
} catch {
} catch (e) {
await swipe(scrollViewId, direction, 'slow', 0.2);
}
}
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@
"nuke": "./scripts/nuke.sh",
"detox:android": "detox build -c android.emu.debug && detox test -c android.emu.debug --loglevel verbose",
"detox:android:release": "detox build -c android.emu.release && detox test -c android.emu.release",
"detox:ios:tests": "detox test -c ios.sim.debug --maxWorkers 3 -- --bail 1",
"detox:ios": "detox build -c ios.sim.debug | xcpretty --color && yarn detox:ios:tests",
"detox:ios:release": "detox build -c ios.sim.release && detox test -c ios.sim.release --maxWorkers 3 -- --bail 1",
"detox:ios:build": "detox build -c ios.sim.debug | xcpretty --color ",
"detox:ios:tests": "detox test -c ios.sim.debug --maxWorkers 2 -- --bail 1",
"detox:ios": "yarn detox:ios:build && yarn detox:ios:tests",
"detox:ios:release": "detox build -c ios.sim.release && detox test -c ios.sim.release --maxWorkers 2 -- --bail 1",
"ds:install": "cd src/design-system/docs && yarn install",
"ds": "cd src/design-system/docs && yarn dev",
"fast": "yarn install && yarn setup && yarn install-pods-fast",
Expand Down
6 changes: 4 additions & 2 deletions src/__swaps__/screens/Swap/components/CoinRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ interface InputCoinRowProps {
onPress: (asset: ParsedSearchAsset | null) => void;
output?: false | undefined;
uniqueId: string;
testID?: string;
}

type PartialAsset = Pick<SearchAsset, 'address' | 'chainId' | 'colors' | 'icon_url' | 'mainnetAddress' | 'name' | 'symbol' | 'uniqueId'>;
Expand All @@ -62,11 +63,12 @@ interface OutputCoinRowProps extends PartialAsset {
output: true;
nativePriceChange?: string;
isTrending?: boolean;
testID?: string;
}

type CoinRowProps = InputCoinRowProps | OutputCoinRowProps;

export function CoinRow({ isFavorite, onPress, output, uniqueId, ...assetProps }: CoinRowProps) {
export function CoinRow({ isFavorite, onPress, output, uniqueId, testID, ...assetProps }: CoinRowProps) {
const inputAsset = userAssetsStore(state => (output ? undefined : state.getUserAsset(uniqueId)));
const outputAsset = output ? (assetProps as PartialAsset) : undefined;

Expand Down Expand Up @@ -116,7 +118,7 @@ export function CoinRow({ isFavorite, onPress, output, uniqueId, ...assetProps }
if (!address || !chainId) return null;

return (
<Box style={{ height: COIN_ROW_WITH_PADDING_HEIGHT, width: '100%' }}>
<Box testID={testID} style={{ height: COIN_ROW_WITH_PADDING_HEIGHT, width: '100%' }}>
<Columns alignVertical="center">
<Column>
<ButtonPressAnimation disallowInterruption onPress={onPressHandler} scaleTo={0.95}>
Expand Down
7 changes: 6 additions & 1 deletion src/__swaps__/screens/Swap/components/SwapActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function SwapButton({
disabled,
opacity,
children,
testID,
}: {
asset: DerivedValue<ExtendedAnimatedAssetWithColors | null>;
borderRadius?: number;
Expand All @@ -47,6 +48,7 @@ function SwapButton({
disabled?: DerivedValue<boolean | undefined>;
opacity?: DerivedValue<number | undefined>;
children?: React.ReactNode;
testID?: string;
}) {
const { isDarkMode } = useColorMode();
const fallbackColor = useForegroundColor('label');
Expand Down Expand Up @@ -110,6 +112,7 @@ function SwapButton({
return (
<Animated.View style={buttonWrapperStyles}>
<Box
testID={testID}
as={Animated.View}
paddingHorizontal={{ custom: small ? 14 : 20 - (outline ? 2 : 0) }}
paddingLeft={small && icon ? '10px' : undefined}
Expand Down Expand Up @@ -225,6 +228,7 @@ export const SwapActionButton = ({
scaleTo,
style,
disabled,
testID,
...props
}: {
asset: DerivedValue<ExtendedAnimatedAssetWithColors | null>;
Expand All @@ -248,6 +252,7 @@ export const SwapActionButton = ({
style?: ViewStyle;
disabled?: DerivedValue<boolean | undefined>;
opacity?: DerivedValue<number | undefined>;
testID?: string;
}) => {
const disabledWrapper = useAnimatedStyle(() => {
return {
Expand All @@ -268,7 +273,7 @@ export const SwapActionButton = ({
style={[hugContent && feedActionButtonStyles.buttonWrapper, style]}
>
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
<SwapButton {...props} disabled={disabled}>
<SwapButton {...props} disabled={disabled} testID={testID}>
{holdProgress && <HoldProgress holdProgress={holdProgress} />}
</SwapButton>
</GestureHandlerButton>
Expand Down
11 changes: 9 additions & 2 deletions src/__swaps__/screens/Swap/components/SwapBackground.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Canvas, Rect, LinearGradient, vec, Paint } from '@shopify/react-native-skia';
import React from 'react';
import { StyleSheet } from 'react-native';
import { StyleSheet, View } from 'react-native';
import { useDerivedValue, withTiming } from 'react-native-reanimated';
import { ScreenCornerRadius } from 'react-native-screen-corner-radius';
import { TIMING_CONFIGS } from '@/components/animations/animationConfigs';
import { useColorMode } from '@/design-system';
import { IS_ANDROID } from '@/env';
import { IS_ANDROID, IS_TEST } from '@/env';
import { useSwapContext } from '@/__swaps__/screens/Swap/providers/swap-provider';
import { getColorValueForThemeWorklet, getTintedBackgroundColor } from '@/__swaps__/utils/swaps';
import { DEVICE_HEIGHT, DEVICE_WIDTH } from '@/utils/deviceUtils';
Expand All @@ -18,12 +18,15 @@ export const SwapBackground = () => {
const { internalSelectedInputAsset, internalSelectedOutputAsset } = useSwapContext();

const animatedTopColor = useDerivedValue(() => {
if (IS_TEST) return getColorValueForThemeWorklet(DEFAULT_BACKGROUND_COLOR, isDarkMode, true);
return withTiming(
getColorValueForThemeWorklet(internalSelectedInputAsset.value?.tintedBackgroundColor || DEFAULT_BACKGROUND_COLOR, isDarkMode, true),
TIMING_CONFIGS.slowFadeConfig
);
});

const animatedBottomColor = useDerivedValue(() => {
if (IS_TEST) return getColorValueForThemeWorklet(DEFAULT_BACKGROUND_COLOR, isDarkMode, true);
return withTiming(
getColorValueForThemeWorklet(internalSelectedOutputAsset.value?.tintedBackgroundColor || DEFAULT_BACKGROUND_COLOR, isDarkMode, true),
TIMING_CONFIGS.slowFadeConfig
Expand All @@ -34,6 +37,10 @@ export const SwapBackground = () => {
return [animatedTopColor.value, animatedBottomColor.value];
});

if (IS_TEST) {
return <View style={[styles.background, { backgroundColor: animatedTopColor.value }]} />;
}

return (
<Canvas style={styles.background}>
<Rect height={DEVICE_HEIGHT + (IS_ANDROID ? 24 : 0)} width={DEVICE_WIDTH} x={0} y={0}>
Expand Down
Loading

0 comments on commit 4cdc783

Please sign in to comment.