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 the runTests function which will run all the functions registered under the describe blocks:
import {runTests} from '@op-engineering/op-test`; const results = await runTests()
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 the displayResults component to show test results in your app in a visual way:
import { runTests, displayResults } from '@op-engineering/op-test'; export default function App() { const [result, setResult] = useState(null); useEffect(() => { runTests().then(setResult); }, []); return displayResults(result); }
You probably want to automate your in-app tests in your CI. For this you can pass the DescribeBlock to the allTestsPassed 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'; let testsPassed: boolean | null = null; const server = new BridgeServer('http_service', true); server.get('/ping', async (_req, _res) => { return { message: 'pong' }; }); server.get('/results', async (_req, _res) => { return { testPassed }; }); server.listen(9000); export function startServer() { return server; } export function stopServer() { server.stop(); } export function setServerTestPassed(r: boolean) { testsPassed = r; }
Then to run your tests:
import { runTests, displayResults, allTestsPassed, } from '@op-engineering/op-test'; import { startServer, setServerTestPassed } from './server'; export default function App() { const [result, setResult] = useState(null); useEffect(() => { runTests().then((newResults) => { setServerTestPassed(allTestsPassed(newResults)); setResult(newResults); }); startServer(); }, []); return displayResults(result); }
The CI code is left as an exercise to the reader, just curl the device ip until you get a response.
MIT
