1

I'm getting a problem while running the test cases using the node.js application where I'm creating a directory if not exists, writing the json and reading the file.

Here's the Working Demo Link

It's throwing the below error even after handling the error in the code. I didn't get much help from other solutions related to Promise rejection in Stackoverflow. Looking for a working solution. I'm getting the below issue after doing npm test:

should reject with an error if the passed data is invalid:

Uncaught TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Promise
  at TypeError.get (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:35:385021)
  at EventEmitter.emit (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:35:143926)
  at process.onGlobalUncaughtException [as _fatalException] (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:35:363886)
  at triggerUncaughtException (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:42:367400)
  at processPromiseRejections (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:35:1794051)
  at processTicksAndRejections (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:35:801887)
  at _0x263935 (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:37:263515)

While doing npm start I'm getting the below problem:

Server running at http://127.0.0.1:3000/
Error: Invalid data
    at writeJSON (file:///home/projects/stackblitz-starters-xzxhal/index.js:70:15)
    at Server.eval (file:///home/projects/stackblitz-starters-xzxhal/index.js:24:15)
TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Promise
    at TypeError.get (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:35:385021)
    at triggerUncaughtException (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:42:367449)
    at processPromiseRejections (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:35:1794051)
    at processTicksAndRejections (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:35:801887)
    at _0x263935 (https://stackblitzstartersxzxhal-cstc.w-credentialless.staticblitz.com/blitz.a19575a2.js:37:263515) {
  code: 'ERR_INVALID_ARG_TYPE'
}

Here's my index.js file code pieces:

const server = http.createServer(async (req, res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    const dirPath = DIR_PATH + dirs[0];
    const filePath = dirPath + './data.json';
    let createdDirectoryIfNotExists = await createDirectoryIfNotExists(filePath);
    if (createdDirectoryIfNotExists) {
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.write(writeJSON('./temp', contents));
        res.end();
    }
});

// write json in file
const writeJSON = async (filePath, contents) => {
    try {
        if (contents && typeof contents === "object") {
            const jsonString = JSON.stringify(contents);
            // write file 
            let isWriteFileSynced = fs.writeFileSync(filePath, jsonString, error => {
                if (error) {
                    console.log(error);
                } else {
                    return jsonString;
                }
            })
            if (isWriteFileSynced) {
                // read file after file is written
                let isReadFileSynced = fs.readFileSync(filePath, "utf8", (error, jsonString) => {
                    if (error) {
                        return false;
                    } else {
                        return jsonString;
                    }
                })

                // if read file, return the jsonString
                if (isReadFileSynced) {
                    return jsonString;
                }
            } else {
                throw new Error("Invalid data");
            }
            return jsonString;
        }
    } catch (error) {
        console.log(error);
        return;
    }

};


// create directory if not exists
const createDirectoryIfNotExists = async (path) => {
    fs.mkdirSync(path, { recursive: true });
    return true;
};

How to solve this issue?

Subhojit
  • 1,389
  • 8
  • 19
  • 33
  • `const writeJSON = async` + `res.write(writeJSON(...)` means you're trying to write a Promise using `res.write` ... so why is `const writeJSON` set to `async` when you use all `sync` fs functions in it and never await anything? ... just get rid of `async` – Jaromanda X Jun 29 '23 at 08:10

1 Answers1

1

That error comes from writeJSON, which returns unresolved Promise, hence the error

So, you need to await it:

res.write(await writeJSON('./temp', contents));

But, as pointed out in the comments, you use sync methods within the function, so no need to return a Promise, so no need to use async on writeJSON function

Also, fs.writeFileSync does not take a callback, and it returns undefined, so the check part will always fail.

It throws, so you need to wrap both fs methods in try/catch, and return json from the try part.

Also, not sure why you read the file afterwards, if it didn't throw, it's written but you can reorganize that:

Here's a starter that should work (somewhat):

const writeJSON = (filePath, contents) => {
  try {
    if (contents && typeof contents === 'object') {

      const jsonString = JSON.stringify(contents);

      // write file
      try {

        fs.writeFileSync(
          filePath,
          jsonString
        );


        // read file after file is written
        let isReadFileSynced = fs.readFileSync(
          filePath,
          'utf8'

        );


        // if read file, return the jsonString
        if (isReadFileSynced) {
          return jsonString;
        }

      } catch (err) {
        console.log(err);
      }


    } else {
      throw new Error('Invalid data');
    }

  } catch (error) {
    console.log(error);
    return;
  }
};

edit

tests passing function:

const writeJSON = async (filePath, contents) => {
 
    if (contents && typeof contents === 'object') {
      const jsonString = JSON.stringify(contents);

      // write file
      try {
        fs.writeFileSync(filePath, jsonString);

        // read file after file is written
        let isReadFileSynced = fs.readFileSync(filePath, 'utf8');

        // if read file, return the jsonString
        if (isReadFileSynced) {
          return jsonString;
        }
      } catch (err) {
        console.log(err);
        // todo
        throw new Error('err writing');
      }
    } else {
      throw new Error('Invalid Data');
    }

};
traynor
  • 5,490
  • 3
  • 13
  • 23
  • Ok. But after applying the solution why its throwing the issue - **TypeError: Cannot read properties of undefined (reading 'catch')** ? – Subhojit Jun 29 '23 at 08:29
  • that's in the test, right? well, as the function does not return a promise, there is no `.catch`, it only returns/throws, so, change the test (expect a string, not to throw etc.): https://stackblitz.com/edit/stackblitz-starters-xzxhal?file=test%2Findex.spec.js%3AL91 – traynor Jun 29 '23 at 08:33
  • Ok. But I don't want to update the test cases. If the function returns a promise how should it be? – Subhojit Jun 29 '23 at 08:40
  • right, now every test will fail.. well, quick and dirty: return a promise: add `async` to `writeJSON`, and await it in `res.write(await writeJSON('./temp', contents));` – traynor Jun 29 '23 at 08:47
  • 1
    you've got an extra `try/catch` now, try removing the first, it should start with `if (contents && typeof contents === 'object') {..`, and also add a throw for new read/write errors – traynor Jun 29 '23 at 08:59
  • try the updated function, the tests should pass – traynor Jun 29 '23 at 09:06
  • Thanks. Its working. I was not able to get where I was going wrong. But now I got to understand it from the solution. Thanks again @traynor. – Subhojit Jun 29 '23 at 09:26
  • 1
    great. another aproach to keep the promise, is that your initial code might have used promisified fs methods, instead of sync, and then resolve/reject from the callbacks, see [Using filesystem in node.js with async / await](https://stackoverflow.com/questions/40593875/using-filesystem-in-node-js-with-async-await) – traynor Jun 29 '23 at 09:33
  • Nice. This approach looks cool too! – Subhojit Jun 29 '23 at 09:36