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
15 changes: 1 addition & 14 deletions app/components/UI/Ramp/hooks/useRampsUnifiedV1Enabled.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
import { useSelector } from 'react-redux';
import { getVersion } from 'react-native-device-info';
import compareVersions from 'compare-versions';
import {
selectRampsUnifiedBuyV1ActiveFlag,
selectRampsUnifiedBuyV1MinimumVersionFlag,
} from '../../../../selectors/featureFlagController/ramps/rampsUnifiedBuyV1';

function hasMinimumRequiredVersion(
minRequiredVersion: string | null | undefined,
isUnifiedV1Enabled: boolean,
) {
if (!minRequiredVersion) return false;
const currentVersion = getVersion();
return (
isUnifiedV1Enabled &&
compareVersions.compare(currentVersion, minRequiredVersion, '>=')
);
}
import { hasMinimumRequiredVersion } from '../utils/hasMinimumRequiredVersion';

export default function useRampsUnifiedV1Enabled() {
const rampsUnifiedBuyV1MinimumVersionFlag = useSelector(
Expand Down
219 changes: 219 additions & 0 deletions app/components/UI/Ramp/hooks/useRampsUnifiedV2Enabled.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
import initialRootState, {
backgroundState,
} from '../../../../util/test/initial-root-state';
import { renderHookWithProvider } from '../../../../util/test/renderWithProvider';
import useRampsUnifiedV2Enabled from './useRampsUnifiedV2Enabled';
import { getVersion } from 'react-native-device-info';

function mockInitialState({
rampsUnifiedBuyV2ActiveFlag = true,
rampsUnifiedBuyV2MinimumVersionFlag,
}: {
rampsUnifiedBuyV2ActiveFlag?: boolean;
rampsUnifiedBuyV2MinimumVersionFlag?: string | null;
} = {}) {
return {
...initialRootState,
engine: {
backgroundState: {
...backgroundState,
RemoteFeatureFlagController: {
remoteFeatureFlags: {
rampsUnifiedBuyV2: {
active: rampsUnifiedBuyV2ActiveFlag,
...(rampsUnifiedBuyV2MinimumVersionFlag !== undefined && {
minimumVersion: rampsUnifiedBuyV2MinimumVersionFlag,
}),
},
},
},
},
},
};
}

jest.mock('react-native-device-info', () => ({
getVersion: jest.fn(),
}));

describe('useRampsUnifiedV2Enabled', () => {
const mockGetVersion = jest.mocked(getVersion);
const originalEnv = process.env;

beforeEach(() => {
jest.clearAllMocks();
process.env = { ...originalEnv };
delete process.env.MM_RAMPS_UNIFIED_BUY_V2_ENABLED;
});

afterAll(() => {
process.env = originalEnv;
});

describe('Build flag precedence', () => {
it('returns true when build flag is set to "true" regardless of remote flags', () => {
process.env.MM_RAMPS_UNIFIED_BUY_V2_ENABLED = 'true';
mockGetVersion.mockReturnValue('1.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: false,
rampsUnifiedBuyV2MinimumVersionFlag: '2.0.0',
}),
},
);

expect(result.current).toBe(true);
});

it('returns false when build flag is set to "false" regardless of remote flags', () => {
process.env.MM_RAMPS_UNIFIED_BUY_V2_ENABLED = 'false';
mockGetVersion.mockReturnValue('2.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: true,
rampsUnifiedBuyV2MinimumVersionFlag: '1.0.0',
}),
},
);

expect(result.current).toBe(false);
});

it('returns true when build flag is set to "true" even with version mismatch', () => {
process.env.MM_RAMPS_UNIFIED_BUY_V2_ENABLED = 'true';
mockGetVersion.mockReturnValue('1.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: true,
rampsUnifiedBuyV2MinimumVersionFlag: '2.0.0',
}),
},
);

expect(result.current).toBe(true);
});
});

describe('Remote feature flag behavior when build flag is not set', () => {
it('returns true when unified V2 is enabled and version meets the minimum requirement', () => {
mockGetVersion.mockReturnValue('8.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: true,
rampsUnifiedBuyV2MinimumVersionFlag: '7.63.0',
}),
},
);

expect(result.current).toBe(true);
});

it('returns false when unified V2 is disabled', () => {
mockGetVersion.mockReturnValue('8.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: false,
rampsUnifiedBuyV2MinimumVersionFlag: '7.63.0',
}),
},
);

expect(result.current).toBe(false);
});

it('returns false when version does not meet the minimum requirement', () => {
mockGetVersion.mockReturnValue('7.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: true,
rampsUnifiedBuyV2MinimumVersionFlag: '7.63.0',
}),
},
);

expect(result.current).toBe(false);
});

it('returns false when minimum version is not defined', () => {
mockGetVersion.mockReturnValue('8.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: true,
rampsUnifiedBuyV2MinimumVersionFlag: null,
}),
},
);

expect(result.current).toBe(false);
});

it('returns false when minimum version is undefined', () => {
mockGetVersion.mockReturnValue('8.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: true,
rampsUnifiedBuyV2MinimumVersionFlag: undefined,
}),
},
);

expect(result.current).toBe(false);
});

it('returns true when version equals minimum version exactly', () => {
mockGetVersion.mockReturnValue('7.63.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: true,
rampsUnifiedBuyV2MinimumVersionFlag: '7.63.0',
}),
},
);

expect(result.current).toBe(true);
});

it('returns false when both active flag and minimum version are not set', () => {
mockGetVersion.mockReturnValue('8.0.0');

const { result } = renderHookWithProvider(
() => useRampsUnifiedV2Enabled(),
{
state: mockInitialState({
rampsUnifiedBuyV2ActiveFlag: false,
rampsUnifiedBuyV2MinimumVersionFlag: null,
}),
},
);

expect(result.current).toBe(false);
});
});
});
33 changes: 33 additions & 0 deletions app/components/UI/Ramp/hooks/useRampsUnifiedV2Enabled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { useSelector } from 'react-redux';
import {
selectRampsUnifiedBuyV2ActiveFlag,
selectRampsUnifiedBuyV2MinimumVersionFlag,
} from '../../../../selectors/featureFlagController/ramps/rampsUnifiedBuyV2';
import { hasMinimumRequiredVersion } from '../utils/hasMinimumRequiredVersion';

export default function useRampsUnifiedV2Enabled() {
const rampsUnifiedBuyV2MinimumVersionFlag = useSelector(
selectRampsUnifiedBuyV2MinimumVersionFlag,
);
const rampsUnifiedBuyV2ActiveFlag = useSelector(
selectRampsUnifiedBuyV2ActiveFlag,
);

const rampsUnifiedBuyV2BuildFlag =
process.env.MM_RAMPS_UNIFIED_BUY_V2_ENABLED;

// if build flag is defined, it takes precedence over remote feature flag
if (
rampsUnifiedBuyV2BuildFlag === 'true' ||
rampsUnifiedBuyV2BuildFlag === 'false'
) {
return rampsUnifiedBuyV2BuildFlag === 'true';
}

const isRampsUnifiedV2Enabled = hasMinimumRequiredVersion(
rampsUnifiedBuyV2MinimumVersionFlag,
rampsUnifiedBuyV2ActiveFlag,
);

return isRampsUnifiedV2Enabled;
}
108 changes: 108 additions & 0 deletions app/components/UI/Ramp/utils/hasMinimumRequiredVersion.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { getVersion } from 'react-native-device-info';
import { hasMinimumRequiredVersion } from './hasMinimumRequiredVersion';

jest.mock('react-native-device-info', () => ({
getVersion: jest.fn(),
}));

describe('hasMinimumRequiredVersion', () => {
const mockGetVersion = jest.mocked(getVersion);

beforeEach(() => {
jest.clearAllMocks();
});

describe('when feature is enabled', () => {
it('returns true when current version exceeds minimum version', () => {
mockGetVersion.mockReturnValue('8.0.0');

const result = hasMinimumRequiredVersion('7.63.0', true);

expect(result).toBe(true);
});

it('returns true when current version equals minimum version', () => {
mockGetVersion.mockReturnValue('7.63.0');

const result = hasMinimumRequiredVersion('7.63.0', true);

expect(result).toBe(true);
});

it('returns false when current version is below minimum version', () => {
mockGetVersion.mockReturnValue('7.0.0');

const result = hasMinimumRequiredVersion('7.63.0', true);

expect(result).toBe(false);
});

it('returns false when minimum version is null', () => {
mockGetVersion.mockReturnValue('8.0.0');

const result = hasMinimumRequiredVersion(null, true);

expect(result).toBe(false);
});

it('returns false when minimum version is undefined', () => {
mockGetVersion.mockReturnValue('8.0.0');

const result = hasMinimumRequiredVersion(undefined, true);

expect(result).toBe(false);
});

it('returns false when minimum version is empty string', () => {
mockGetVersion.mockReturnValue('8.0.0');

const result = hasMinimumRequiredVersion('', true);

expect(result).toBe(false);
});
});

describe('when feature is disabled', () => {
it('returns false even when version meets requirement', () => {
mockGetVersion.mockReturnValue('8.0.0');

const result = hasMinimumRequiredVersion('7.63.0', false);

expect(result).toBe(false);
});

it('returns false when minimum version is null', () => {
mockGetVersion.mockReturnValue('8.0.0');

const result = hasMinimumRequiredVersion(null, false);

expect(result).toBe(false);
});
});

describe('version comparison edge cases', () => {
it('returns true when patch version exceeds minimum version', () => {
mockGetVersion.mockReturnValue('7.63.1');

const result = hasMinimumRequiredVersion('7.63.0', true);

expect(result).toBe(true);
});

it('returns true when minor version exceeds minimum version', () => {
mockGetVersion.mockReturnValue('7.64.0');

const result = hasMinimumRequiredVersion('7.63.0', true);

expect(result).toBe(true);
});

it('returns true when major version exceeds minimum version', () => {
mockGetVersion.mockReturnValue('8.0.0');

const result = hasMinimumRequiredVersion('7.63.0', true);

expect(result).toBe(true);
});
});
});
Loading
Loading