0

I am trying to get some unit tests set up using Mocha.js and Chai, one of the tests I am trying to make is to check to see if a json file has been created after a class in an external file is called.

const chai = require('chai');
chai.use(require('chai-json'));
const DataHandler = require('../handler');
const expect = require('chai').expect;
const path = require('path')

const handler = new DataHandler();

describe('#json handling', function(){
    it('should create a testData.json file', function(){
        const json = path.basename('../testData.json');
        expect(json).to.be.a.jsonFile();
    })
})

The tests are successful if I run them a second time as the testData.json file is created after the first tests are completed. This however shouldn't be the case and the json file should be created even before the test is run when new DataHandler is initialised

This is the first part of my DataHandler class that creates/updates the json file is as follows

class DataHandler{

    constructor(){
        if(this.shouldUpdate()) {this.update()};
    }

    shouldUpdate(){
        if(!fs.existsSync("testData.json")) {return true};

        const file = fs.readFileSync("testData.json");
        const parsed = JSON.parse(file)
        const oldDT = Date.parse(parsed['updated_date']);

        const dateDifference = Date.now() - oldDT;
        const minutes = Math.floor(dateDifference / 60000);

        if (minutes > 2) {return true};
    }

    update(){
        request("http://someurl.com/data.json", function (error, response, body) {
            if (!error && response.statusCode == 200) {
                const parsedJSON = JSON.parse(body);
                parsedJSON['updated_date'] = new Date();
                const json = JSON.stringify(parsedJSON);
                fs.writeFileSync("testData.json", json);
            }
        })

    }
}
hcphoon
  • 538
  • 5
  • 24
  • The path.basename() method returns the filename part of a file path. It has nothing to d with whether file is created or not. It just returns file name part of the given path. In your case ` const json = path.basename('../testData.json');` returns **testData.json** – vipul patel Oct 09 '19 at 12:31
  • @vipulpatel I know that, that is not my issue – hcphoon Oct 09 '19 at 12:34
  • Could you please show, how file is created in `DataHandler`? I guess, that you have ran into an issue with asynchronous execution, and there is no wait until file will being created. – kernel72 Oct 09 '19 at 12:40
  • @kernel72 added to the origional post – hcphoon Oct 09 '19 at 12:44
  • @hcphoon Curiosity : if that returns file name in path then how come `expect(json).to.be.a.jsonFile();` assertions works. Should not be like just simple string comparision `expect(json).to.be.eqial.to("testData.json");` – vipul patel Oct 09 '19 at 13:06

1 Answers1

0

You create file asynchronously in update() method (request is async function), but your test executes synchronously and doesn't wait file for creation. You have to wait it.

As an example. Move your init code out of constructor and call it separately

const fs = require("fs").promises;

class DataHandler {
  async init() {
    if (this.shouldUpdate()) {
      await this.update();
    }
  }

  async shouldUpdate() {
    const isExist = await fs.stat("testDate.json");
    if (!isExist) {
      return true;
    }

    const file = await fs.readFile("testData.json");
    const parsed = JSON.parse(file);
    const oldDT = Date.parse(parsed["updated_date"]);

    const dateDifference = Date.now() - oldDT;
    const minutes = Math.floor(dateDifference / 60000);

    if (minutes > 2) {
      return true;
    }
  }

  async update() {
    const response = await request("http://someurl.com/data.json");

    if (response.statusCode == 200) {
      const parsedJSON = JSON.parse(body);
      parsedJSON["updated_date"] = new Date();
      const json = JSON.stringify(parsedJSON);
      await fs.writeFile("testData.json", json);
    }
  }
}

and test

const handler = new DataHandler();

describe('#json handling', function(){
    it('should create a testData.json file', async function(){
        await handler.init()
        const json = path.basename('../testData.json');
        expect(json).to.be.a.jsonFile();
    })
})

Something like that

kernel72
  • 89
  • 6
  • How would I do this? – hcphoon Oct 09 '19 at 13:00
  • You can ,for example, use sync version of `request` (for example ,https://www.npmjs.com/package/sync-request), so that will make your code fully synchoronous, and test should start working. But using sync code in node.js is not good practice. If you want to avoid bad practices, you have to rewrite code to use async versions of functions which work with files. – kernel72 Oct 09 '19 at 13:13
  • Ok that works for now thank you, how would you recommend rewriting my code to use async versions? I have looked into using promises as pointed out in this thread https://stackoverflow.com/questions/8775262/synchronous-requests-in-node-js but it did not work for me – hcphoon Oct 09 '19 at 13:37