Collin
Collin

Reputation: 409

Jest mock readFile, writeFile doesn't load my mocks

General question before. When I use jest.mock() can I only mock the whole module? Or also exported functions, constants. In my app.js, I use for example const fileSystem = require('fs'). I'm trying to test the app, which has a method where it reads a file with fs. Do I have now to mock the 'fs' module in my test or load the app.js and mock then the constant where fs is loaded?

Here is my code:

const express = require('express')
const dataFilePath = '../shoppinglist/data.json'
const fileSystem = require('fs')
let data
module.exports = {app, listener, getNewestId, getSmsFormatedShoppingList, readUpdatedData, 
dataFilePath}

app.get(baseUrl, (req, res) => {
    let finishedState
    readUpdatedData()
    if(isDataEmpty()){
      return res.status(200).send([])
    }
   if(req.query.isFinished){
        finishedState = req.query.isFinished === 'true'
    }
    const listsWithoutItems = data.data.map(({ items, ...rest }) => rest)

    const filteredList = (finishedState === true || finishedState === false)  ? sortShoppingListByFinished(listsWithoutItems, finishedState) : listsWithoutItems

    if(filteredList.length === 0){
        res.statusCode = 204
        res.send()
    }

    // adjust later, this is just used for tests
    res.setHeader('Content-Type', 'application/json')
    data.data = filteredList
    res.json(data)
    res.status(200).send()
})


function readUpdatedData(){
        let rawData = fileSystem.readFileSync(dataFilePath)
        data = JSON.parse(rawData)
        console.log(data)
        console.log('-------------------------')
}

Now I like to test, if the api call is successful and the data which are read is correct. For this I tried to mock the data.json, but when the test runs, then fileSystem.readFileSync('../shoppinglist/data.json') is always undefined. So I guess when it loads the app, it ignores somehow my mocked data for ../shoppinglist/data.json

describe('Get for all Lists with entries', () => {
    it('should return a list with 2 entries without items', async () => {
       jest.mock('../shoppinglist/data.json', () => ({
                    "data" : [
                        {
                            "id": 0,
                            "name": "filled shopping list",
                            "location": "lidl",
                            "targetDate": "22.03.1986",
                            "priority": 1,
                            "isFinished": false,
                            "items": [{"count":1, "name": "vodka" }, {"count":1, "name": "vodka" }
                            ]
                        }, {
                            "id": 1,
                            "name": "filled shopping list2",
                            "location": "lidl2",
                            "targetDate": "22.03.1986",
                            "priority": 1,
                            "isFinished": false,
                            "items": [{"count":1, "name": "vodka" }, {"count":1, "name": "vodka" }
                            ]
                        }
                    ]}))
        const {app} = require(appPath)
        let res
        res = await request(app)
            .get(baseUrl)
        expect(res.statusCode).toEqual(200)
        expect(res.body.data).toHaveLength(2)
        expect(res.body[0]).toEqual(expect.not.objectContaining({"items": ["vodka"]}))
        
    })
})

I've tried also to mock the fs in my test, but I guess it doesn't work like this

NEW EDIT AFTER TRY

I've tried now this in the test:

const fs = require( 'fs')
jest.mock('fs')

describe('Get for all Lists with entries', () => {
it('should return a list with 2 entries without items', async () => {
    fs.writeFileSync.mockClear();
    fs.readFileSync.mockReturnValue('X')

  
    const {app} = require(appPath)
    let res
    res = await request(app)
        .get(baseUrl)
    expect(res.statusCode).toEqual(200)
    expect(res.body.data).toHaveLength(2)
    expect(res.body[0]).toEqual(expect.not.objectContaining({"items": 
    ["vodka"]}))
        
       })
    })

But still, when app.js is called with

const {app} = require(appPath)
    let res
    res = await request(app)
        .get(baseUrl)

the method readUpdateData has always at rawData undefined, like the mock is never returend.

function readUpdatedData(){
    let rawData = fileSystem.readFileSync(dataFilePath)
    data = JSON.parse(rawData)
    module.exports = data
    console.log(data)
    console.log('-------------------------')
 }

Upvotes: 0

Views: 1179

Answers (1)

Collin
Collin

Reputation: 409

I've found now a solution

const mockReadFile = jest.spyOn(fs, 'readFileSync')
mockReadFile.mockImplementation(() =>  JSON.stringify({
        "data" : [
            {
                "id": 0,
                "name": "filled shopping list",
                "location": "lidl",
                "targetDate": "22.03.1986",
                "priority": 1,
                "isFinished": false,
                "items": [{"count":1, "name": "vodka" }, {"count":1, "name": "vodka" }
                ]
            }, {
                "id": 1,
                "name": "filled shopping list2",
                "location": "lidl2",
                "targetDate": "22.03.1986",
                "priority": 1,
                "isFinished": false,
                "items": [{"count":1, "name": "vodka" }, {"count":1, "name": 
                "vodka" }
                ]
                }
                ]}))

With this, the data is correctly read from the mock

Upvotes: 0

Related Questions