Home > Net >  Mocking up Firebase onValue function using Jest
Mocking up Firebase onValue function using Jest

Time:09-28

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:

enter image description here

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
  • Related