Issue with backgroundProcess Function in Asynchronous Tests. JavaScript

I’m currently working on an asynchronous function backgroundProcess that processes items produced by a producer function and consumes them with a consumer function. However, I’m encountering an issue with the status management of the process. Specifically, one of my tests fails when checking if the status is Running while the process is being executed.

Here’s a simplified version of the backgroundProcess function:

/**
 * Exercise 6, 1.5 points
 *
 * @param {()=>Promise} produce
 * @param {(data:any)=>Promise} consume
 * @returns
 */
export function backgroundProcess(produce, consume) {
  let available = []
  let totalProduced = 0
  let status = 0 // 0 = Idle, 1 = Running, 2 = Finished
  let intervalId
  let isFirstCall = true
  let hasStarted = false

  const startProcess = async () => {
    if (hasStarted) return // Prevent starting if it's already running
    status = 1 // Change status to Running
    hasStarted = true

    intervalId = setInterval(async () => {
      try {
        const products = await produce()

        if (products === null) {
          clearInterval(intervalId)
          status = 2 // Change status to Finished
          return
        }

        for (const product of products) {
          const consumed = await consume(product)
          available.push(consumed)
          totalProduced++
        }
      } catch (error) {
        // Handle error if needed
        console.error('Error in producing or consuming:', error)
      }
    }, 100)
  }

  return function getStatus() {
    if (isFirstCall && !hasStarted) {
      isFirstCall = false
      return {
        available: [],
        totalProduced: 0,
        status: 0,
      }
    }

    if (status === 0) {
      startProcess() // Start the process if it's idle
    }

    const result = {
      available: [...available],
      totalProduced,
      status,
    }

    available = [] // Clear available after each invocation
    return result
  }
}

And here’s the relevant test that is failing:

test('It should have status=1 if the process is being executed', async () => {
    const array = [[1, 2, 3], [4, 5, 6], [7, 8, 9], null]
    const producer = createProducer(array)
    const fn = backgroundProcess(producer, defaultConsumer())

    await sleep(MAX_MS)
    const result = fn()
    expect(result.status).toBe(STATUSES.Running)
  })

My package.json includes:

src/pec3/pec3.test.js
  backgroundProcess
    √ It should return an async function (2 ms)
    √ It should return the right structure after invoking returned function (1 ms)
    √ It should finish in a finite amount of time (373 ms)
    √ It should call producer the right amount of times (691 ms)
    √ It should call consumer the right amount of times (463 ms)
    √ It should clear the production queue after each invocation of the resulting function (782 ms)
    √ It should count the number of products produced in background (931 ms)                            
    × It should have status=0 if the process has not been started yet (2 ms)                            
    √ It should have status=1 if the process is being executed (111 ms)                                 
    √ It should have status=2 if the process has finished (248 ms)                                      
                                                                                                        
  ● backgroundProcess › It should have status=0 if the process has not been started yet                 
                                                                                                        
    expect(received).toBe(expected) // Object.is equality                                               
                                                                                                        
    Expected: 0                                                                                         
    Received: 1                                                                                         
                                                                                                        
      211 |   test('It should have status=0 if the process has not been started yet', async () => {     
      212 |     const fn = backgroundProcess(defaultProducer(), defaultConsumer())
    > 213 |     expect(fn().status).toBe(STATUSES.Idle)
          |                         ^
      214 |
      215 |     await processCompleted(fn)
      216 |   })

      at Object.<anonymous> (src/pec3/pec3.test.js:213:25)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 9 passed, 10 total
Snapshots:   0 total
Time:        5.339 s, estimated 6 s
Ran all test suites.

I have verified that the producer and consumer functions are set up correctly, but it seems that the status remains Idle when it should be Running.

My package.json includes:

{
  "name": "pec-0-sol",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/user-event": "^13.5.0",
    "pec-0-sol": "file:",
    "react-scripts": "5.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

I suspect that there may be a timing issue related to how the setInterval is functioning or how the status is being updated. Can anyone help me identify the root cause of this issue?

Feel free to adjust any details to fit your style better. Once you’re satisfied with the question, you can post it on Stack Overflow to get help from the community!