Build a Cash Register Project - Can't pass tests 9 to 19

My code performs as expected but doesn’t pass the tests:

Hey everyone, this is my first time posting here. I’m usually able to dig out of my own mess, but I’m legitimately stuck here for more than two weeks.

My code works very well on the preview and console, but when I try to pass the tests it doesn’t work from tests 9 to 19.

Could anyone point me in the right direction to correct any mistakes?

Thank you all in advance.

My code so far

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Cash Register Project for FreeCodeCamp" />
    <title>Cash Register App</title>
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <header>
      <img alt="American flag" src="https://upload.wikimedia.org/wikipedia/en/thumb/a/a4/Flag_of_the_United_States.svg/320px-Flag_of_the_United_States.svg.png" class="flag">
      <h1>Cash Register App</h1>
      <img alt="triangular logo" src="https://static.wixstatic.com/media/297896_47a9276413e44a36936ef7d403a5aa96~mv2.png/v1/fill/w_3152,h_2746,al_c,q_95,usm_0.66_1.00_0.01,enc_auto/MASTERIZED%20copie%202.png">
    </header>
    <main>
      <div id="input-div">
        <h3 id="price">Product Price: $</h3>
        <label for="cash"><h2>Enter money</h2></label>
        <input id="cash" type="number" value> 
        <button id="purchase-btn">Pay</button>
        <button id="reset-btn">Reset</button>
      </div>  
      <div id="change-due-container">
        <h2>Change</h2>
        <p id="change-due"></p>
      </div>  
      <div id="cash-register">
        <h2>Money in drawer</h2>
        <div id="register-coins">
          <ol>
            <li class="coin">
              <figure>
                <img src="https://www.usmint.gov/content/dam/usmint/coins/circulating-coins/2024-lincoln-penny-proof-obverse.jpg">
                <figcaption>Penny</figcaption>
              </figure>
              <span class="currency">$1.01</span>
            </li>
            <li class="coin">
              <figure>
                <img src="https://www.usmint.gov/content/dam/usmint/coins/circulating-coins/2024-jefferson-nickel-proof-obverse.jpg">
                <figcaption>Nickel</figcaption>
              </figure>
              <span class="currency">$2.05</span>
            </li>
            <li class="coin">
              <figure>
                <img src="https://www.usmint.gov/content/dam/usmint/coins/circulating-coins/2024-roosevelt-dime-proof-obverse.jpg">
                <figcaption>Dime</figcaption>
              </figure>
              <span class="currency">$3.1</span>
            </li>
            <li class="coin">
              <figure>
                <img src="https://www.usmint.gov/content/dam/usmint/coins/50-state-quarters/2004-50-state-quarters-coin-uncirculated-obverse.jpg">
                <figcaption>Quarter</figcaption>
              </figure>
              <span class="currency">$4.25</span>
            </li>
          </ol>
        </div>
        <div id="register-bills">
          <ol>
            <li class="bill">
              <figure>
                <img src="https://www.uscurrency.gov/sites/default/files/styles/bill_version/public/denominations/1_1963-present-front-1_0.jpg.webp?itok=4Y3M6xCA">
                <figcaption>One Dollar</figcaption>
              </figure>
              <span class="currency">$90</span>
            </li>
            <li class="bill">
              <figure>
                <img src="https://www.uscurrency.gov/sites/default/files/styles/bill_version/public/denominations/%245-FRN-2021-face.png.webp?itok=RcxNac5p">
                <figcaption>Five Dollars</figcaption>
              </figure>
              <span class="currency">$55</span>
            </li>
            <li class="bill">
              <figure>
                <img src="https://www.uscurrency.gov/sites/default/files/styles/bill_version/public/denominations/10_2006-present-front-v2.1-jpg.jpg.webp?itok=V3yT8Jl8">
                <figcaption>Ten Dollars</figcaption>
              </figure>
              <span class="currency">$20</span>
            </li>
            <li class="bill">
              <figure>
                <img src="https://www.uscurrency.gov/sites/default/files/styles/bill_version/public/denominations/20_2003-present-front.jpg.webp?itok=GcGWp1CN">
                <figcaption>Twenty Dollars</figcaption>
              </figure>
              <span class="currency">$60</span>
            </li>
            <li class="bill">
              <figure>
                <img src="https://www.uscurrency.gov/sites/default/files/styles/bill_version/public/denominations/100-front-2013-present.jpg.webp?itok=tVYD2VJT">
                <figcaption>Hundred Dollars</figcaption>
              </figure>
              <span class="currency">$100</span>
            </li>
          </ol>
        </div>
      </div>
    </main>
    <script src="script.js"></script>
  </body>
</html>
const changeDue = document.getElementById("change-due"); 
const cash = document.getElementById("cash"); 
const purchaseBtn = document.getElementById("purchase-btn"); 
const resetBtn = document.getElementById("reset-btn");  
const currency = document.querySelectorAll(".currency"); 
const originalCid = [1.01, 2.05, 3.1, 4.25, 90, 55, 20, 60, 100];

let price = 1.87;
let change = [];
let newCid = [];
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]
];


const isChangeDue = (paidAmount, priceOfPurchase) => {
  const paid = Math.round(Number(paidAmount) * 100);
  const price = Math.round(Number(priceOfPurchase) * 100);
  if(paidAmount.trim() === "" || isNaN(paid) || paidAmount < 0){
    alert("Please insert a Valid Number");
    return true
  } else if  (price > paid) {
    alert("Customer does not have enough money to purchase the item");
    return true
  } else if (price === paid) {
    changeDue.innerText = "No change due - customer paid with exact cash";
    console.log(changeDue);
    return true
  };
};

const calculateChange = (paidAmount, priceOfPurchase) => {  
  const valueX100 = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];
  const cashX100 = Math.round(paidAmount * 100);
  const priceX100 = Math.round(priceOfPurchase * 100);
  let differenceX100 = cashX100 - priceX100;
  
  for(let i = cid.length - 1; i >= 0; i--){
    let cidX100 = Math.round(cid[i][1] * 100); 
    let name = cid[i][0];
    
    let maxUnits = Math.floor((differenceX100) / valueX100[i]);
    let availableUnits = Math.floor(cidX100 / valueX100[i]);
    let unitsToUse = Math.min(maxUnits, availableUnits);
    let changeX100 = (unitsToUse * valueX100[i]);
    
    differenceX100 -= changeX100;
    newCid.unshift((cidX100 -= changeX100) / 100);
    change.unshift([name, (changeX100 / 100)]);
  }

  if (differenceX100 !== 0) {
    changeDue.innerText = "Status: INSUFFICIENT_FUNDS";
    console.log(changeDue.innerText);
    change = [];
    return false
  };

  return change;
};

const updateRegister = () => {   
  let previousCid = cid.map(item => [...item]);

  for (let i = 0; i < cid.length; i++) {  
    cid[i][1] = newCid[i]

    currency[i].textContent = `$${cid[i][1]}`; 
    currency[i].style.color 
    = cid[i][1] === previousCid[i][1]
    ? "var(--detail5)" 
    : "var(--detail3)"; 

    previousCid[i][1] = cid[i][1];
  };
};

const showChangeDue = () => {
  const totalCidAfterChange = cid.reduce((sum, item) => sum + item[1], 0);
  changeDue.innerText = "";

  changeDue.innerText 
  = totalCidAfterChange === 0
  ? `Status: CLOSED`
  : `Status: OPEN`;

  const changeFilter = change.filter(item => item[1] != 0).reverse();
  changeDue.innerText += changeFilter
    .map(
      item => ` ${item[0]}: $${item[1]}`
      )
    .join("");

  return
};

window.onload = function () {document.getElementById("price").innerText += price};

resetBtn.addEventListener("click", () => {
  changeDue.innerText = "";
  cash.value = "";
  change = [];

  for (let i = 0; i < cid.length; i++) {
    cid[i][1] = originalCid[i];
    currency[i].textContent = `$${cid[i][1]}`; 
    currency[i].style.color = "var(--detail5)";
  }
});

purchaseBtn.addEventListener("click", (e) =>{
  e.preventDefault();
  change = [];

  if (isChangeDue(cash.value, price)) return
  if (!calculateChange(cash.value, price)) return 

  updateRegister();
  showChangeDue();
  });
* { 
  box-sizing: border-box;
  margin: 0;
  padding: 0; 
}

:root {
  font-size: 62.5%;
  --tier1: #002654;
  --tier2: #FFFFFF;
  --tier3: #ED2939;
  --detail1: #002654;
  --detail2: #FFFFFF;
  --detail3: #ED2939;
  --detail4: #1a1a1a;
  --detail5: #77aa77;
}

html { 
  scroll-behavior: smooth;
  overflow-x: hidden;
}

body {
  min-height: 100vh;
  gap: 3rem;
}

/* Header Styles */
header {
  width: 100%;
  height: 17rem;
  background-color: var(--tier1);
  z-index: 1000;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 2rem;
}

header .flag {
  max-height: 4rem;
  margin-right: 1rem;
}

header img:not(.flag) {
  max-height: 5rem;
  margin-right: 1rem;
}

/* Typography */
h1, h2, h3 {
  font-family: Optima, sans-serif;
  color: var(--detail2);
}

h1 {
  font-size: 5rem;
  font-weight: 600;
}

h2 {
  font-size: 4rem;
  color: var(--detail3);
}

h3 {
  font-size: 2.5rem;
  font-weight: 300;
  color: var(--detail1);
}


p {
  font-family: Verdana, sans-serif;
  color: var(--detail4);
  font-size: 1.8rem;
  padding: 1rem;
  border-bottom: 1px solid var(--detail4);
  line-height: 2.2rem;
  letter-spacing: 1%;
  word-spacing: 1%;
  text-indent: 0;
  white-space: normal;
  text-align: left;
}

/* Main Layout - Mobile First */
main {
  display: grid;
  grid-template-areas: 
    "customer change-due"
    "cash-register cash-register";
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 2fr;
  gap: 1rem;
  width: 90%;
  margin: 3rem auto 0 auto;
  padding: 0;
}

/* Customer Input Section */
#customer { 
  background: var(--tier4);
  border-radius: 1rem;
  padding: 2rem;
  box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.1);
  grid-area: customer;
  border: 2px solid var(--detail1);
  max-height: 40rem;
  min-width: 400px;
  display: grid;
  grid-template-areas: "label label" 
    "price price" 
    "input input" 
    "button1 button2";
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto auto 1fr auto;
  place-content: space-between;
  place-items: stretch;
  gap: 1rem;
}

/* Change Due Section */
#change-due-container {
  border: 1px solid var(--detail3);
  border-radius: 7px;
  grid-area: change-due;
  padding: 1rem;
  box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.1); 
  max-height: 40rem;
  overflow-y: auto; 
  overflow-x: hidden; 
  white-space: nowrap; 
  display: flex; 
  flex-direction: column;
  gap: 0.5rem; 
  align-items: top; 
  justify-content: left;
}

/* Cash Register Section */
#cash-register {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  grid-area: cash-register;
  width: 100%;
  border: 2px solid var(--detail1);
  border-radius: 1rem;
}

/*customer Elements */
#customer label {
  display: block;
  font-weight: bold;
  color: var(--detail1);
  font-size: 4.5rem;
  grid-area: label;
}

#price {
  grid-area: price;
}

#cash {
  padding: 4rem 2rem;
  border: 0.2rem solid var(--detail1);
  height: 100%;
  border-radius: 1rem;
  font-size: 4rem;
  background: var(--tier2);
  color: var(--detail4);
  grid-area: input;
}

button {
  border-radius: 1rem;
  cursor: pointer;
  font-size: 4rem;
  transition: background-color 0.3s, transform 0.2s;
}

#purchase-btn {
  border: 0.2rem solid var(--detail1);
  background-color: var(--tier1);
  color: var(--detail2);
  grid-area: button1;
}

#reset-btn {
  border: 0.2rem solid var(--detail1);
  background-color: var(--tier2);
  color: var(--detail4);
  grid-area: button2;
}

button:hover {
  opacity: 0.8;
  transform: scale(1.05);
}

/* register-coins + register-bills grid */
#cash-register h2 {
  text-align: center;
}

#register-coins ol,
#register-bills ol {
  display: grid;
  grid: auto-flow / 1fr 1fr;
  gap: 2;
  place-content: center;
  place-items: center;
  padding: 2rem;
  list-style: none;
}

#register-coins li,
#register-bills li {
  display: flex;
  align-items: center;
  flex-direction: row;
}

#register-coins img,
#register-bills img {
  width: auto;
  height: 100px;
  object-fit: contain;
  display: block;
  margin: 0 auto;
}

#register-coins figcaption,
#register-bills figcaption {
  text-align: center;
  font-size: 2.4rem; 
  color: var(--detail4);
  margin-top: 0.5rem;
}

.currency {
  color: var(--detail5);
  font-size: 2.8rem; 
  margin-left: 1rem;
  flex-shrink: 0;
  font-weight: 600;
}

.hidden {
  visibility: hidden;
}

/* Desktop Layout - Media Query */
@media screen and (min-width: 1024px) {
  main {
    grid-template-areas: 
      "customer cash-register"
      "change-due cash-register";
    grid-template-columns: 1fr 2fr;
    grid-template-rows: 1fr 1fr;
    gap: 1rem;
    width: 90%; 
    margin: 3rem auto 3rem auto; 
  }

  #customer {
    padding: 4rem 2rem;
  }

  #change-due-container {
    padding: 4rem 2rem;
  }

  #cash {
    padding: 2.5rem;
    font-size: 2.5rem;
  }

  button {
    padding: 2.5rem 5rem;
    font-size: 2.5rem;
  }
}

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15

Challenge Information:

Build a Cash Register Project - Build a Cash Register

Tests 9 to 19:

    1. When price is 11.95 and the value in the #cash element is 11.95, the value in the #change-dueelement should be "No change due - customer paid with exact cash".
    1. When the value in the #cash element is equal to price, the value in the #change-due element should be "No change due - customer paid with exact cash".
    1. When price is 19.5, the value in the #cash element is 20, cid is [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]], and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: OPEN QUARTER: $0.5".
    1. When price is 3.26, the value in the #cash element is 100, cid is [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]], and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: OPEN TWENTY: $60 TEN: $20 FIVE: $15 ONE: $1 QUARTER: $0.5 DIME: $0.2 PENNY: $0.04".
    1. When price is less than the value in the #cash element, total cash in drawer cid is greater than the change due, individual denomination amounts allows for returning change due, and the #purchase-btnelement is clicked, the value in the #change-due element should be "Status: OPEN" with required change due in coins and bills sorted in highest to lowest order.
    1. When price is 19.5, the value in the #cash element is 20, cid is [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]], and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: INSUFFICIENT_FUNDS"
    1. When the price is less than the value in the #cash element and the total cash in the drawer (cid) is insufficient to cover the change due, the purchase should not proceed. When the #purchase-btn is clicked under these conditions, the #change-due element should display "Status: INSUFFICIENT_FUNDS".
    1. When price is 19.5, the value in the #cash element is 20, cid is [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]], and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: INSUFFICIENT_FUNDS".
    1. When price is less than the value in the #cash element, total cash in drawer cid is greater than change due, but the individual denomination amounts make it impossible to return needed change, when the #purchase-btn element is clicked, the value in the #change-due element should be "Status: INSUFFICIENT_FUNDS"
    1. When price is 19.5, the value in the #cash element is 20, cid is [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]], and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: CLOSED PENNY: $0.5".
    1. When price is less than the value in the #cash element, total cash in drawer cid is equal to change due, and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: CLOSED" with change due in coins and bills sorted in highest to lowest order.

Your function needs to be called multiple times in a row and still work. If you have global variables, they will not be reset each time the function is called.

You should only have price and cid as global variables.

Your code contains global variables that are changed each time the function is run. This means that after each function call completes, subsequent function calls start with the previous value. To fix this, make sure your function doesn’t change any global variables, and declare/assign variables within the function if they need to be changed.

Example:

var myGlobal = [1];
function returnGlobal(arg) {
  myGlobal.push(arg);
  return myGlobal;
} // unreliable - array gets longer each time the function is run

function returnLocal(arg) {
  var myLocal = [1];
  myLocal.push(arg);
  return myLocal;
} // reliable - always returns an array of length 2

Thank you for your reply!

I’ve been working on a solution to these global variables because I’ve read on another post those might be the issue.

I’ve moved the newCid and change variables inside the calculateChange function, but it didn’t work.

I returned those two variables inside an object which I destructured in the eventListesner. But even so the tests 9 to 19 won’t go through.

Any other ideas? When can we start questioning the tests? :sweat_smile:

const changeDue = document.getElementById("change-due"); 
const cash = document.getElementById("cash"); 
const purchaseBtn = document.getElementById("purchase-btn"); 
const resetBtn = document.getElementById("reset-btn");  
const currency = document.querySelectorAll(".currency"); 
const originalCid = [1.01, 2.05, 3.1, 4.25, 90, 55, 20, 60, 100];

let price = 1.87;
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]
];

const isChangeDue = (paidAmount, priceOfPurchase) => {
  const paid = Math.round(Number(paidAmount) * 100);
  const price = Math.round(Number(priceOfPurchase) * 100);
  if (paidAmount.trim() === "" || isNaN(paid) || paidAmount < 0) {
    alert("Please insert a Valid Number");
    return true;
  } else if (price > paid) {
    alert("Customer does not have enough money to purchase the item");
    return true;
  } else if (price === paid) {
    changeDue.innerText = "No change due - customer paid with exact cash";
    console.log(changeDue);
    return true;
  }
};

const calculateChange = (paidAmount, priceOfPurchase) => { 
  let change = [];
  let newCid = [];

  const valueX100 = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];
  const cashX100 = Math.round(paidAmount * 100);
  const priceX100 = Math.round(priceOfPurchase * 100);
  let differenceX100 = cashX100 - priceX100;
  
  for (let i = cid.length - 1; i >= 0; i--) {
    let cidX100 = Math.round(cid[i][1] * 100); 
    let name = cid[i][0];
    
    let maxUnits = Math.floor(differenceX100 / valueX100[i]);
    let availableUnits = Math.floor(cidX100 / valueX100[i]);
    let unitsToUse = Math.min(maxUnits, availableUnits);
    let changeX100 = unitsToUse * valueX100[i];
    
    differenceX100 -= changeX100;
    newCid.unshift((cidX100 - changeX100) / 100);
    change.unshift([name, changeX100 / 100]);
  }

  if (differenceX100 !== 0) {
    changeDue.innerText = "Status: INSUFFICIENT_FUNDS";
    console.log(changeDue.innerText);
    return false;
  }

  return { change, newCid };
};

const updateRegister = (newCid) => {   
  let previousCid = cid.map(item => [...item]);

  for (let i = 0; i < cid.length; i++) {  
    cid[i][1] = newCid[i];
    currency[i].textContent = `$${cid[i][1]}`; 
    currency[i].style.color = cid[i][1] === previousCid[i][1]
      ? "var(--detail5)" 
      : "var(--detail3)"; 
  }
};

const showChangeDue = (change) => {
  const totalCidAfterChange = cid.reduce((sum, item) => sum + item[1], 0);
  changeDue.innerText = "";

  changeDue.innerText = totalCidAfterChange === 0
    ? "Status: CLOSED"
    : "Status: OPEN";

  const changeFilter = change.filter(item => item[1] !== 0).reverse();
  changeDue.innerText += changeFilter
    .map(item => ` ${item[0]}: $${item[1]}`)
    .join("");

  return;
};

window.onload = function () {
  document.getElementById("price").innerText += price;
};

resetBtn.addEventListener("click", () => {
  changeDue.innerText = "";
  cash.value = "";

  for (let i = 0; i < cid.length; i++) {
    cid[i][1] = originalCid[i];
    currency[i].textContent = `$${cid[i][1]}`; 
    currency[i].style.color = "var(--detail5)";
  }
});

purchaseBtn.addEventListener("click", (e) => {
  e.preventDefault();

  if (isChangeDue(cash.value, price)) return;
  const result = calculateChange(cash.value, price);
  if (!result) return;

  const { change, newCid } = result;
  updateRegister(newCid);
  showChangeDue(change);
});

Thank you as well for your reply!

Honest question: Is it still unreliable if I reset the global variable in the beginning of the function?

var myGlobal = [1];
function returnGlobal(arg) {
  myGlobal = [];
  myGlobal.push(arg);
  return myGlobal;
} // like this

it’s still not a great idea to have extra things in the global space, but it’s certainly better than letting the global variables accumulate data

Thank you!

I still need to learn best practices in coding.

I’m lacking experience to be completely honest.

coding is the only way to get experience, so you are gaining experience right now

This is the way haha

Any ideas why it didn’t work when I moved the global variables inside the calculateChange function and returned them as a object, which later I destructured inside the eventListener?

what did not work there?

at what point of your code you stop having the expected values?

Well, I’m not sure.

When I console.log the output or use the preview to test my code it works just fine, so I don’t know what’s wrong.

I’ve created another way to use the variables newCid and change inside the calculate function. I return them inside an object which a destructure inside the eventListener.

calculateChange Function

const calculateChange = (paidAmount, priceOfPurchase) => { 
  let change = [];
  let newCid = [];

  const valueX100 = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];
  const cashX100 = Math.round(paidAmount * 100);
  const priceX100 = Math.round(priceOfPurchase * 100);
  let differenceX100 = cashX100 - priceX100;
  
  for (let i = cid.length - 1; i >= 0; i--) {
    let cidX100 = Math.round(cid[i][1] * 100); 
    let name = cid[i][0];
    
    let maxUnits = Math.floor(differenceX100 / valueX100[i]);
    let availableUnits = Math.floor(cidX100 / valueX100[i]);
    let unitsToUse = Math.min(maxUnits, availableUnits);
    let changeX100 = unitsToUse * valueX100[i];
    
    differenceX100 -= changeX100;
    newCid.unshift((cidX100 - changeX100) / 100);
    change.unshift([name, changeX100 / 100]);
  }

  if (differenceX100 !== 0) {
    changeDue.innerText = "Status: INSUFFICIENT_FUNDS";
    console.log(changeDue.innerText);
    return false;
  }

  return { change, newCid };
};

eventListener

purchaseBtn.addEventListener("click", (e) => {
  e.preventDefault();

  if (isChangeDue(cash.value, price)) return;
  const result = calculateChange(cash.value, price);
  if (!result) return;

  const { change, newCid } = result;
  updateRegister(newCid);
  showChangeDue(change);
});

Whole JS

const changeDue = document.getElementById("change-due"); 
const cash = document.getElementById("cash"); 
const purchaseBtn = document.getElementById("purchase-btn"); 
const resetBtn = document.getElementById("reset-btn");  
const currency = document.querySelectorAll(".currency"); 
const originalCid = [1.01, 2.05, 3.1, 4.25, 90, 55, 20, 60, 100];

let price = 1.87;
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]
];

const isChangeDue = (paidAmount, priceOfPurchase) => {
  const paid = Math.round(Number(paidAmount) * 100);
  const price = Math.round(Number(priceOfPurchase) * 100);
  if (paidAmount.trim() === "" || isNaN(paid) || paidAmount < 0) {
    alert("Please insert a Valid Number");
    return true;
  } else if (price > paid) {
    alert("Customer does not have enough money to purchase the item");
    return true;
  } else if (price === paid) {
    changeDue.innerText = "No change due - customer paid with exact cash";
    return true;
  }
};

const calculateChange = (paidAmount, priceOfPurchase) => { 
  let change = [];
  let newCid = [];

  const valueX100 = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];
  const cashX100 = Math.round(paidAmount * 100);
  const priceX100 = Math.round(priceOfPurchase * 100);
  let differenceX100 = cashX100 - priceX100;
  
  for (let i = cid.length - 1; i >= 0; i--) {
    let cidX100 = Math.round(cid[i][1] * 100); 
    let name = cid[i][0];
    
    let maxUnits = Math.floor(differenceX100 / valueX100[i]);
    let availableUnits = Math.floor(cidX100 / valueX100[i]);
    let unitsToUse = Math.min(maxUnits, availableUnits);
    let changeX100 = unitsToUse * valueX100[i];
    
    differenceX100 -= changeX100;
    newCid.unshift((cidX100 - changeX100) / 100);
    change.unshift([name, changeX100 / 100]);
  }

  if (differenceX100 !== 0) {
    changeDue.innerText = "Status: INSUFFICIENT_FUNDS";
    console.log(changeDue.innerText);
    return false;
  }

  return { change, newCid };
};

const updateRegister = (newCid) => {   
  let previousCid = cid.map(item => [...item]);

  for (let i = 0; i < cid.length; i++) {  
    cid[i][1] = newCid[i];
    currency[i].textContent = `$${cid[i][1]}`; 
    currency[i].style.color = cid[i][1] === previousCid[i][1]
      ? "var(--detail5)" 
      : "var(--detail3)"; 
  }
};

const showChangeDue = (change) => {
  const totalCidAfterChange = cid.reduce((sum, item) => sum + item[1], 0);
  changeDue.innerText = "";

  changeDue.innerText = totalCidAfterChange === 0
    ? "Status: CLOSED"
    : "Status: OPEN";

  const changeFilter = change.filter(item => item[1] !== 0).reverse();
  changeDue.innerText += changeFilter
    .map(item => ` ${item[0]}: $${item[1]}`)
    .join("");

  return;
};

window.onload = function () {
  document.getElementById("price").innerText += price;
};

resetBtn.addEventListener("click", () => {
  changeDue.innerText = "";
  cash.value = "";

  for (let i = 0; i < cid.length; i++) {
    cid[i][1] = originalCid[i];
    currency[i].textContent = `$${cid[i][1]}`; 
    currency[i].style.color = "var(--detail5)";
  }
});

purchaseBtn.addEventListener("click", (e) => {
  e.preventDefault();

  if (isChangeDue(cash.value, price)) return;
  const result = calculateChange(cash.value, price);
  if (!result) return;

  const { change, newCid } = result;
  updateRegister(newCid);
  showChangeDue(change);
});

but you know something is wrong? in what way?

My issue is I can’t pass the tests and I don’t know why.

have you removed all the global variables?

Yes. All of them. I just moved the originalCid.

resetBtn.addEventListener("click", () => {
  const originalCid = [1.01, 2.05, 3.1, 4.25, 90, 55, 20, 60, 100];
  changeDue.innerText = "";
  cash.value = "";

  for (let i = 0; i < cid.length; i++) {
    cid[i][1] = originalCid[i];
    currency[i].textContent = `$${cid[i][1]}`; 
    currency[i].style.color = "var(--detail5)";
  }
});

This was the last one. Unfortunatelly, it didn’t work.

what is the role of originalCid?

It served to storage value for a resetBtn I’ve added to facilitate when I was testing the Cash Register.
So it would go back to the original value the project passed. If removed it would not affect the rest of the code.

what happens if your code runs with a different cid?

I’ve just performed user stories #10. It seems to work very well.

Tbh I’ve performed all user stories before and it worked.

  1. When price is 19.5, the value in the #cash element is 20, cid is [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]], and the #purchase-btn element is clicked, the value in the #change-due element should be "Status: CLOSED PENNY: $0.5".

can you describe how you are testing it?