简体   繁体   中英

Node dependency container doesn't work as expected

I have a DI container like this:

# di-container.js
const container = {
    fileReader: require("./file-reader"),
    csvReader: require("./csv-reader"),
}

module.exports = {
    container
}

And csv-reader.js looks like this:

# csv-reader.js
const { container } = require("./di-container")

async function readFileAsCSV(path)
    const fileContents = await container.fileReader.readFileContents(path)
    return fileContents.split("\n")
                       .map(line => line.split(","))
}

I have a test file csv-reader.spec.js :

# csv-reader.spec.js
const { container } = require("./di-container")

describe("csvReader", () => {
    it("should read cells from file", async () => {
        const fakeCSV = "\"Name\",\"Age\"\n\"Bob Smith\",\"32\""
        container.fileReader.readFileContents = (_) => fakeCSV

        const result = container.csvReader.readFileAsCSV()

        # Do some assertions...
    })
})

When running the test it fails with the error (stack trace line numbers different as the example is slightly different):

TypeError: Cannot read property 'fileReader' of undefined
 at Object.readFileAsCSV (csv-reader.js:8:42)
 at Context.it (csv-reader.spec.js:15:44)
 at processImmediate (internal/timers.js:443:21)

I expected that the memory reference to container is the same in csv-reader.spec.js and csv-reader.js , so I should be able to change container.fileReader.readFileContents and csv-reader will use the mock function.

If I remove the csvReader: require("./csv-reader") line from di-container.js and use const csvReader = require("./csv-reader") in csv-reader.spec.js , then the test passes. This would suggest some oddity with the order in which the dependencies in container are being created.

I have tried rearranging the order of fileReader and csvReader in container , and changing them to be like container.fileReader = ... instead of inline instantiation but that did not work.jav

You have a dependency module cycle .

Your di-container.js file requires csv-reader.js and csv-reader.js file requires di-container.js which forms a cycle.

Because of this, require("./di-container") returns null inside the csv-reader.js file. Because require("./di-container") is null , The destructured container will be undefined. And thus, your are getting the error which you mentioned.

You need to redesign your functions and might want to think about where do you want to put them.


On very broad level, just separate out the functions which are to be used in both the files and put them inside common.js

Then, require common.js inside csv-reader.js and di-container.js


If I remove the csvReader: require("./csv-reader") line from di-container.js and use const csvReader = require("./csv-reader") in csv-reader.spec.js, then the test passes. This would suggest some oddity with the order in which the dependencies in container are being created.

The cycle broke once you did not require csv-reader.js from the di-container.js and hence it is working just fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM