I'm trying to mock up Firebase 9.0.0 onValue()
function using Jest. The main component reads a feature using the onValue()
function and renders the result.
Acerca.js
:
import React, { useEffect, useState } from 'react'
import { db, onValue, ref } from './Firebase'
const Acerca = () => {
const [feature, setFeature] = useState('')
useEffect(() => {
let featureRef = ref(db, 'feature')
let unsubscribe = onValue(featureRef, snapshot => {
setFeature(snapshot.val())
})
return () => unsubscribe()
}, [])
return(
<>{feature ? <h3>{feature}</h3> : null}</>
)
}
export default Acerca
Acerca.test.js
:
import React from 'react'
import Acerca from './Acerca'
import { render } from 'react-dom'
import { act } from 'react-dom/test-utils'
import { onValue } from './Firebase'
it("Acerca -> displays title", async () => {
const data = {
feature: {
title: "New feature"
}
}
const snapshot = { val: () => data }
const firebase = { onValue }
const spy = jest.spyOn(firebase, 'onValue').mockImplementation(() => jest.fn((event, callback) => callback(snapshot)))
await act(async () => {
render(<Acerca/>, container)
})
expect(container.querySelector('h3').textContent).toBe(data.feature.title)
})
The problem is that the mock up function is not being called (null value instead of the dummy data) and the test fails:
What is the correct way to mock up the onValue()
function?
CodePudding user response:
Acerca.js
:
import React, { useEffect, useState } from 'react';
import { db, onValue, ref } from './Firebase';
const Acerca = () => {
const [feature, setFeature] = useState();
useEffect(() => {
let featureRef = ref(db, 'feature');
let unsubscribe = onValue(featureRef, (snapshot) => {
setFeature(snapshot.val().feature);
});
return () => unsubscribe();
}, []);
return <>{feature ? <h3>{feature.title}</h3> : null}</>;
};
export default Acerca;
Firebase.js
:
// simulate real firebase module
export function onValue(ref, callback) {
const snapshot = {
val() {
return 'real implementation';
},
};
callback(snapshot);
return function unsubscribe() {};
}
export function ref(db, name) {
return {};
}
export const db = {};
Acerca.test.js
:
import React from 'react';
import { render } from 'react-dom';
import { act } from 'react-dom/test-utils';
import { onValue } from './Firebase';
import Acerca from './Acerca';
jest.mock('./Firebase');
describe('Acerca', () => {
test('should pass', async () => {
const data = { feature: { title: 'New feature' } };
const snapshot = { val: () => data };
onValue.mockImplementation((ref, callback) => {
callback(snapshot);
return jest.fn();
});
const container = document.createElement('div');
await act(async () => {
render(<Acerca />, container);
});
expect(container.querySelector('h3').textContent).toBe(data.feature.title);
});
});
test result:
PASS examples/69324329/Acerca.test.js (8.029 s)
Acerca
✓ should pass (20 ms)
-------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files | 70 | 100 | 37.5 | 73.68 |
Acerca.js | 91.67 | 100 | 75 | 100 |
Firebase.js | 37.5 | 100 | 0 | 37.5 | 2-8,12
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.556 s