Build a Cash Register Project - The tests fail

The tests of the “Cash Register” project do not pass, but it seems to me that the behavior of the application is as expected. Running the application in the browser seems to give the right results.

The project is this:

https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures-v8/build-a-cash-register-project/build-a-cash-register

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 rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <header>
      <div id="author">francisford Coppola Connection</div>
      <div id="title">Cash Register</div>
    </header>
    <main>
      <div id="input-side">
        <form>
          <div id="input-container">
            <div>
              <label for="cash">Enter cash from customer:</label>
              <input type="number" name="cash" id="cash" />
            </div>
          </div>
          <div id="button-container">
            <button type="button" id="purchase-btn">Purchase</button>
          </div>
        </form>
      </div>
      <div id="output-side">
        <div id="price-container">
          <span class="price">Price:</span>
          <div id="price"></div>
        </div>
        <div id="div-container">
          <div id="change-due-container">
            <span class="change">Change Due</span>
            <div id="change-due"></div>
          </div>
          <div id="change-in-drawer-container">
            <span class="change">Change in Drawer</span>
            <div id="change-in-drawer"></div>
          </div>
        </div>
      </div>
    </main>
    <script src="script.js"></script>
  </body>
</html>

CSS

:root {
  --shady-lady: #b59db5;
  --camelot: #823462;
  --grape: #3f1947;
  --green-pea: #226651;
  --summer-green: #92c1a6;
  --antique-white: #faebd7;
}

*,
::after,
::before {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

html {
  font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
  font-size: 15px;
}

body {
  background-color: var(--grape);
  color: var(--antique-white);
}

header {
  top: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  gap: 3rem;
  margin-top: 4rem;
}

#author {
  font-size: 3rem;
  font-weight: bold;
  color: var(--summer-green);
}

#title {
  font-size: 5rem;
  font-weight: bold;
}

main {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--shady-lady);
  padding: 10px;
  width: 60%;
  margin: 7rem auto;
}

#input-side,
#output-side {
  border: 1px solid var(--shady-lady);
  padding: 5px;
}

#input-side {
  width: 100%;
}

form {
  display: flex;
  flex-direction: row;
  justify-content: center;
}

#input-container,
#button-container {
  display: flex;
  padding: 5px;
  width: 100%;
}

#input-container {
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
}

label[for='cash'],
#cash {
  display: block;
  font-size: 1.5rem;
}

#cash {
  padding-left: 0.33rem;
}

#button-container {
  align-items: flex-end;
}

#purchase-btn {
  height: 2rem;
  padding: 0 1rem;
}

#output-side {
  width: 75%;
}

#price-container {
  display: flex;
  flex-direction: row;
  justify-content: center;
  position: relative;
  top: 0;
  left: 0;
  width: 100%;
}

#price-container div {
  background-color: var(--summer-green);
  color: var(--camelot);
  font-size: 1.5rem;
  font-weight: bold;
  text-align: center;
  width: 15rem;
  height: 1.5rem;
  margin-left: 1rem;
}

#div-container {
  display: flex;
  gap: 10px;
}

#change-due-container,
#change-in-drawer-container {
  display: block;
  width: 49%;
  margin-top: 0.5rem;
}

#change-due,
#change-in-drawer {
  width: 100%;
  height: 17rem;
  background-color: var(--summer-green);
  color: var(--camelot);
  font-size: 1.1rem;
  margin-top: 0.33rem;
  padding: 1rem;
}

span.price {
  font-size: 1.5rem;
}

span.change {
  font-size: 1.2rem;
}

JS

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 drawerContent = [
  { figure: 'one hundred', value: 100 },
  { figure: 'twenty', value: 20 },
  { figure: 'ten', value: 10 },
  { figure: 'five', value: 5 },
  { figure: 'one', value: 1 },
  { figure: 'quarter', value: 0.25 },
  { figure: 'dime', value: 0.1 },
  { figure: 'nickel', value: 0.05 },
  { figure: 'penny', value: 0.01 },
];

const cashInput = document.getElementById('cash');
const purchaseButton = document.getElementById('purchase-btn');
const priceDiv = document.getElementById('price');
const changeDueDiv = document.getElementById('change-due');
const changeInDrawerDiv = document.getElementById('change-in-drawer');

priceDiv.textContent = price;

const updateDrawerContent = () => {
  for (const line of cid) {
    drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount = line[1];
  }
};
updateDrawerContent();

const updateChangeInDrawerText = () => {
  let drawerContentText = '';
  for (const figure of drawerContent) {
    drawerContentText += '<p><strong>' + figure.figure + ':</strong> ' + figure.amount + '</p>';
  }
  changeInDrawerDiv.innerHTML = `${drawerContentText}`;
};

updateChangeInDrawerText(cid);

const handlePurchaseButton = () => {
  const cashAmount = parseFloat(cashInput.value) || null;
  const priceAmount = parseFloat(priceDiv.textContent) || null;

  if (cashAmount === null || cashAmount === undefined) {
    alert('You must indicate how much money the customer has paid');
    return;
  }

  if (cashAmount < priceAmount) {
    alert('Customer does not have enough money to purchase the item');
    return;
  }

  if (cashAmount === priceAmount) {
    changeDueDiv.textContent = 'No change due - customer paid with exact cash';
    return;
  }

  let changeAmount = cashAmount - priceAmount;
  let hasChanged = false;
  const totalDrawer = cid.reduce((totalAmount, figure) => totalAmount + figure[1], 0);
  let status = '';

  if (totalDrawer < changeAmount) {
    status = 'INSUFFICIENT_FUNDS';
    changeDueDiv.textContent = `Status: ${status}`;
    return;
  }

  while (changeAmount > 0) {
    const currChangeAmount = changeAmount;
    for (const figure of drawerContent) {
      if (changeAmount >= parseFloat(figure.value) && parseFloat(figure.amount) > 0) {
        changeAmount = Number((changeAmount - figure.value).toFixed(2));
        figure.amount = Number((figure.amount - figure.value).toFixed(2));
        hasChanged = true;
        break;
      }
    }
    if (!hasChanged || currChangeAmount == changeAmount) {
      hasChanged = false;
      break;
    }
  }

  if (!hasChanged) {
    status = 'INSUFFICIENT_FUNDS';
    changeDueDiv.textContent = `Status: ${status}`;
    updateDrawerContent();
    return;
  } else if (totalDrawer == cashAmount - priceAmount) {
    status = '<p>Status: CLOSED</p>';
    for (const line of cid.reverse()) {
      const difference = (line[1] - drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount).toFixed(2);
      status += difference <= 0 ? '' : `<p>${line[0]}: $${difference}</p>`;
    }
    changeDueDiv.innerHTML = status;
    updateChangeInDrawerText();
  } else {
    status = '<p>Status: OPEN</p>';
    for (const line of cid.reverse()) {
      const difference = (line[1] - drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount).toFixed(2);
      status += difference <= 0 ? '' : `<p>${line[0]}: $${difference}</p>`;
    }
    changeDueDiv.innerHTML = status;
    updateChangeInDrawerText();
  }
};

purchaseButton.addEventListener('click', handlePurchaseButton);

These are the errors detected by tests with screenshots of the application in the browser:

  • When the value in the #cash element is less than price, an alert should appear with the text "Customer does not have enough money to purchase the item".

  • 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.

  • 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”.

  • 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”.

  • 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”.

What could be the problem?

you should use price as it’s the variable that the tests use. Anything you do with price in the global environment is not repeated when the tests run, and the tests change the value of price

this is not updated, so you can’t use

you can’t use this

1 Like

Okay thanks.

I made the changes you suggested. Now the clickHandler is

const handlePurchaseButton = () => {
  const cashAmount = parseFloat(cashInput.value) || null;

  if (cashAmount === null || cashAmount === undefined) {
    alert('You must indicate how much money the customer has paid');
    return;
  }

  if (cashAmount < price) {
    alert('Customer does not have enough money to purchase the item');
    return;
  }

  if (cashAmount === price) {
    changeDueDiv.textContent = 'No change due - customer paid with exact cash';
    return;
  }

  let changeAmount = cashAmount - price;
  let hasChanged = false;
  const totalDrawer = cid.reduce((totalAmount, figure) => totalAmount + figure[1], 0);
  let status = '';

  if (totalDrawer < changeAmount) {
    status = 'INSUFFICIENT_FUNDS';
    changeDueDiv.textContent = `Status: ${status}`;
    return;
  }

  while (changeAmount > 0) {
    const currChangeAmount = changeAmount;
    for (const figure of drawerContent) {
      if (changeAmount >= parseFloat(figure.value) && parseFloat(figure.amount) > 0) {
        changeAmount = Number((changeAmount - figure.value).toFixed(2));
        figure.amount = Number((figure.amount - figure.value).toFixed(2));
        hasChanged = true;
        break;
      }
    }
    if (!hasChanged || currChangeAmount == changeAmount) {
      hasChanged = false;
      break;
    }
  }

  if (!hasChanged) {
    status = 'INSUFFICIENT_FUNDS';
    changeDueDiv.textContent = `Status: ${status}`;
    updateDrawerContent();
    return;
  } else if (totalDrawer == cashAmount - price) {
    status = '<p>Status: CLOSED</p>';
    for (const line of cid.reverse()) {
      const difference = (line[1] - drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount).toFixed(2);
      status += difference <= 0 ? '' : `<p>${line[0]}: $${difference}</p>`;
    }
    changeDueDiv.innerHTML = status;
    updateChangeInDrawerText();
  } else {
    status = '<p>Status: OPEN</p>';
    for (const line of cid.reverse()) {
      const difference = (line[1] - drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount).toFixed(2);
      status += difference <= 0 ? '' : `<p>${line[0]}: $${difference}</p>`;
    }
    changeDueDiv.innerHTML = status;
    updateChangeInDrawerText();
  }
};

but the following errors are returned to me, while, as can be seen in the screenshots, the behavior of the application seems to be as expected.

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

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

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

show all your code, are you still doing things in the global scope?
in the global scope you should have the declaration of cid, price, and the selection of the elements, no other operation

It seems to me that this is exactly the case

let price = 19.5;
let cid = [
  ['PENNY', 0.5],
  ['NICKEL', 0],
  ['DIME', 0],
  ['QUARTER', 0],
  ['ONE', 0],
  ['FIVE', 0],
  ['TEN', 0],
  ['TWENTY', 0],
  ['ONE HUNDRED', 0],
];
const drawerContent = [
  { figure: 'one hundred', value: 100 },
  { figure: 'twenty', value: 20 },
  { figure: 'ten', value: 10 },
  { figure: 'five', value: 5 },
  { figure: 'one', value: 1 },
  { figure: 'quarter', value: 0.25 },
  { figure: 'dime', value: 0.1 },
  { figure: 'nickel', value: 0.05 },
  { figure: 'penny', value: 0.01 },
];

const cashInput = document.getElementById('cash');
const purchaseButton = document.getElementById('purchase-btn');
const priceDiv = document.getElementById('price');
const changeDueDiv = document.getElementById('change-due');
const changeInDrawerDiv = document.getElementById('change-in-drawer');

priceDiv.textContent = price;

const updateDrawerContent = () => {
  for (const line of cid) {
    drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount = line[1];
  }
};
updateDrawerContent();

const updateChangeInDrawerText = () => {
  let drawerContentText = '';
  for (const figure of drawerContent) {
    drawerContentText += '<p><strong>' + figure.figure + ':</strong> ' + figure.amount + '</p>';
  }
  changeInDrawerDiv.innerHTML = `${drawerContentText}`;
};

updateChangeInDrawerText();

const handlePurchaseButton = () => {
  const cashAmount = parseFloat(cashInput.value) || null;

  if (cashAmount === null || cashAmount === undefined) {
    alert('You must indicate how much money the customer has paid');
    return;
  }

  if (cashAmount < price) {
    alert('Customer does not have enough money to purchase the item');
    return;
  }

  if (cashAmount === price) {
    changeDueDiv.textContent = 'No change due - customer paid with exact cash';
    return;
  }

  let changeAmount = cashAmount - price;
  let hasChanged = false;
  const totalDrawer = cid.reduce((totalAmount, figure) => totalAmount + figure[1], 0);
  let status = '';

  if (totalDrawer < changeAmount) {
    status = 'INSUFFICIENT_FUNDS';
    changeDueDiv.textContent = `Status: ${status}`;
    return;
  }

  while (changeAmount > 0) {
    const currChangeAmount = changeAmount;
    for (const figure of drawerContent) {
      if (changeAmount >= parseFloat(figure.value) && parseFloat(figure.amount) > 0) {
        changeAmount = Number((changeAmount - figure.value).toFixed(2));
        figure.amount = Number((figure.amount - figure.value).toFixed(2));
        hasChanged = true;
        break;
      }
    }
    if (!hasChanged || currChangeAmount == changeAmount) {
      hasChanged = false;
      break;
    }
  }

  if (!hasChanged) {
    status = 'INSUFFICIENT_FUNDS';
    changeDueDiv.textContent = `Status: ${status}`;
    updateDrawerContent();
    return;
  } else if (totalDrawer == cashAmount - price) {
    status = '<p>Status: CLOSED</p>';
    for (const line of cid.reverse()) {
      const difference = (line[1] - drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount).toFixed(2);
      status += difference <= 0 ? '' : `<p>${line[0]}: $${difference}</p>`;
    }
    changeDueDiv.innerHTML = status;
    updateChangeInDrawerText();
  } else {
    status = '<p>Status: OPEN</p>';
    for (const line of cid.reverse()) {
      const difference = (line[1] - drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount).toFixed(2);
      status += difference <= 0 ? '' : `<p>${line[0]}: $${difference}</p>`;
    }
    changeDueDiv.innerHTML = status;
    updateChangeInDrawerText();
  }
};

purchaseButton.addEventListener('click', handlePurchaseButton);

here you are using a global variable

for the first failing test, your output is
<p>Status: OPEN</p><p>ONE HUNDRED: $100.00</p><p>TWENTY: $60.00</p><p>TEN: $20.00</p><p>FIVE: $55.00</p><p>ONE: $90.00</p><p>QUARTER: $4.25</p><p>DIME: $3.10</p><p>NICKEL: $2.05</p><p>PENNY: $1.01</p>
You are still using global variables.

this is changing the global cid, an other thing you should not do

Ilenia, thank you for your help, but at this point I can’t stand it anymore.

If a project demands results, and my project returns those exact results in every possible situation, then my project must pass. If, however, a specific and particular implementation is asked for, then it must be stated explicitly and understandably.

The implementation choices I made make sense relative to the specifics of the project, which in fact works as expected. And I can’t guess what the particular implementation is cryptically being asked for.

Now I ask you: Does the project I wrote respond to all the requests of the challenge and return the results expected?

Not really, no.

You have written a function that can only be called once, which invalidates the purpose of writing a function.

1 Like

Good point. So the problem is the line

for (const line of cid.reverse()) {

Ok, I changed the lines where that statement is located like this:

for (const line of [...cid].reverse()) {

The reverse() instruction is used to get the output in the same order requested by the user stories. Now the application responds in the exact same way even if it is used several times consecutively.

But the result doesn’t change: the system returns the same errors I said before.

Please don’t tell me which code I got wrong. Tell me instead what the application should do that it doesn’t yet do.

Thank you.

It is difficult to know what your code is doing for sure without the full updated code.

However, you should 1) not have any logic for generating results outside of the event handler you attach to the button since the tests simulate clicking the button after updating the CID and price 2) you can’t rely upon reverse always giving the order you need as array ordering can be funky between browsers ( I don’t exactly know the internals of why) so you should use a sort to get any target ordering

Ok, let’s see:
cid has values high enough that we don’t have to worry in this case.
price is 19.5

I write 20 in the input, and press the button
Status: OPEN PENNY: $0.50 and it’s fine
then I write 21 and press the button
Status: OPEN ONE: $1.00 QUARTER: $1.00
this is not correct, the change is 1.50, not 2.

2 Likes

I modified the project code as follows:

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],
];
const drawerContent = [
  { figure: 'one hundred', value: 100 },
  { figure: 'twenty', value: 20 },
  { figure: 'ten', value: 10 },
  { figure: 'five', value: 5 },
  { figure: 'one', value: 1 },
  { figure: 'quarter', value: 0.25 },
  { figure: 'dime', value: 0.1 },
  { figure: 'nickel', value: 0.05 },
  { figure: 'penny', value: 0.01 },
];

const cashInput = document.getElementById('cash');
const purchaseButton = document.getElementById('purchase-btn');
const priceDiv = document.getElementById('price');
const changeDueDiv = document.getElementById('change-due');
const changeInDrawerDiv = document.getElementById('change-in-drawer');

priceDiv.textContent = price;

const updateDrawerContent = () => {
  for (const line of cid) {
    drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount = line[1];
  }
};
updateDrawerContent();

const updateChangeInDrawerText = () => {
  let drawerContentText = '';
  for (const figure of drawerContent) {
    drawerContentText += '<p><strong>' + figure.figure + ':</strong> ' + figure.amount + '</p>';
  }
  changeInDrawerDiv.innerHTML = `${drawerContentText}`;
};
updateChangeInDrawerText();

const updateCid = () => {
  cid = [];
  for (const figure of drawerContent) {
    cid.push([figure.figure.toUpperCase(), figure.amount]);
  }
};

const handlePurchaseButton = () => {
  const cashAmount = parseFloat(cashInput.value) || null;

  if (cashAmount === null || cashAmount === undefined) {
    alert('You must indicate how much money the customer has paid');
    return;
  }

  if (cashAmount < price) {
    alert('Customer does not have enough money to purchase the item');
    return;
  }

  if (cashAmount === price) {
    changeDueDiv.textContent = 'No change due - customer paid with exact cash';
    return;
  }

  let changeAmount = cashAmount - price;
  let hasChanged = false;
  const totalDrawer = Number(drawerContent.reduce((totalAmount, figure) => totalAmount + figure.amount, 0).toFixed(2));

  if (totalDrawer < changeAmount) {
    changeDueDiv.textContent = `Status: INSUFFICIENT_FUNDS`;
    return;
  }

  updateCid();
  while (changeAmount > 0) {
    const currChangeAmount = changeAmount;
    for (const figure of drawerContent) {
      if (changeAmount >= parseFloat(figure.value) && parseFloat(figure.amount) > 0) {
        changeAmount = Number((changeAmount - figure.value).toFixed(2));
        figure.amount = Number((figure.amount - figure.value).toFixed(2));
        hasChanged = true;
        break;
      }
    }
    if (!hasChanged || currChangeAmount == changeAmount) {
      hasChanged = false;
      break;
    }
  }

  if (!hasChanged) {
    changeDueDiv.textContent = `Status: INSUFFICIENT_FUNDS`;
    updateDrawerContent();
    return;
  } else {
    let status = totalDrawer == cashAmount - price ? '<p>Status: CLOSED</p>' : '<p>Status: OPEN</p>';
    for (const line of [...cid].sort((a, b) => b[1] - a[1])) {
      const prec = Number(line[1]);
      const succ = Number(drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount);
      const difference = Number((prec - succ).toFixed(2));
      status += difference <= 0 ? '' : `<p>${line[0]}: $${difference}</p>`;
    }
    changeDueDiv.innerHTML = status;
    updateChangeInDrawerText();
  }
};

purchaseButton.addEventListener('click', handlePurchaseButton);

Now I get the following errors (I add screenshots of the application running in the browser, which shows that the errors do not emerge at runtime)

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"

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".

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".

I also did the test, suggested yesterday by Ilenia, of doing multiple consecutive operations, and it seems that the numbers obtained are the expected ones.

What else is missing from the application to make it pass all the tests?

Add this at the end of your editor, then look at the console. In this way you can see exactly what the tests are finding when your code execute.
About the expected, the tests do not check for exact equality, but that all the word: word or word: number couples are present.

const test = () => {
  price = 3.26
  cid = [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]
  document.querySelector('#cash').value = 100
  document.querySelector('#purchase-btn').click()
  console.log({ price: price, cid: cid, cash: document.querySelector('#cash').value, changeDue: document.querySelector('#change-due').innerText, expected: "Status: OPEN TWENTY: $60 TEN: $20 FIVE: $15 ONE: $1 QUARTER: $0.5 DIME: $0.2 PENNY: $0.04" })

  price = 3.26
  cid = [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]
  document.querySelector('#cash').value = 20
  document.querySelector('#purchase-btn').click()
  console.log({ price: price, cid: cid, cash: document.querySelector('#cash').value, changeDue: document.querySelector('#change-due').innerText, expected: "Status: INSUFFICIENT_FUNDS" })

  price = 19.5
  cid = [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]
  document.querySelector('#cash').value = 20
  document.querySelector('#purchase-btn').click()
  console.log({ price: price, cid: cid, cash: document.querySelector('#cash').value, changeDue: document.querySelector('#change-due').innerText, expected: "Status: INSUFFICIENT_FUNDS" })

  price = 19.5
  cid = [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 1], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]
  document.querySelector('#cash').value = 20
  document.querySelector('#purchase-btn').click()
  console.log({ price: price, cid: cid, cash: document.querySelector('#cash').value, changeDue: document.querySelector('#change-due').innerText, expected: "Status: INSUFFICIENT_FUNDS" })

  price = 19.5
  cid = [["PENNY", 0.5], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]
  document.querySelector('#cash').value = 20
  document.querySelector('#purchase-btn').click()
  console.log({ price: price, cid: cid, cash: document.querySelector('#cash').value, changeDue: document.querySelector('#change-due').innerText, expected: "Status: CLOSED PENNY: $0.5" })
}

test()

I did all the tests that were given to me yesterday. This is the updated code:

let price = 19.5;
let cid = [
  ['PENNY', 0.5],
  ['NICKEL', 0],
  ['DIME', 0],
  ['QUARTER', 0],
  ['ONE', 0],
  ['FIVE', 0],
  ['TEN', 0],
  ['TWENTY', 0],
  ['ONE HUNDRED', 0],
];
const drawerContent = [
  { figure: 'one hundred', value: 100 },
  { figure: 'twenty', value: 20 },
  { figure: 'ten', value: 10 },
  { figure: 'five', value: 5 },
  { figure: 'one', value: 1 },
  { figure: 'quarter', value: 0.25 },
  { figure: 'dime', value: 0.1 },
  { figure: 'nickel', value: 0.05 },
  { figure: 'penny', value: 0.01 },
];

const cashInput = document.getElementById('cash');
const purchaseButton = document.getElementById('purchase-btn');
const priceDiv = document.getElementById('price');
const changeDueDiv = document.getElementById('change-due');
const changeInDrawerDiv = document.getElementById('change-in-drawer');

priceDiv.textContent = price;

const updateDrawerContent = () => {
  for (const line of cid) {
    drawerContent.find((el) => el.figure == line[0].toLowerCase()).amount = line[1];
  }
};
updateDrawerContent();

const updateChangeInDrawerText = () => {
  let drawerContentText = '';
  for (const figure of drawerContent) {
    drawerContentText += '<p><strong>' + figure.figure + ':</strong> ' + figure.amount + '</p>';
  }
  changeInDrawerDiv.innerHTML = `${drawerContentText}`;
};
updateChangeInDrawerText();

const updateCid = () => {
  cid = [];
  for (const figure of [...drawerContent].sort((a, b) => b.value - a.value)) {
    cid.push([figure.figure.toUpperCase(), figure.amount]);
  }
};

const handlePurchaseButton = () => {
  const cashAmount = parseFloat(cashInput.value) || null;

  if (cashAmount === null || cashAmount === undefined) {
    alert('You must indicate how much money the customer has paid');
    return;
  }

  if (cashAmount < price) {
    alert('Customer does not have enough money to purchase the item');
    return;
  }

  if (cashAmount === price) {
    changeDueDiv.textContent = 'No change due - customer paid with exact cash';
    return;
  }

  let changeAmount = cashAmount - price;
  let hasChanged = false;
  const totalDrawer = Number(drawerContent.reduce((totalAmount, figure) => totalAmount + figure.amount, 0).toFixed(2));

  if (totalDrawer < changeAmount) {
    changeDueDiv.textContent = `Status: INSUFFICIENT_FUNDS`;
    return;
  }

  updateCid();
  while (changeAmount > 0) {
    const currChangeAmount = changeAmount;
    for (const figure of drawerContent) {
      if (changeAmount >= parseFloat(figure.value) && parseFloat(figure.amount) > 0) {
        changeAmount = Number((changeAmount - figure.value).toFixed(2));
        figure.amount = Number((figure.amount - figure.value).toFixed(2));
        hasChanged = true;
        break;
      }
    }
    if (!hasChanged || currChangeAmount == changeAmount) {
      hasChanged = false;
      break;
    }
  }

  if (!hasChanged) {
    changeDueDiv.textContent = `Status: INSUFFICIENT_FUNDS`;
    updateDrawerContent();
    return;
  } else {
    let status = totalDrawer == cashAmount - price ? '<p>Status: CLOSED</p>' : '<p>Status: OPEN</p>';
    for (const line of [...drawerContent].sort((a, b) => b.value - a.value)) {
      const prec = Number(cid.find((el) => el[0] == line.figure.toUpperCase())[1]);
      const succ = Number(line.amount);
      const difference = Number((prec - succ).toFixed(2));
      status += difference <= 0 ? '' : `<p>${line.figure.toUpperCase()}: $${difference}</p>`;
    }
    changeDueDiv.innerHTML = status;
    updateChangeInDrawerText();
  }
};

purchaseButton.addEventListener('click', handlePurchaseButton);

And these are the results obtained by running the application in the browser.

test 1:
price = 3.26
cid = [
  ["PENNY", 1.01],
  ["NICKEL", 2.05],
  ["DIME", 3.1],
  ["QUARTER", 4.25],
  ["ONE", 90],
  ["FIVE", 55],
  ["TEN", 20],
  ["TWENTY", 60],
  ["ONE HUNDRED", 100]
]
cash = 100

expected:
Status: OPEN
TWENTY: $60
TEN: $20
FIVE: $15
ONE: $1
QUARTER: $0.5
DIME: $0.2
PENNY: $0.04

result:
same results: SUCCESS
same order: SUCCESS

---

Test 2:
price = 3.26
cid = [
  ["PENNY", 0.01],
  ["NICKEL", 0],
  ["DIME", 0],
  ["QUARTER", 0],
  ["ONE", 0],
  ["FIVE", 0],
  ["TEN", 0],
  ["TWENTY", 0],
  ["ONE HUNDRED", 0]
]
cash = 20

expected:
Status: INSUFFICIENT_FUNDS

result:
same results: SUCCESS

---

test 3:
price = 19.5
cid = [
  ["PENNY", 0.01],
  ["NICKEL", 0],
  ["DIME", 0],
  ["QUARTER", 0],
  ["ONE", 0],
  ["FIVE", 0],
  ["TEN", 0],
  ["TWENTY", 0],
  ["ONE HUNDRED", 0]
]
cash = 20

expected:
Status: INSUFFICIENT_FUNDS

result:
same results: SUCCESS

---

test 4:
price = 19.5
cid = [
  ["PENNY", 0.01],
  ["NICKEL", 0],
  ["DIME", 0],
  ["QUARTER", 0],
  ["ONE", 1],
  ["FIVE", 0],
  ["TEN", 0],
  ["TWENTY", 0],
  ["ONE HUNDRED", 0]
]
cash = 20

expected:
Status: INSUFFICIENT_FUNDS

result:
same results: SUCCESS

---

test 5:
price = 19.5
cid = [
  ["PENNY", 0.5],
  ["NICKEL", 0],
  ["DIME", 0],
  ["QUARTER", 0],
  ["ONE", 0],
  ["FIVE", 0],
  ["TEN", 0],
  ["TWENTY", 0],
  ["ONE HUNDRED", 0]
]
cash = 20

expected:
Status: CLOSED PENNY: $0.5

result:
same results: SUCCESS
same order: SUCCESS

But the system returns the following errors. (I attach the screenshots of the application running ON THE fCC PAGE.)

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"

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".

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".

As you can see, the results seem to be as expected, and yet the system refuses to let the project go through.

Why?

I’m not sure what this is, but it’s not part of the instructions. You shouldn’t be changing the CID variable

It is used to update the cash register after each transaction. This way the application can be used many times consecutively as you said in this post.

It doesn’t seem to me to be a mistake, but a design choice. Does this seem like a mistake to you?

I would like to point out that for three days I have continued to say, and demonstrate, that the application does not make visible errors and that nevertheless the system does not let it pass. Maybe it’s time to start responding with explicit concepts and not with allusions.

Here is an explicit concept: don’t do anything that the instructions don’t ask you to do here. That magnifies the difficulty of your debugging.

My comment above was about you using global variables in a way that made your function single use. You shouldn’t use any global variables except for the ones you were given in the initial code, and you shouldn’t change those global variables yourself.

In the script.js file, you have been provided with the price and cid variables. The price variable is the price of the item, and the cid variable is the cash-in-drawer, which is a 2D array listing the available currency in the cash drawer.

These values should not be changed by your code. They are only changed during tests. None of the user stories say to change thes values. Don’t look for additional functionality to add until the tests pass.

I get you are frustrated, but please remember to be kind to your fellow community members, especially those donating the free tutoring!

the tests are not to separete, you should use it all at once, otherwise it’s not different to test it manually

What you get is not what I get

{ price: 3.26,
  cid: 
   [ [ 'PENNY', 1.01 ],
     [ 'NICKEL', 2.05 ],
     [ 'DIME', 3.1 ],
     [ 'QUARTER', 4.25 ],
     [ 'ONE', 90 ],
     [ 'FIVE', 55 ],
     [ 'TEN', 20 ],
     [ 'TWENTY', 60 ],
     [ 'ONE HUNDRED', 100 ] ],
  cash: '100',
  changeDue: 'Status: INSUFFICIENT_FUNDS',
  expected: 'Status: OPEN TWENTY: $60 TEN: $20 FIVE: $15 ONE: $1 QUARTER: $0.5 DIME: $0.2 PENNY: $0.04' }
{ price: 3.26,
  cid: 
   [ [ 'PENNY', 0.01 ],
     [ 'NICKEL', 0 ],
     [ 'DIME', 0 ],
     [ 'QUARTER', 0 ],
     [ 'ONE', 0 ],
     [ 'FIVE', 0 ],
     [ 'TEN', 0 ],
     [ 'TWENTY', 0 ],
     [ 'ONE HUNDRED', 0 ] ],
  cash: '20',
  changeDue: 'Status: INSUFFICIENT_FUNDS',
  expected: 'Status: INSUFFICIENT_FUNDS' }
{ price: 19.5,
  cid: 
   [ [ 'ONE HUNDRED', 0 ],
     [ 'TWENTY', 0 ],
     [ 'TEN', 0 ],
     [ 'FIVE', 0 ],
     [ 'ONE', 0 ],
     [ 'QUARTER', 0 ],
     [ 'DIME', 0 ],
     [ 'NICKEL', 0 ],
     [ 'PENNY', 0.5 ] ],
  cash: '20',
  changeDue: 'Status: CLOSED\n\nPENNY: $0.5',
  expected: 'Status: INSUFFICIENT_FUNDS' }
{ price: 19.5,
  cid: 
   [ [ 'PENNY', 0.01 ],
     [ 'NICKEL', 0 ],
     [ 'DIME', 0 ],
     [ 'QUARTER', 0 ],
     [ 'ONE', 1 ],
     [ 'FIVE', 0 ],
     [ 'TEN', 0 ],
     [ 'TWENTY', 0 ],
     [ 'ONE HUNDRED', 0 ] ],
  cash: '20',
  changeDue: 'Status: INSUFFICIENT_FUNDS',
  expected: 'Status: INSUFFICIENT_FUNDS' }
{ price: 19.5,
  cid: 
   [ [ 'PENNY', 0.5 ],
     [ 'NICKEL', 0 ],
     [ 'DIME', 0 ],
     [ 'QUARTER', 0 ],
     [ 'ONE', 0 ],
     [ 'FIVE', 0 ],
     [ 'TEN', 0 ],
     [ 'TWENTY', 0 ],
     [ 'ONE HUNDRED', 0 ] ],
  cash: '20',
  changeDue: 'Status: INSUFFICIENT_FUNDS',
  expected: 'Status: CLOSED PENNY: $0.5' }
1 Like

With your latest code, the call to updateDrawerContent only happens one time at the top-level. If you add that function call to the top of the button click handler, your code should pass.

I completely rewrote the code, now the project has been accepted.

Thanks to everyone who helped me.