Using jest mock for socket.io events in react native - react-native

I am trying to write tests for my react native app but am running into issues because we use sockets for connection and data transmission. The very basic initial test code looks like this:
import React from "react";
import renderer from "react-test-renderer";
import { SessionTab } from "./index";
beforeEach(() => {
jest.spyOn(console, "warn").mockImplementation(() => {});
});
beforeAll(() => {
ReactDOM.createPortal = jest.fn((element, node) => {
return element;
});
});
test("renders correctly", () => {
const tree = renderer.create(<SessionTab />).toJSON();
expect(tree).toMatchSnapshot();
});
The error I'm getting when I run my test looks like this:
6 | export default store = createStore(rootReducer, applyMiddleware(thunk));
7 |
> 8 | SocketDriver.OnBroadcast('admin.getModel', async () => {
| ^
9 | let messageQueue = await SocketDriver.messageQueue.getQueue();
10 |
11 | SocketDriver.emitToServer('system.reportModel', { data: {
The function being referenced there looks like this:
static OnBroadcast(event, handler) {
SocketDriver.listen(event);
event += '.broadcast';
SocketDriver.events[event].addListener(event, handler);
}
I think this is where using jest mocks could help, but even though I've read some documentation, I'm unclear how to implement. How would I set up a jest mock for the OnBroadcast event above?

Related

Testing a nested custom hook with react-testing-library

I'm trying to test a hook in isolation with #testing-library/render-hooks in a React Native project. The hook I have looks something like this:
const useStatus = () => {
const [ status, setStatus ] = useState(null)
const { data: data1 } = useDataHook1()
const { data: data2 } = useDataHook2()
useEffect(() => {
if (data1 && data2) {
// Some logic to determine status based on data1 + data2
setStatus(...)
}
}, [data1, data2])
return { status }
}
So I want to test useStatus and I'd like to mock useData1 and useData2, all three hooks of which are defined in the same file. My test looks like so:
import * as hooks from 'path/to/hooks'
const data1Spy = jest.spyOn(hooks, 'useData1')
const data2Spy = jest.spyOn(hooks, 'useData2')
describe('useStatus', () => {
it('should render', async () => {
data1Spy.mockReturnValue({ data: 'foo' }
data2Spy.mockReturnValue({ data: 'bar' }
const { result, waitForNextUpdate } = renderHook(() => hooks.useStatus())
await waitForNextUpdate()
console.log(result.current.status)
}
}
The console logs values that I would expect if the nested data hooks weren't returning, and the error:
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
appears, which tells me that the mocks aren't being set correctly. (Thinking the SWR queries are trying to dispatch in a test environment, leading to unresolved promises floating around after the test finishes.)
Some things I've tried:
Using mockReturnValue as seen in the above code
Using mockImplementation instead of mockReturnValue
Using jest.mock + jest.requireActual pattern as is done here
I'm not sure what else to try. I've been able to mock hooks before using the above pattern when rendering a component, but this is my first time working with rendering the hook directly. Any thoughts?

How do I import data from SQL via Prisma into React without running into a Promise error?

I'm currently trying to bring data from my MS SQL database into React components without causing a Promise error. Basically, this inherently involves async functions, but every time I use them, I get an error claiming that I'm trying to pass a Promise rather than an actual array into React.
How do I overcome this issue and pull data via prisma into Typescript and then transfer it into a React component without having complaints about a Promise?
Here's my code:
export const getServerSideProps = async () => {
const res = await fetch("http://localhost:8081/api/fRED_Market_Yield_10Y");
const my10y = await res.json();
return {
props: { my10y },
};
};
export function MY10Y({ my10y: [] }) {
return (
<div>
{my10y?.map((p: { DateTime: Key | null | undefined; Value: boolean | ReactChild | ReactFragment | ReactPortal | null | undefined; }) => {
return (
<div key={p.DateTime}>
<p>
{p.Value}%
</p>
</div>
);
})}
</div>
);
}
// pages/api/products.js
import { Prisma, PrismaClient } from "#prisma/client";
import { Key, ReactChild, ReactFragment, ReactPortal } from "react";
let prisma: PrismaClient<Prisma.PrismaClientOptions, never, Prisma.RejectOnNotFound | Prisma.RejectPerOperation | undefined>;
prisma = new PrismaClient();
//export default prisma;
export default async function handle(req: any, res: { json: (arg0: any) => void; }) {
const my10y = await prisma.fRED_Market_Yield_10Y.findMany();
res.json(my10y);
}

React Native: 'Jest did not exit one second after the test run has completed' with #testing-library/react-hooks and react-query

I am using jest and #testing-library/react-hooks to test hooks implemented with react-query in my React Native code.
The tests work ok, but at the end, I am getting:
Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
Here is my simplified code:
import { renderHook } from '#testing-library/react-hooks'
import React from 'react'
import { QueryClient, QueryClientProvider, useQuery } from 'react-query'
const useSomething = () => {
return useQuery('myquery', () => 'OK')
}
beforeAll((done) => {
done()
})
afterAll((done) => {
done()
})
// test cases
describe('Testing something', () => {
it('should do something', async () => {
const queryClient = new QueryClient()
const wrapper = ({ children }: { children: React.ReactFragment }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
)
const { result, waitFor } = renderHook(() => useSomething(), { wrapper })
await waitFor(() => {
return result.current.isSuccess
})
expect(result.current.data).toBe('OK')
})
})
I tried using cleanup, done, unmount, etc. before each/all with no results. If I remove useQuery from useSomething, the problem disappears.
Any idea how to fix it?
This issue has been reported in the past here:
https://github.com/tannerlinsley/react-query/issues/1847
The issue is caused by the react-query garbage collection timer running, which defaults to 5 minutes. Solutions are, as described in the issue:
clearing the queryCache after each test:
afterEach(() => { queryClient.clear() });
setting cacheTime to 0 for your test, e.g. with: queryClient.setDefaultOptions({ queries: { cacheTime: 0 } })
using jest.useFakeTimers()
You could try defining a function like:
export function flushPromises() {
return new Promise((resolve) => setImmediate(resolve));
}
Then on your test before the expect:
await flushPromises();
More info here

Firestore (9.1.3): Connection WebChannel transport erroned / Work on web browser but not on device mobiles (IOS/Android)

After upgrading from firebase v8 to v9 I have this problem, writing to firestore works fine in web browser but not on IOS / Android (no writing is done), after few minutes I have this warning:
#firebase/firestore:, Firestore (9.1.3): Connection, WebChannel transport errored:, me ...
summary of the code
import { initializeApp } from 'firebase/app'
import { getFirestore } from "firebase/firestore"
import { doc, setDoc } from "firebase/firestore"
const app = initializeApp(config)
const db = getFirestore(app);
const MyComponent = () => {
...
useEffect(() => {
(async function zda() {
await setDoc(doc(db, "users", "mario"), {
employment: "plumber",
outfitColor: "red",
specialAttack: "fireball"
})
})()
}, [])
By the way, I solved my problem with this line
const db = initializeFirestore(app, {useFetchStreams: false})

How to initialize manually next.js app (for testing purpose)?

I try to test my web services, hosted in my Next.js app and I have an error with not found Next.js configuration.
My web service are regular one, stored in the pages/api directory.
My API test fetches a constant ATTACKS_ENDPOINT thanks to this file:
/pages/api/tests/api.spec.js
import { ATTACKS_ENDPOINT } from "../config"
...
describe("endpoints", () => {
beforeAll(buildOptionsFetch)
it("should return all attacks for attacks endpoint", async () => {
const response = await fetch(API_URL + ATTACKS_ENDPOINT, headers)
config.js
import getConfig from "next/config"
const { publicRuntimeConfig } = getConfig()
export const API_URL = publicRuntimeConfig.API_URL
My next.config.js is present and is used properly by the app when started.
When the test is run, this error is thrown
TypeError: Cannot destructure property `publicRuntimeConfig` of 'undefined' or 'null'.
1 | import getConfig from "next/config"
2 |
> 3 | const { publicRuntimeConfig } = getConfig()
I looked for solutions and I found this issue which talks about _manually initialise__ next app.
How to do that, given that I don't test React component but API web service ?
I solved this problem by creating a jest.setup.js file and adding this line of code
First add jest.setup.js to jest.config.js file
// jest.config.js
module.exports = {
// Your config
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
};
AND then
// jest.setup.js
jest.mock('next/config', () => () => ({
publicRuntimeConfig: {
YOUR_PUBLIC_VARIABLE: 'value-of-env' // Change this line and copy your env
}
}))
OR
// jest.setup.js
import { setConfig } from 'next/config'
import config from './next.config'
// Make sure you can use "publicRuntimeConfig" within tests.
setConfig(config)
The problem I faced with testing with Jest was that next was not being initialized as expected. My solution was to mock the next module... You can try this:
/** #jest-environment node */
jest.mock('next');
import next from 'next';
next.mockReturnValue({
prepare: () => Promise.resolve(),
getRequestHandler: () => (req, res) => res.status(200),
getConfig: () => ({
publicRuntimeConfig: {} /* This is where you import the mock values */
})
});
Read about manual mocks here: https://jestjs.io/docs/en/manual-mocks
In my case, I had to:
Create a jest.setup.js file and
setConfig({
...config,
publicRuntimeConfig: {
BASE_PATH: '/',
SOME_KEY: 'your_value',
},
serverRuntimeConfig: {
YOUR_KEY: 'your_value',
},
});
Then add this in your jest.config.js file:
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],