Skip to content
Closed
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: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,18 @@ jobs:

- name: Build all packages
run: yarn workspaces foreach --all --topological-dev run prepare

test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup
uses: ./.github/actions/setup

- name: Typecheck test files
run: yarn workspace react-native-executorch typecheck:tests

- name: Run API contract tests
run: yarn workspace react-native-executorch test --ci
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`Public API surface export names match snapshot 1`] = `
[
"ALL_MINILM_L6_V2",
"ALL_MPNET_BASE_V2",
"BIELIK_V3_0_1_5B",
"BIELIK_V3_0_1_5B_QUANTIZED",
"BK_SDM_TINY_VPRED_256",
"BK_SDM_TINY_VPRED_512",
"BaseResourceFetcherClass",
"CLIP_VIT_BASE_PATCH32_IMAGE",
"CLIP_VIT_BASE_PATCH32_IMAGE_QUANTIZED",
"CLIP_VIT_BASE_PATCH32_TEXT",
"ClassificationModule",
"CocoKeypoint",
"CocoLabel",
"CocoLabelYolo",
"DEEPLAB_V3_MOBILENET_V3_LARGE",
"DEEPLAB_V3_MOBILENET_V3_LARGE_QUANTIZED",
"DEEPLAB_V3_RESNET101",
"DEEPLAB_V3_RESNET101_QUANTIZED",
"DEEPLAB_V3_RESNET50",
"DEEPLAB_V3_RESNET50_QUANTIZED",
"DEFAULT_CHAT_CONFIG",
"DEFAULT_CONTEXT_BUFFER_TOKENS",
"DEFAULT_MESSAGE_HISTORY",
"DEFAULT_STRUCTURED_OUTPUT_PROMPT",
"DEFAULT_SYSTEM_PROMPT",
"DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W",
"DISTILUSE_BASE_MULTILINGUAL_CASED_V2_8DA4W_MODEL",
"DISTILUSE_BASE_MULTILINGUAL_CASED_V2_TOKENIZER",
"DeeplabLabel",
"DownloadStatus",
"EFFICIENTNET_V2_S",
"EFFICIENTNET_V2_S_COREML_FP16_MODEL",
"EFFICIENTNET_V2_S_COREML_FP32_MODEL",
"EFFICIENTNET_V2_S_QUANTIZED",
"EFFICIENTNET_V2_S_XNNPACK_FP32_MODEL",
"EFFICIENTNET_V2_S_XNNPACK_INT8_MODEL",
"ExecutorchModule",
"FASTSAM_S",
"FASTSAM_S_COREML_FP16_MODEL",
"FASTSAM_S_XNNPACK_FP32_MODEL",
"FASTSAM_X",
"FASTSAM_X_COREML_FP16_MODEL",
"FASTSAM_X_XNNPACK_FP32_MODEL",
"FCN_RESNET101",
"FCN_RESNET101_QUANTIZED",
"FCN_RESNET50",
"FCN_RESNET50_QUANTIZED",
"FSMN_VAD",
"FastSAMLabel",
"HAMMER2_1_0_5B",
"HAMMER2_1_0_5B_QUANTIZED",
"HAMMER2_1_1_5B",
"HAMMER2_1_1_5B_QUANTIZED",
"HAMMER2_1_3B",
"HAMMER2_1_3B_QUANTIZED",
"HTTP_CODE",
"IMAGENET1K_MEAN",
"IMAGENET1K_STD",
"ImageEmbeddingsModule",
"Imagenet1kLabel",
"InstanceSegmentationModule",
"KOKORO_AMERICAN_ENGLISH_FEMALE_HEART",
"KOKORO_AMERICAN_ENGLISH_FEMALE_RIVER",
"KOKORO_AMERICAN_ENGLISH_FEMALE_SARAH",
"KOKORO_AMERICAN_ENGLISH_MALE_ADAM",
"KOKORO_AMERICAN_ENGLISH_MALE_MICHAEL",
"KOKORO_AMERICAN_ENGLISH_MALE_SANTA",
"KOKORO_BRITISH_ENGLISH_FEMALE_EMMA",
"KOKORO_BRITISH_ENGLISH_MALE_DANIEL",
"KOKORO_FRENCH_FEMALE_SIWIS",
"KOKORO_GERMAN",
"KOKORO_GERMAN_FEMALE_ANNA",
"KOKORO_HINDI_FEMALE_ALPHA",
"KOKORO_HINDI_MALE_OMEGA",
"KOKORO_HINDI_MALE_PSI",
"KOKORO_ITALIAN_FEMALE_SARA",
"KOKORO_ITALIAN_MALE_NICOLA",
"KOKORO_POLISH",
"KOKORO_POLISH_MALE_MATEUSZ",
"KOKORO_PORTUGUESE_FEMALE_DORA",
"KOKORO_PORTUGUESE_MALE_SANTA",
"KOKORO_SPANISH_FEMALE_DORA",
"KOKORO_SPANISH_MALE_ALEX",
"KOKORO_STANDARD",
"LFM2_5_1_2B_INSTRUCT",
"LFM2_5_1_2B_INSTRUCT_QUANTIZED",
"LFM2_5_350M",
"LFM2_5_350M_QUANTIZED",
"LFM2_5_VL_1_6B_QUANTIZED",
"LFM2_5_VL_450M_QUANTIZED",
"LFM2_VL_1_6B_QUANTIZED",
"LFM2_VL_450M_QUANTIZED",
"LLAMA3_2_1B",
"LLAMA3_2_1B_QLORA",
"LLAMA3_2_1B_SPINQUANT",
"LLAMA3_2_3B",
"LLAMA3_2_3B_QLORA",
"LLAMA3_2_3B_SPINQUANT",
"LLMModule",
"LRASPP_MOBILENET_V3_LARGE",
"LRASPP_MOBILENET_V3_LARGE_QUANTIZED",
"Logger",
"MULTI_QA_MINILM_L6_COS_V1",
"MULTI_QA_MPNET_BASE_DOT_V1",
"MessageCountContextStrategy",
"NoopContextStrategy",
"OCRModule",
"OCR_ABAZA",
"OCR_ADYGHE",
"OCR_AFRIKAANS",
"OCR_ALBANIAN",
"OCR_AVAR",
"OCR_AZERBAIJANI",
"OCR_BELARUSIAN",
"OCR_BOSNIAN",
"OCR_BULGARIAN",
"OCR_CHECHEN",
"OCR_CROATIAN",
"OCR_CZECH",
"OCR_DANISH",
"OCR_DARGWA",
"OCR_DUTCH",
"OCR_ENGLISH",
"OCR_ESTONIAN",
"OCR_FRENCH",
"OCR_GERMAN",
"OCR_HUNGARIAN",
"OCR_ICELANDIC",
"OCR_INDONESIAN",
"OCR_INGUSH",
"OCR_IRISH",
"OCR_ITALIAN",
"OCR_JAPANESE",
"OCR_KANNADA",
"OCR_KARBADIAN",
"OCR_KOREAN",
"OCR_KURDISH",
"OCR_LAK",
"OCR_LATIN",
"OCR_LATVIAN",
"OCR_LEZGHIAN",
"OCR_LITHUANIAN",
"OCR_MALAY",
"OCR_MALTESE",
"OCR_MAORI",
"OCR_MONGOLIAN",
"OCR_NORWEGIAN",
"OCR_OCCITAN",
"OCR_PALI",
"OCR_POLISH",
"OCR_PORTUGUESE",
"OCR_ROMANIAN",
"OCR_RUSSIAN",
"OCR_SERBIAN_CYRILLIC",
"OCR_SERBIAN_LATIN",
"OCR_SIMPLIFIED_CHINESE",
"OCR_SLOVAK",
"OCR_SLOVENIAN",
"OCR_SPANISH",
"OCR_SWAHILI",
"OCR_SWEDISH",
"OCR_TABASSARAN",
"OCR_TAGALOG",
"OCR_TAJIK",
"OCR_TELUGU",
"OCR_TURKISH",
"OCR_UKRAINIAN",
"OCR_UZBEK",
"OCR_VIETNAMESE",
"OCR_WELSH",
"ObjectDetectionModule",
"PARAPHRASE_MULTILINGUAL_MINILM_L12_V2_QUANTIZED",
"PHI_4_MINI_4B",
"PHI_4_MINI_4B_QUANTIZED",
"PRIVACY_FILTER_NEMOTRON",
"PRIVACY_FILTER_OPENAI",
"PoseEstimationModule",
"PrivacyFilterModule",
"QWEN2_5_0_5B",
"QWEN2_5_0_5B_QUANTIZED",
"QWEN2_5_1_5B",
"QWEN2_5_1_5B_QUANTIZED",
"QWEN2_5_3B",
"QWEN2_5_3B_QUANTIZED",
"QWEN3_0_6B",
"QWEN3_0_6B_QUANTIZED",
"QWEN3_1_7B",
"QWEN3_1_7B_QUANTIZED",
"QWEN3_4B",
"QWEN3_4B_QUANTIZED",
"QWEN3_5_0_8B_QUANTIZED",
"QWEN3_5_2B_QUANTIZED",
"RF_DETR_NANO",
"RF_DETR_NANO_COREML_INT8_MODEL",
"RF_DETR_NANO_SEG",
"RF_DETR_NANO_SEG_COREML_INT8_MODEL",
"RF_DETR_NANO_SEG_XNNPACK_FP32_MODEL",
"RF_DETR_NANO_XNNPACK_FP32_MODEL",
"ResourceFetcher",
"ResourceFetcherUtils",
"RnExecutorchError",
"RnExecutorchErrorCode",
"SELFIE_SEGMENTATION",
"SMOLLM2_1_135M",
"SMOLLM2_1_135M_QUANTIZED",
"SMOLLM2_1_1_7B",
"SMOLLM2_1_1_7B_QUANTIZED",
"SMOLLM2_1_360M",
"SMOLLM2_1_360M_QUANTIZED",
"SPECIAL_TOKENS",
"SSDLITE_320_MOBILENET_V3_LARGE",
"SSDLITE_320_MOBILENET_V3_LARGE_COREML_FP16_MODEL",
"SSDLITE_320_MOBILENET_V3_LARGE_XNNPACK_FP32_MODEL",
"STYLE_TRANSFER_CANDY",
"STYLE_TRANSFER_CANDY_QUANTIZED",
"STYLE_TRANSFER_MOSAIC",
"STYLE_TRANSFER_MOSAIC_QUANTIZED",
"STYLE_TRANSFER_RAIN_PRINCESS",
"STYLE_TRANSFER_RAIN_PRINCESS_QUANTIZED",
"STYLE_TRANSFER_UDNIE",
"STYLE_TRANSFER_UDNIE_QUANTIZED",
"ScalarType",
"SelfieSegmentationLabel",
"SemanticSegmentationModule",
"SlidingWindowContextStrategy",
"SourceType",
"SpeechToTextModule",
"StyleTransferModule",
"TextEmbeddingsModule",
"TextToImageModule",
"TextToSpeechModule",
"TokenizerModule",
"VADModule",
"VerticalOCRModule",
"WHISPER_BASE",
"WHISPER_BASE_EN",
"WHISPER_BASE_EN_MODEL_COREML",
"WHISPER_BASE_EN_MODEL_XNNPACK",
"WHISPER_BASE_EN_TOKENIZER",
"WHISPER_BASE_MODEL_COREML",
"WHISPER_BASE_MODEL_XNNPACK",
"WHISPER_BASE_TOKENIZER",
"WHISPER_SMALL",
"WHISPER_SMALL_EN",
"WHISPER_SMALL_EN_MODEL_COREML",
"WHISPER_SMALL_EN_MODEL_XNNPACK",
"WHISPER_SMALL_EN_TOKENIZER",
"WHISPER_SMALL_MODEL_COREML",
"WHISPER_SMALL_MODEL_XNNPACK",
"WHISPER_SMALL_TOKENIZER",
"WHISPER_TINY",
"WHISPER_TINY_EN",
"WHISPER_TINY_EN_MODEL_COREML",
"WHISPER_TINY_EN_MODEL_XNNPACK",
"WHISPER_TINY_EN_TOKENIZER",
"WHISPER_TINY_MODEL_COREML",
"WHISPER_TINY_MODEL_XNNPACK",
"WHISPER_TINY_TOKENIZER",
"YOLO26L",
"YOLO26L_SEG",
"YOLO26M",
"YOLO26M_SEG",
"YOLO26N",
"YOLO26N_POSE",
"YOLO26N_SEG",
"YOLO26S",
"YOLO26S_SEG",
"YOLO26X",
"YOLO26X_SEG",
"cleanupExecutorch",
"fixAndValidateStructuredOutput",
"getModelNameForUrl",
"getStructuredOutputPrompt",
"initExecutorch",
"isAvailable",
"models",
"parseToolCall",
"selectByBox",
"selectByPoint",
"selectByText",
"styleTransferUrls",
"useClassification",
"useExecutorchModule",
"useImageEmbeddings",
"useInstanceSegmentation",
"useLLM",
"useOCR",
"useObjectDetection",
"usePoseEstimation",
"usePrivacyFilter",
"useSemanticSegmentation",
"useSpeechToText",
"useStyleTransfer",
"useTextEmbeddings",
"useTextToImage",
"useTextToSpeech",
"useTokenizer",
"useVAD",
"useVerticalOCR",
]
`;
21 changes: 21 additions & 0 deletions packages/react-native-executorch/__tests__/api/apiSurface.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as RNE from '../../src';

// Snapshots the sorted list of public export names from
// `src/index.ts`. Any addition or removal flips the snapshot so the change is
// surfaced in the diff — a deliberate API tweak just needs `--updateSnapshot`,
// an accidental break does not slip through.
describe('Public API surface', () => {
it('export names match snapshot', () => {
const exportNames = Object.keys(RNE).sort();
expect(exportNames).toMatchSnapshot();
});

it('every export is non-undefined', () => {
for (const [name, value] of Object.entries(RNE)) {
expect({ name, defined: value !== undefined }).toEqual({
name,
defined: true,
});
}
});
});
45 changes: 45 additions & 0 deletions packages/react-native-executorch/__tests__/api/errorCodes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { RnExecutorchErrorCode } from '../../src/errors/ErrorCodes';
import { RnExecutorchError } from '../../src/errors/errorUtils';

// TypeScript enums emit a numeric reverse-mapping: `Enum[42] === 'KeyName'`.
// We use that to walk the enum at runtime as `[name, code]` pairs.
function enumEntries(): Array<[string, number]> {
return Object.entries(RnExecutorchErrorCode)
.filter(([, v]) => typeof v === 'number')
.map(([k, v]) => [k, v as number]);
}

describe('RnExecutorchErrorCode', () => {
const entries = enumEntries();

it('contains entries', () => {
expect(entries.length).toBeGreaterThan(0);
});

it('every numeric code is unique', () => {
const codes = entries.map(([, v]) => v);
const dupes = codes.filter((c, i) => codes.indexOf(c) !== i);
expect(dupes).toEqual([]);
});

it.each(entries)('%s = %s is a non-negative integer', (_name, code) => {
expect(Number.isInteger(code)).toBe(true);
expect(code).toBeGreaterThanOrEqual(0);
});

it.each(entries)('%s = %s has a working reverse lookup', (name, code) => {
expect(
(RnExecutorchErrorCode as unknown as Record<number, string>)[code]
).toBe(name);
});

it.each(entries)(
'new RnExecutorchError(%s = %s) produces a non-empty message',
(_name, code) => {
const err = new RnExecutorchError(code);
expect(typeof err.message).toBe('string');
expect(err.message.length).toBeGreaterThan(0);
expect(err.code).toBe(code);
}
);
});
Loading
Loading