A lightweight, in-app testing framework for React Native applications.
You can think of op-test as a half-way between a Detox (UI e2e test) and Jest (runs in a Node environment). It's specially useful for library authors that depend on native libraries or some sort of runtime behavior that requires a simulator/emulator/device to assert correct functionality. It's specially suited to test JSI enabled libraries as testing JSI/TurboModules/NitroModules functions require the whole the React Native app to have started.

npm install --save @op-engineering/op-test
Import the testing utilities and write your tests:
import{describe,it,expect}from'@op-engineering/op-test';describe('Example',()=>{it('should work',()=>{expect(1+1).toBe(2);});});
You can then call therunTests
function which will run all the functions registered under thedescribe
blocks:
import{runTests}from '@op-engineering/op-test`;constresults=awaitrunTests()
describe(name: string, fn: () => void)
: Group related testsit(name: string, fn: TestFunction)
: Define a test caseexpect(value)
: Create assertions with:.toBe(expected)
: Strict equality.toEqual(expected)
: Loose equality.not.toBe(expected)
: Negative strict equality.not.toEqual(expected)
: Negative loose equality.resolves
: For testing promises.rejects
: For testing promise rejections
beforeAll(fn)
: Run before all tests in a describe blockbeforeEach(fn)
: Run before each testafterAll(fn)
: Run after all tests in a describe blockafterEach(fn)
: Run after each test
Use thedisplayResults
component to show test results in your app in a visual way:
import{runTests,displayResults}from'@op-engineering/op-test';exportdefaultfunctionApp(){const[result,setResult]=useState(null);useEffect(()=>{runTests().then(setResult);},[]);returndisplayResults(result);}
You probably want to automate your in-app tests in your CI. For this you can pass the DescribeBlock to theallTestsPassed
function, it will return a boolean that indicates if all tests have passed. You can this automate this in various ways in your CI. My favorite is starting and in-app http server, exposing a single endpoint. From your CI you can then start the app, query this endpoint (over and over until it returns a reponse). Here is a snippet how to do this.
Server code:
import{BridgeServer}from'react-native-http-bridge-refurbished';lettestsPassed:boolean|null=null;constserver=newBridgeServer('http_service',true);server.get('/ping',async(_req,_res)=>{return{message:'pong'};});server.get('/results',async(_req,_res)=>{return{ testPassed};});server.listen(9000);exportfunctionstartServer(){returnserver;}exportfunctionstopServer(){server.stop();}exportfunctionsetServerTestPassed(r:boolean){testsPassed=r;}
Then to run your tests:
import{runTests,displayResults,allTestsPassed,}from'@op-engineering/op-test';import{startServer,setServerTestPassed}from'./server';exportdefaultfunctionApp(){const[result,setResult]=useState(null);useEffect(()=>{runTests().then((newResults)=>{setServerTestPassed(allTestsPassed(newResults));setResult(newResults);});startServer();},[]);returndisplayResults(result);}
The CI code is left as an exercise to the reader, just curl the device ip until you get a response.
MIT