VS Code debugger not working as expected while debugging Nodejs app

Viewed 211

I am debugging a node app and it has a method deleteProduct. Inside this method is two static methods Cart.deleteProductFromCart(productID, product.price) and Product.deleteProductWithId(productID) that read files from the filesystem and write to the file.

Using the VSCode built-in debugger, When I set the breakpoints to see if the callbacks are getting called back properly, only the callback fired from the first method gets registered whereas the callback from the second method never gets called. I also experimented by changing the order of the two methods. And, the result is that only the method which gets called first has its callback registered whereas the callback from the second method is never called. This happens only during the debug session. The program runs as expected with yarn start though.

So, it's really hard to debug the whole process.

I am not sure if this is an issue with the vs-code debugger or something I am doing wrong due to which the callback is not being registered during the debugging process.

URL to the repository is attached here

enter image description here

const deleteProduct = async (req, res, next) => {
  const productID = req.params.productID;

  const product = await Product.fetchProductWithId(productID);

  Cart.deleteProductFromCart(productID, product.price);
  Product.deleteProductWithId(productID);

  res.redirect(301, '/products');
};

Cart Model

const fs = require('fs');
const path = require('path');

const rootDir = require('../utils/path');

const filePath = path.join(rootDir, 'data', 'cart.json');

class Cart {
  static addProduct(productID, productPrice) {
    fs.readFile(filePath, (err, data) => {
      let cart = { items: [], totalPrice: 0 };

      if (!err && data?.length > 0) {
        cart = JSON.parse(data);
      }

      const existingProduct = cart.items.find((item) => item.id === productID);

      if (existingProduct) {
        existingProduct.quantity++;
      } else {
        const product = { id: productID, quantity: 1 };
        cart.items.push(product);
      }

      cart.totalPrice = cart.totalPrice + +productPrice;
      console.log(existingProduct === cart.items[0]);

      fs.writeFileSync(filePath, JSON.stringify(cart));
    });
  }

  // Delete logic
  static deleteProductFromCart(productID, productPrice) {
    fs.readFile(filePath, (err, data) => {
    
    // Attached breakpoints within this callback
      if (err) {
        return;
      }

      const cart = JSON.parse(data);
      const product = cart.items.find((item) => item.id === productID);

      if (product) {
        cart.totalPrice = cart.totalPrice - product.quantity * +productPrice;
        cart.items = cart.items.filter((item) => item.id !== productID);
      }

      fs.writeFileSync(filePath, JSON.stringify(cart));
    });
  }
}

module.exports = { Cart };

Product Model

const fs = require('fs');
const path = require('path');
const { v4: uuidv4 } = require('uuid');

const rootDir = require('../utils/path');

const filePath = path.join(rootDir, 'data', 'products.json');

class Product {
  constructor(id, title, price, imageURL, description) {
    this.id = id;
    this.title = title;
    this.price = price;
    this.imageURL = imageURL;
    this.description = description;
  }

  save() {
    fs.readFile(filePath, (err, data) => {
      let products = [];

      if (!err && data.length > 0) {
        products = JSON.parse(data);
      }

      if (this.id) {
        const productIndex = products.findIndex((item) => item.id === this.id);
        products[productIndex] = this;
      } else {
        this.id = uuidv4();
        products.push(this);
      }

      fs.writeFileSync(filePath, JSON.stringify(products));
    });
  }

  static deleteProductWithId(id) {
    fs.readFile(filePath, (err, data) => {
    
    // Attached callback within this callback
      let products = [];

      if (!err && data.length > 0) {
        products = JSON.parse(data);
      }

      const productIndex = products.findIndex((item) => item.id === id);
      products.splice(productIndex, 1);

      fs.writeFileSync(filePath, JSON.stringify(products));
    });
  }

  static async fetchProductWithId(id) {
    return new Promise((resolve, reject) => {
      try {
        fs.readFile(filePath, (err, data) => {
          if (data) {
            const products = JSON.parse(data);
            const product = products.find((item) => item.id === id);

            resolve(product);
          }
          resolve({
            id: null,
            title: 'null',
            price: 0,
            description: null,
            imageURL: null,
          });
        });
      } catch {
        reject(err);
      }
    });
  }

  static async fetchAll() {
    return new Promise((resolve, reject) => {
      try {
        fs.readFile(filePath, (err, data) => {
          if (data.length > 0) {
            resolve(JSON.parse(data));
          }
          resolve([]);
        });
      } catch {
        reject(err);
      }
    });
  }
}

module.exports = { Product };

lauch.json file

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "pwa-node",
      "request": "launch",
      "name": "Launch Program",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/app.js",
      // Auto Restart Debugger on file Change
      // nodemon should be installed globally
      // Also integrated console should be used so that they both listen to same port or something like that
      "restart": true,
      "runtimeExecutable": "nodemon",
      "console": "integratedTerminal"
    }
  ]
}

To Reproduce

Steps to reproduce the behavior:

  1. Attach breakpoints inside callback of readFile as shown in the snippet in both the static methods
  2. Run the debugger
  3. Observe Callstack or Run Step Over, Step Into to see the program flow
  4. Observe that callback from the second method which read file from the filesystem is never reached till the end of program execution.
0 Answers
Related