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
39 changes: 23 additions & 16 deletions .github/workflows/react-native-cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ on:
- android
- ios
- all
release_notes:
type: string
description: 'Manual release notes override'
required: false

env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
Expand Down Expand Up @@ -276,30 +280,33 @@ jobs:
groups: Resgrid
notify: on

- name: 📋 Extract Release Notes from PR Body

- name: 📋 Prepare Release Notes file
if: ${{ matrix.platform == 'android' }}
env:
RELEASE_NOTES_INPUT: ${{ github.event.inputs.release_notes }}
PR_BODY: ${{ github.event.pull_request.body }}
run: |
set -eo pipefail
# Grab lines after "## Release Notes" until the next header
RELEASE_NOTES="$(printf '%s\n' "$PR_BODY" \
| awk 'f && /^## /{f=0} /^## Release Notes/{f=1; next} f')"
# Use a unique delimiter to write multiline into GITHUB_ENV
delimiter="EOF_$(date +%s)_$RANDOM"
{
echo "RELEASE_NOTES<<$delimiter"
printf '%s\n' "${RELEASE_NOTES:-No release notes provided.}"
echo "$delimiter"
} >> "$GITHUB_ENV"

- name: 📋 Prepare Release Notes file
if: ${{ matrix.platform == 'android' }}
run: |
# Determine source of release notes: workflow input, PR body, or recent commits
if [ -n "$RELEASE_NOTES_INPUT" ]; then
NOTES="$RELEASE_NOTES_INPUT"
elif [ -n "$PR_BODY" ]; then
NOTES="$(printf '%s\n' "$PR_BODY" \
| awk 'f && /^## /{exit} /^## Release Notes/{f=1; next} f')"
else
NOTES="$(git log -n 5 --pretty=format:'- %s')"
fi
# Fail if no notes extracted
if [ -z "$NOTES" ]; then
echo "Error: No release notes extracted" >&2
exit 1
fi
# Write header and notes to file
{
echo "## Version 10.${{ github.run_number }} - $(date +%Y-%m-%d)"
echo
printf '%s\n' "${RELEASE_NOTES:-No release notes provided.}"
printf '%s\n' "$NOTES"
} > RELEASE_NOTES.md

- name: 📦 Create Release
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

node_modules/
.expo/
.idea/
dist/
npm-debug.*
*.jks
Expand Down
19 changes: 19 additions & 0 deletions __mocks__/@/components/ui/actionsheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// @ts-nocheck
import React from 'react';

export function Actionsheet(props: any) {
const { isOpen, children } = props;
return isOpen ? React.createElement(React.Fragment, null, children) : null;
}
export function ActionsheetBackdrop() {
return React.createElement(React.Fragment, null);
}
export function ActionsheetContent(props: any) {
return React.createElement(React.Fragment, null, props.children);
}
export function ActionsheetDragIndicator() {
return React.createElement(React.Fragment, null);
}
export function ActionsheetDragIndicatorWrapper(props: any) {
return React.createElement(React.Fragment, null, props.children);
}
5 changes: 5 additions & 0 deletions __mocks__/@aptabase/react-native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const trackEvent = jest.fn();

export default {
trackEvent,
};
22 changes: 22 additions & 0 deletions __mocks__/@gorhom/bottom-sheet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Manual mock for @gorhom/bottom-sheet
const React = require('react');
const { View } = require('react-native');

function BottomSheet(props) {
return React.createElement(View, null, props.children);
}

function BottomSheetBackdrop(props) {
return React.createElement(View, null, props.children);
}

function BottomSheetView(props) {
return React.createElement(View, null, props.children);
}

module.exports = {
__esModule: true,
default: BottomSheet,
BottomSheetBackdrop,
BottomSheetView,
};
12 changes: 11 additions & 1 deletion __mocks__/@gorhom/bottom-sheet.ts
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
module.exports = require('@gorhom/bottom-sheet/mock');
// @ts-nocheck
// Valid TS manual mock for @gorhom/bottom-sheet
const React = require('react');
const { View } = require('react-native');

// @ts-nocheck
// Manual TS mock for @gorhom/bottom-sheet
// Provides dummy exports for testing
export default (() => null) as any;
export const BottomSheetBackdrop: any = () => null;
export const BottomSheetView: any = () => null;
13 changes: 13 additions & 0 deletions __mocks__/@react-native-community/netinfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* eslint-disable no-undef */
// Manual mock for @react-native-community/netinfo
const NetInfo = {
// Mock fetch to return connected by default
fetch: jest.fn(() => Promise.resolve({ isConnected: true, isInternetReachable: true })),
// Mock addEventListener to return an unsubscribe function
addEventListener: jest.fn(() => () => {}),
// Provide RNCNetInfo to satisfy native module expectations
RNCNetInfo: {},
};
// Export default and named exports
module.exports = NetInfo;
module.exports.default = NetInfo;
23 changes: 23 additions & 0 deletions __mocks__/expo-audio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Mock for expo-audio to understand the PermissionStatus structure
export const getRecordingPermissionsAsync = jest.fn();
export const requestRecordingPermissionsAsync = jest.fn();

// Default mock implementation
getRecordingPermissionsAsync.mockResolvedValue({
granted: false,
canAskAgain: true,
expires: 'never',
status: 'undetermined',
});

requestRecordingPermissionsAsync.mockResolvedValue({
granted: true,
canAskAgain: true,
expires: 'never',
status: 'granted',
});
// Default export for convenience
export default {
getRecordingPermissionsAsync,
requestRecordingPermissionsAsync,
};
10 changes: 10 additions & 0 deletions __mocks__/expo-task-manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* eslint-disable no-undef */
// Manual mock for expo-task-manager
const defineTask = jest.fn();
const isTaskRegisteredAsync = jest.fn(async () => false);
const unregisterTaskAsync = jest.fn(async () => {});
module.exports = {
defineTask,
isTaskRegisteredAsync,
unregisterTaskAsync,
};
96 changes: 96 additions & 0 deletions __mocks__/react-native-ble-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Mock for react-native-ble-manager
export type BleState = 'on' | 'off' | 'turning_on' | 'turning_off' | 'unsupported' | 'unknown';

export interface Peripheral {
id: string;
name?: string;
rssi?: number;
advertising?: {
isConnectable?: boolean;
localName?: string;
manufacturerData?: any;
serviceUUIDs?: string[];
txPowerLevel?: number;
};
}

export interface BleManagerDidUpdateValueForCharacteristicEvent {
peripheral: string;
characteristic: string;
service: string;
value: number[];
}

const mockPeripherals: Peripheral[] = [];
let mockState: BleState = 'on';
let mockIsScanning = false;
let scanTimerId: ReturnType<typeof setTimeout> | null = null;

const BleManager = {
start: jest.fn().mockResolvedValue(undefined),

checkState: jest.fn().mockImplementation(() => Promise.resolve(mockState)),

scan: jest.fn().mockImplementation((serviceUUIDs: string[], duration: number, allowDuplicates: boolean = false) => {
mockIsScanning = true;
// Simulate scanning timeout
scanTimerId = setTimeout(() => {
mockIsScanning = false;
scanTimerId = null;
}, duration * 1000);
return Promise.resolve();
}),

stopScan: jest.fn().mockImplementation(() => {
if (scanTimerId) {
clearTimeout(scanTimerId);
scanTimerId = null;
}
mockIsScanning = false;
return Promise.resolve();
}),

connect: jest.fn().mockResolvedValue(undefined),

disconnect: jest.fn().mockResolvedValue(undefined),

retrieveServices: jest.fn().mockResolvedValue(undefined),

startNotification: jest.fn().mockResolvedValue(undefined),

stopNotification: jest.fn().mockResolvedValue(undefined),

getConnectedPeripherals: jest.fn().mockResolvedValue([]),

getDiscoveredPeripherals: jest.fn().mockImplementation(() => {
return Promise.resolve(mockPeripherals.map((p) => ({ ...p })));
}),

isPeripheralConnected: jest.fn().mockResolvedValue(false),

// Mock utilities for testing
setMockState: (state: BleState) => {
mockState = state;
},

addMockPeripheral: (peripheral: Peripheral) => {
mockPeripherals.push(peripheral);
},

clearMockPeripherals: () => {
mockPeripherals.length = 0;
},

getMockPeripherals: () => mockPeripherals.map((p) => ({ ...p })),

isMockScanning: () => mockIsScanning,
};

// Set up as any for easier mocking
(BleManager as any).setMockState = BleManager.setMockState;
(BleManager as any).addMockPeripheral = BleManager.addMockPeripheral;
(BleManager as any).clearMockPeripherals = BleManager.clearMockPeripherals;
(BleManager as any).getMockPeripherals = BleManager.getMockPeripherals;
(BleManager as any).isMockScanning = BleManager.isMockScanning;

export default BleManager;
28 changes: 28 additions & 0 deletions __mocks__/react-native-callkeep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const mockMethods = {
setup: jest.fn().mockResolvedValue(undefined),
startCall: jest.fn().mockResolvedValue(undefined),
reportConnectingOutgoingCallWithUUID: jest.fn().mockResolvedValue(undefined),
reportConnectedOutgoingCallWithUUID: jest.fn().mockResolvedValue(undefined),
endCall: jest.fn().mockResolvedValue(undefined),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
answerIncomingCall: jest.fn(),
rejectCall: jest.fn(),
setCurrentCallActive: jest.fn(),
backToForeground: jest.fn(),
};

export default mockMethods;

export const AudioSessionCategoryOption = {
allowAirPlay: 1,
allowBluetooth: 2,
allowBluetoothA2DP: 4,
defaultToSpeaker: 8,
};

export const AudioSessionMode = {
voiceChat: 1,
};

export const CONSTANTS = {};
2 changes: 1 addition & 1 deletion __mocks__/react-native-gesture-handler.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('react-native-gesture-handler/lib/commonjs/mocks.js');
module.exports = require('react-native-gesture-handler/src/mocks.js');
1 change: 1 addition & 0 deletions contact-details-test-result.json

Large diffs are not rendered by default.

Loading
Loading