Skip to content
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
6 changes: 6 additions & 0 deletions app.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ module.exports = {
],

'expo-apple-authentication',
[
'expo-screen-orientation',
{
initialOrientation: 'PORTRAIT',
},
],
],
android: {
package:
Expand Down
69 changes: 69 additions & 0 deletions app/__mocks__/expo-screen-orientation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// mock expo-screen-orientation for testing

export const lockAsync = jest.fn().mockResolvedValue(undefined);
export const unlockAsync = jest.fn().mockResolvedValue(undefined);
export const getOrientationAsync = jest.fn().mockResolvedValue(1); // Portrait
export const getOrientationLockAsync = jest.fn().mockResolvedValue(0);
export const getPlatformOrientationLockAsync = jest.fn().mockResolvedValue({});
export const supportsOrientationLockAsync = jest.fn().mockResolvedValue(true);

export const Orientation = {
UNKNOWN: 0,
PORTRAIT_UP: 1,
PORTRAIT_DOWN: 2,
LANDSCAPE_LEFT: 3,
LANDSCAPE_RIGHT: 4,
};

export const OrientationLock = {
DEFAULT: 0,
ALL: 1,
PORTRAIT: 2,
PORTRAIT_UP: 3,
PORTRAIT_DOWN: 4,
LANDSCAPE: 5,
LANDSCAPE_LEFT: 6,
LANDSCAPE_RIGHT: 7,
OTHER: 8,
UNKNOWN: 9,
};

export const SizeClassIOS = {
UNKNOWN: 0,
COMPACT: 1,
REGULAR: 2,
};

export const WebOrientationLock = {
PORTRAIT_PRIMARY: 'portrait-primary',
PORTRAIT_SECONDARY: 'portrait-secondary',
LANDSCAPE_PRIMARY: 'landscape-primary',
LANDSCAPE_SECONDARY: 'landscape-secondary',
PORTRAIT: 'portrait',
LANDSCAPE: 'landscape',
NATURAL: 'natural',
ANY: 'any',
UNKNOWN: 'unknown',
};

export const WebOrientation = {
PORTRAIT_PRIMARY: 0,
PORTRAIT_SECONDARY: 180,
LANDSCAPE_PRIMARY: 90,
LANDSCAPE_SECONDARY: -90,
};

// Default export for namespace imports
export default {
lockAsync,
unlockAsync,
getOrientationAsync,
getOrientationLockAsync,
getPlatformOrientationLockAsync,
supportsOrientationLockAsync,
Orientation,
OrientationLock,
SizeClassIOS,
WebOrientationLock,
WebOrientation,
};
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const createStyles = ({ theme }: { theme: Theme }) =>
chartSection: {
paddingTop: 0,
marginTop: 16,
position: 'relative',
},
tabsSection: {
paddingVertical: 8,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,25 @@ jest.mock('react-native/Libraries/Linking/Linking', () => ({
getInitialURL: jest.fn(() => Promise.resolve(null)),
}));

jest.mock('react-native-modal', () => {
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
const { View } = require('react-native');
return ({
isVisible,
children,
...props
}: {
isVisible: boolean;
children: React.ReactNode;
[key: string]: unknown;
}) =>
isVisible ? (
<View testID="modal-container" {...props}>
{children}
</View>
) : null;
});

// Mock @consensys/native-ramps-sdk to provide missing enum
jest.mock('@consensys/native-ramps-sdk', () => ({
...jest.requireActual('@consensys/native-ramps-sdk'),
Expand Down Expand Up @@ -59,6 +78,20 @@ jest.mock('../../selectors/chartPreferences', () => ({
selectPerpsChartPreferredCandlePeriod: jest.fn(() => '15m'),
}));

// Mock Logger
const mockLoggerError = jest.fn();
const mockLoggerLog = jest.fn();
const mockLoggerWarn = jest.fn();

jest.mock('../../../../../util/Logger', () => ({
__esModule: true,
default: {
error: (...args: unknown[]) => mockLoggerError(...args),
log: (...args: unknown[]) => mockLoggerLog(...args),
warn: (...args: unknown[]) => mockLoggerWarn(...args),
},
}));

// Create mock functions that can be modified during tests
const mockUsePerpsAccount = jest.fn();
const mockUsePerpsLiveAccount = jest.fn();
Expand Down Expand Up @@ -1428,8 +1461,7 @@ describe('PerpsMarketDetailsView', () => {
});

it('handles error when opening TradingView URL fails', async () => {
// Mock console.error to avoid test output pollution
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
mockLoggerError.mockClear();

// Mock Linking.openURL to reject
(Linking.openURL as jest.Mock).mockRejectedValueOnce(
Expand All @@ -1449,15 +1481,97 @@ describe('PerpsMarketDetailsView', () => {
const tradingViewLink = getByText('TradingView.');
fireEvent.press(tradingViewLink);

// Wait for the error to be logged
// Wait for the error to be logged using Logger.error
await waitFor(() => {
expect(consoleErrorSpy).toHaveBeenCalledWith(
'Failed to open Trading View URL:',
expect(mockLoggerError).toHaveBeenCalledWith(
expect.any(Error),
expect.objectContaining({
feature: 'perps',
message: 'Failed to open Trading View URL',
}),
);
});
});
});

consoleErrorSpy.mockRestore();
describe('Fullscreen chart functionality', () => {
it('opens fullscreen chart modal when fullscreen button is pressed', async () => {
const { getByTestId, queryByTestId } = renderWithProvider(
<PerpsConnectionProvider>
<PerpsMarketDetailsView />
</PerpsConnectionProvider>,
{
state: initialState,
},
);

// Verify close button is not initially visible (modal is closed)
expect(queryByTestId('perps-chart-fullscreen-close-button')).toBeNull();

// Press fullscreen button
const fullscreenButton = getByTestId(
'perps-market-header-fullscreen-button',
);
fireEvent.press(fullscreenButton);

// Verify modal is now visible by checking for close button
await waitFor(() => {
expect(getByTestId('perps-chart-fullscreen-close-button')).toBeTruthy();
});
});

it('closes fullscreen chart modal when close button is pressed', async () => {
const { getByTestId, queryByTestId } = renderWithProvider(
<PerpsConnectionProvider>
<PerpsMarketDetailsView />
</PerpsConnectionProvider>,
{
state: initialState,
},
);

// Open the modal first
const fullscreenButton = getByTestId(
'perps-market-header-fullscreen-button',
);
fireEvent.press(fullscreenButton);

// Wait for modal to be visible
await waitFor(() => {
expect(getByTestId('perps-chart-fullscreen-close-button')).toBeTruthy();
});

// Press close button
const closeButton = getByTestId('perps-chart-fullscreen-close-button');
fireEvent.press(closeButton);

// Verify modal is closed
await waitFor(() => {
expect(queryByTestId('perps-chart-fullscreen-close-button')).toBeNull();
});
});

it('renders fullscreen chart when modal is open', async () => {
const { getByTestId } = renderWithProvider(
<PerpsConnectionProvider>
<PerpsMarketDetailsView />
</PerpsConnectionProvider>,
{
state: initialState,
},
);

// Open the modal
const fullscreenButton = getByTestId(
'perps-market-header-fullscreen-button',
);
fireEvent.press(fullscreenButton);

// Wait for modal to be visible and verify chart is rendered
await waitFor(() => {
expect(getByTestId('perps-chart-fullscreen-close-button')).toBeTruthy();
expect(getByTestId('fullscreen-chart')).toBeTruthy();
});
});
});

Expand Down
Loading
Loading