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
24 changes: 24 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Test

on:
push:
branches: [main]
pull_request:

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "yarn"

- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Run tests
run: yarn test --forceExit --ci
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,7 @@ assets/models/**/*.json


key_local_mind
android/local.properties
android/local.properties


coverage/
9 changes: 9 additions & 0 deletions __mocks__/@gorhom/bottom-sheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react';
import { View } from 'react-native';

export const BottomSheetModal = React.forwardRef((_props: any, _ref: any) => null);
export const BottomSheetView = ({ children, style }: any) => (
<View style={style}>{children}</View>
);
export const BottomSheetBackdrop = () => null;
export const BottomSheetModalProvider = ({ children }: any) => <>{children}</>;
6 changes: 6 additions & 0 deletions __mocks__/@react-native-clipboard/clipboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const Clipboard = {
setString: jest.fn(),
getString: jest.fn(() => Promise.resolve('')),
};

export default Clipboard;
23 changes: 23 additions & 0 deletions __mocks__/async-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const store: Record<string, string> = {};

const AsyncStorage = {
getItem: jest.fn((key: string) => Promise.resolve(store[key] ?? null)),
setItem: jest.fn((key: string, value: string) => {
store[key] = value;
return Promise.resolve();
}),
removeItem: jest.fn((key: string) => {
delete store[key];
return Promise.resolve();
}),
clear: jest.fn(() => {
Object.keys(store).forEach((k) => delete store[k]);
return Promise.resolve();
}),
getAllKeys: jest.fn(() => Promise.resolve(Object.keys(store))),
multiGet: jest.fn((keys: string[]) =>
Promise.resolve(keys.map((k) => [k, store[k] ?? null]))
),
};

export default AsyncStorage;
3 changes: 3 additions & 0 deletions __mocks__/expo-file-system.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const File = jest.fn().mockImplementation(() => ({
text: jest.fn(),
}));
5 changes: 5 additions & 0 deletions __mocks__/react-native-audio-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const AudioManager = {
requestRecordingPermissions: jest.fn(() => Promise.resolve('Granted')),
setAudioSessionOptions: jest.fn(),
setAudioSessionActivity: jest.fn(() => Promise.resolve()),
};
6 changes: 6 additions & 0 deletions __mocks__/react-native-device-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const DeviceInfo = {
getTotalMemorySync: jest.fn(() => 8 * 1024 * 1024 * 1024), // 8 GB default
getUsedMemory: jest.fn(() => Promise.resolve(0)),
};

export default DeviceInfo;
51 changes: 51 additions & 0 deletions __mocks__/react-native-executorch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const makeModelConstants = (name: string) => ({
modelSource: `https://huggingface.co/mock/${name}/model.pte`,
tokenizerSource: `https://huggingface.co/mock/${name}/tokenizer.json`,
tokenizerConfigSource: `https://huggingface.co/mock/${name}/tokenizer_config.json`,
});

export const QWEN3_0_6B_QUANTIZED = makeModelConstants('qwen3-0.6b-quantized');
export const QWEN3_0_6B = makeModelConstants('qwen3-0.6b');
export const QWEN3_1_7B = makeModelConstants('qwen3-1.7b');
export const QWEN3_1_7B_QUANTIZED = makeModelConstants('qwen3-1.7b-quantized');
export const QWEN3_4B = makeModelConstants('qwen3-4b');
export const QWEN3_4B_QUANTIZED = makeModelConstants('qwen3-4b-quantized');
export const LLAMA3_2_1B = makeModelConstants('llama3.2-1b');
export const LLAMA3_2_1B_QLORA = makeModelConstants('llama3.2-1b-qlora');
export const LLAMA3_2_1B_SPINQUANT = makeModelConstants('llama3.2-1b-spinquant');
export const LLAMA3_2_3B = makeModelConstants('llama3.2-3b');
export const LLAMA3_2_3B_QLORA = makeModelConstants('llama3.2-3b-qlora');
export const LLAMA3_2_3B_SPINQUANT = makeModelConstants('llama3.2-3b-spinquant');
export const HAMMER2_1_0_5B = makeModelConstants('hammer2.1-0.5b');
export const HAMMER2_1_0_5B_QUANTIZED = makeModelConstants('hammer2.1-0.5b-quantized');
export const HAMMER2_1_1_5B = makeModelConstants('hammer2.1-1.5b');
export const HAMMER2_1_1_5B_QUANTIZED = makeModelConstants('hammer2.1-1.5b-quantized');
export const HAMMER2_1_3B = makeModelConstants('hammer2.1-3b');
export const HAMMER2_1_3B_QUANTIZED = makeModelConstants('hammer2.1-3b-quantized');
export const QWEN2_5_0_5B = makeModelConstants('qwen2.5-0.5b');
export const QWEN2_5_0_5B_QUANTIZED = makeModelConstants('qwen2.5-0.5b-quantized');
export const QWEN2_5_1_5B = makeModelConstants('qwen2.5-1.5b');
export const QWEN2_5_1_5B_QUANTIZED = makeModelConstants('qwen2.5-1.5b-quantized');
export const QWEN2_5_3B = makeModelConstants('qwen2.5-3b');
export const QWEN2_5_3B_QUANTIZED = makeModelConstants('qwen2.5-3b-quantized');
export const PHI_4_MINI_4B = makeModelConstants('phi4-mini-4b');
export const PHI_4_MINI_4B_QUANTIZED = makeModelConstants('phi4-mini-4b-quantized');
export const LFM2_5_1_2B_INSTRUCT = makeModelConstants('lfm2.5-1.2b-instruct');
export const LFM2_5_1_2B_INSTRUCT_QUANTIZED = makeModelConstants('lfm2.5-1.2b-instruct-quantized');
export const WHISPER_TINY_EN = 'whisper-tiny-en';

export const LLMModule = {
fromCustomModel: jest.fn(),
};

export const SpeechToTextModule = {
fromModelName: jest.fn(),
};

export const TextEmbeddingsModule = {
fromCustomModel: jest.fn(),
};

export const ResourceFetcher = {
fetch: jest.fn(),
};
3 changes: 3 additions & 0 deletions __mocks__/react-native-fs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const exists = jest.fn();
export const unlink = jest.fn();
export const copyFileAssets = jest.fn();
6 changes: 6 additions & 0 deletions __mocks__/react-native-markdown-display.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import { Text } from 'react-native';

const Markdown = ({ children }: { children: string }) => <Text>{children}</Text>;

export default Markdown;
1 change: 1 addition & 0 deletions __mocks__/react-native-pdfium.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const readPDF = jest.fn();
3 changes: 3 additions & 0 deletions __mocks__/react-native-reanimated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Use the official mock provided by react-native-reanimated
const Reanimated = require('react-native-reanimated/mock');
module.exports = Reanimated;
6 changes: 6 additions & 0 deletions __mocks__/react-native-toast-message.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const Toast = {
show: jest.fn(),
hide: jest.fn(),
};

export default Toast;
6 changes: 6 additions & 0 deletions __mocks__/svgMock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react';
import { View } from 'react-native';

const SvgMock = (props: any) => <View {...props} />;
export default SvgMock;
export const ReactComponent = SvgMock;
Loading
Loading