Build a Cash Register Project - Project works but tests fail

Tell us what’s happening:

My project works perfectly when i manually test it, but fails the website tests. I’ve seen other people with this issue, but I can’t seem to understand how to apply the solutions to my case. I tried debugging, googling, checking my code with AI, but nothing has given me a satistactory fix to my issue. I’m seriously at my wit’s end.

Your code so far

<!-- file: index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cash Register</title>
    <link href="styles.css" rel="stylesheet">
  </head>
  <body>
    <main>
      <h1>Cash Register</h1>
      <input type="number" id="cash">
      <div id="change-due"></div>
      <button id="purchase-btn">Purchase</button>
        <p><strong>Change in drawer:</strong></p>
        <p id="cash-register-p"></p>
    </main>
    <script src="script.js"></script>
  </body>
</html>

/* file: script.js */
let price = 19.5;
let cid = [
  ['PENNY', 1.01],
  ['NICKEL', 2.05],
  ['DIME', 3.1],
  ['QUARTER', 4.25],
  ['ONE', 90],
  ['FIVE', 55],
  ['TEN', 20],
  ['TWENTY', 60],
  ['ONE HUNDRED', 100]
];

class Register {
  constructor(name) {
    this.name = name;
    this.coins = {
      value: {
        PENNY: 0.01,
        NICKEL: 0.05,
        DIME: 0.1,
        QUARTER: 0.25,
        ONE: 1,
        FIVE: 5,
        TEN: 10,
        TWENTY: 20,
        'ONE HUNDRED': 100,
      },
      count: {},
      change: {},
    };
  }

  totalCash() {
    return cid.reduce((amount, coin) => amount + coin[1], 0);
  }

  change() {
    return parseFloat(cashInput.value) - price;
  }

  countCoins() {
    Object.keys(this.coins.value).forEach(coin => {
      const cashInRegister = cid.find(item => item[0] === coin)[1];
      this.coins.count[coin] = Math.floor(cashInRegister / this.coins.value[coin]);
    })
  }

  changeInCoins() {
    let change = this.change();
    for (let i = Object.keys(this.coins.value).length - 1; i >= 0; i--) {
      const coinsInRegisterCount = this.coins.count[cid[i][0]];
      const coinValue = this.coins.value[cid[i][0]];
      const maxNumOfCoins = Math.floor(change / coinValue);

      if (maxNumOfCoins <= coinsInRegisterCount) {
        this.coins.change[cid[i][0]] = maxNumOfCoins;
        this.coins.count[cid[i][0]] -= maxNumOfCoins;
        //{change = change % coinValue} with due adjustments to avoid float calc errors
        change = Math.round((change * 100) % (coinValue * 100)) / 100;
      } else {
        this.coins.change[cid[i][0]] = coinsInRegisterCount;
        this.coins.count[cid[i][0]] -= coinsInRegisterCount;
        change = (change * 100 - cid[i][1] * 100) / 100;
      }
    }
  }

  availableChangeInCoins() {
    this.changeInCoins();
    let result = 0;

    for (const key in this.coins.change) {
      result += this.coins.change[key] * this.coins.value[key];
    }
    return result;
  }

  displayChange() {
    for (let i = Object.keys(this.coins.change).length - 1; i >= 0; i--) {
      const countChangeCoins = this.coins.change[cid[i][0]];
      const coinKey = cid[i][0];
      const coinValue = this.coins.value[cid[i][0]];
      if (countChangeCoins > 0) {
        changeContainer.innerHTML += `${coinKey}: $${countChangeCoins * coinValue}<br>`;
      }
    }
  }

  handleEdgeCases() {
    if (!parseFloat(cashInput.value)) {
      alert('Please enter a valid number');
      return false;
    } else if (parseFloat(cashInput.value) < price) {
      alert('Customer does not have enough money to purchase the item');
      return false;
    } else if (parseFloat(cashInput.value) === price) {
      changeContainer.innerText = "No change due - customer paid with exact cash";
      return false;
    } else if (this.change() > this.totalCash()) {
      changeContainer.innerHTML = `Status: INSUFFICIENT_FUNDS<br>`;
      return false;
    } else if (this.change() <= this.totalCash() && this.change() > this.availableChangeInCoins()) {
      changeContainer.innerHTML = `Status: INSUFFICIENT_FUNDS<br>`;
      return false;
    }
    
    return true;
  }

}

//document objects
const cashInput = document.getElementById('cash');
const purchaseBtn = document.getElementById('purchase-btn');
const changeContainer = document.getElementById('change-due');
const cashRegister = document.getElementById('cash-register-p');

const register = new Register;

const updateCashRegister = (obj) => {
  cashRegister.innerHTML = `Pennies: $${obj['PENNY'] * register.coins.value['PENNY']}<br>
    Nickels: $${obj['NICKEL'] * register.coins.value['NICKEL']}<br>
    Dimes: $${obj['DIME'] * register.coins.value['DIME']}<br>
    Quarters: $${obj['QUARTER'] * register.coins.value['QUARTER']}<br>
    Ones: $${obj['ONE'] * register.coins.value['ONE']}<br>
    Fives: $${obj['FIVE'] * register.coins.value['FIVE']}<br>
    Tens: $${obj['TEN'] * register.coins.value['TEN']}<br>
    Twenties $${obj['TWENTY'] * register.coins.value['TWENTY']}<br>
    Hundreds $${obj['ONE HUNDRED'] * register.coins.value['ONE HUNDRED']}<br>`
};
register.countCoins();
updateCashRegister(register.coins.count);

const eventListenerFun = () => {
  if(register.handleEdgeCases()) {
    changeContainer.innerHTML = `Status: OPEN<br>`;
    updateCashRegister(register.coins.count);
    if (Object.values(register.coins.count).every(value => value === 0)) {
      changeContainer.innerHTML = `Status: CLOSED<br>`;
    }
    register.displayChange();
  }
}

purchaseBtn.addEventListener('click', () => {
  eventListenerFun();
});

cashInput.addEventListener('keydown', event => {
  if (event.key === 'Enter') {
    eventListenerFun();
  }
});

/* file: styles.css */

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36

Challenge Information:

Build a Cash Register Project - Build a Cash Register

Please post your full code

updated it, sorry it’s my first post, i thought it was gonna do it automatically (lol)

Hey, I had this issue and added a semi colon, I know it seems a bit crazy but my code passed after that.

const eventListenerFun = () => { if (register.handleEdgeCases()) { changeContainer.innerHTML = Status: OPEN
; updateCashRegister(register.coins.count); if (Object.values(register.coins.count).every((value) => value === 0)) { changeContainer.innerHTML = Status: CLOSED
; } register.displayChange(); } };

thanks for the suggestion, tried to add the semi column where you suggested but didn’t work, tried to put a bunch more of semicolumns just in case in other spots that might need it but still no luck with passing

Ok, did you try to reset your test yet?

wdym by reset the test? like revert to the saved code? or refreshing the page? or something else?

I would try to refresh at least for now, I`m going to copy your code and run it, do you know how many its missing btw?

it’s almost always missing the last 2 tests. sometimes it also misses the 13th or the 16th or both of them. this adds to the confusion, given that even the fails are not consistent between different tests. i tried refreshing just now but nothing changed

Let’s try to debug!

Let’s add these values at the bottom of the editor:

price = 19.5;
cash.value = 20;
cid =  [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]];

and then press the button.

The output is Status: OPEN QUARTER: $0.5, that doesn’t look like Status: INSUFFICIENT_FUNDS at all.

thank you, I’m starting to understand a bit better the issue. While testing i was changing the values into the original cid, and in this way it works and correctly presents the “INSUFFICIENT_FUNDS” status. But if reassigning the values at the bottom of the editor doesn’t work then there must be some other issue I’m not seeing yet. I still don’t understand exactly how to fix this and why it would work by changing the original cid, but not by reassigning it at the bottom of the editor. Maybe I’m not updating the cid dinamically?

can you figure out if you have things that execute only when the app is started for the first time that capture the cid value?

this is the function that executes when the button is clicked, it has calls to a few functions, what about everything else?

Okay, I think i might have an idea thanks to your input. What I’m thinking is - I have these functions running when the page first loads. The counCoins() one must be specifically important because the other functions rely on the this.coins.count object that this function updates from the cid.

register.countCoins();
updateCashRegister(register.coins.count);

the updateCashRegister is called directly in the event listener function, but not the count coins. I initially thought that it was being called again through the handleEdgeCases() function, but now that I look back at it, that doesn’t seem to be the case. For example, the changeInCoins function accesses directly the this.coins.count object, but doesn’t call on the countCoins() function. Maybe this is the issue?

If they capture values at the app start and do not update later they are certainly the issue

1 Like

For now I’m working on it trying to figure out how to make the cid update later. But I have a question, if this is the issue, wouldn’t that make all the tests fail? aren’t all of them based on reassinging the price and cid at some point?

It depends, 13 fails sometimes.
If the starting cid can make the change happen, then the test will not fail.

You can write the starting cid as let cid = [ ['PENNY', 0], ['NICKEL', 0], ['DIME', 0], ['QUARTER', 0], ['ONE', 0], ['FIVE', 0], ['TEN', 0], ['TWENTY', 0], ['ONE HUNDRED', 0] ];

if the code you are testing is considering those values than it’s not taking the updated cid, and all the Status: OPEN tests will fail

yes, in fact by writing the starting cid as you suggested, all the open status tests do fail. AI noticed a couple of other statuses fail too.

Your feedback has been very helpful so far, at least now I’m understanding where the issue is (tysm :pray:). However I’m still struggling to understand how to fix it. :smiling_face_with_tear:

you need to make everything run when the button is clicked, and everytime that the button is clicked. And they need to take the values that cid and price have at that moment, not an earlier value

1 Like