Build a Cash Register Project - Build a Cash Register

Tell us what’s happening:

Object-oriented approach on cash register project certification project doesn’t work?Even the simpliest alert test case doesn’t go check.
I also notice this in other cert projects; some test cases just don’t go check, even when manually testing themselves.
I’m kind of speculating that there is a bug on the e2e test or just doesn’t support an object oriented approach.

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>
    <div class="container">
        <h1>Cash Register</h1>
        <h2>Enter cash from customer:</h2>
        <div id="change-due"></div>
        <input id="cash" type="number">
        <button id="purchase-btn">Purchase</button>
        <div class="cash-machine-container">
            <div class="pole-display">
            </div>
            <div class="pole-display-screen"></div>
            <div class="pole-display-stand">
            </div>
            <div class="monitor-wrapper">
                <div class="monitor-screen">
                </div>
            </div>

            <div class="keyboard-wrapper">
                <img class="keyboard"
                    src="https://cdn.animaapp.com/projects/66cdbf599e66f4186c4a605e/releases/66cdbf766ea48700391d8020/img/rectangle-9.svg"
                    anima-src="https://cdn.animaapp.com/projects/66cdbf599e66f4186c4a605e/releases/66cdbf766ea48700391d8020/img/rectangle-9.svg"
                    alt="Rectangle 9">
                <img class="keys-svg"
                    src="https://cdn.animaapp.com/projects/66cdbf599e66f4186c4a605e/releases/66cdbf766ea48700391d8020/img/rectangle@2x.png"
                    anima-src="https://cdn.animaapp.com/projects/66cdbf599e66f4186c4a605e/releases/66cdbf766ea48700391d8020/img/rectangle@2x.png"
                    alt="Rectangle">
            </div>
            <div class="drawer-wrapper">
                <!-- <img class="drawer-rectangle-surface" data-id="2:11" src="https://cdn.animaapp.com/projects/66cdbf599e66f4186c4a605e/releases/66cdbf766ea48700391d8020/img/rectangle-10.svg" anima-src="https://cdn.animaapp.com/projects/66cdbf599e66f4186c4a605e/releases/66cdbf766ea48700391d8020/img/rectangle-10.svg" alt="Rectangle 10"> -->
                <div class="drawer-rectangle"></div>
                <img class="line"
                    src="https://cdn.animaapp.com/projects/66cdbf599e66f4186c4a605e/releases/66cdbf766ea48700391d8020/img/line-1.svg"
                    anima-src="https://cdn.animaapp.com/projects/66cdbf599e66f4186c4a605e/releases/66cdbf766ea48700391d8020/img/line-1.svg"
                    alt="Line">
                <div class="ellipse">
                    <!-- These two elements key and key-2 are just keyholes if we merged them -->
                    <div class="keyhole">
                    </div>
                    <div class="keyhole-2"></div>
                </div>

            </div>
        </div>
    </div>




</body>
<script src="script.js"></script>

</html>


<!-- Reference of my Design (Mockup) -->
<!-- https://spring-shape-2207.animaapp.io -->

/* file: script.js */
let price = 19.5;
let cid = [
  ['PENNY', 0.01],
  ['NICKEL', 0],
  ['DIME', 0],
  ['QUARTER', 0],
  ['ONE', 0],
  ['FIVE', 0],
  ['TEN', 0],
  ['TWENTY', 0],
  ['ONE HUNDRED', 0],
];
let cashInDrawer = new Map([...cid].reverse()); // create a copy of cid but in Map, we'll use this instead
const getEl = (element) => document.querySelector(element);

class App {
  constructor() {
    this.changeDueMap = new Map(); // we will keep track of each cash and change due amount.
    this.cash = NaN; // The user's cash
    this.status = ''; // render the change due status
    this.render(); // renders data
  }

  render() {
    const $customerDisplay = getEl('.pole-display-screen');
    const $monitorDisplay = getEl('.monitor-screen');
    $customerDisplay.innerHTML = `Total: <b>$${price}</b>`;
    $monitorDisplay.innerHTML = `
      <h3> Change in drawer: </h3>
            <ul>
                <li>Pennies:<b> $ ${cashInDrawer
                  .get('PENNY')
                  .toFixed(2)} </b> </li>
                <li>Nickels: <b> $ ${cashInDrawer
                  .get('NICKEL')
                  .toFixed(2)} </b> </li>
                <li>Dimes: <b> $ ${cashInDrawer
                  .get('DIME')
                  .toFixed(2)} </b> </li>
                <li>Quarters: <b> $ ${cashInDrawer
                  .get('QUARTER')
                  .toFixed(2)} </b></li>
                <li>Ones: <b> $ ${cashInDrawer.get('ONE').toFixed(2)} </b> </li>
                <li>Fives: <b> $ ${cashInDrawer
                  .get('FIVE')
                  .toFixed(2)} </b></li>
                <li>Tens: <b> $ ${cashInDrawer.get('TEN').toFixed(2)} </b> </li>
                <li>Twenties: <b> $ ${cashInDrawer
                  .get('TWENTY')
                  .toFixed(2)} </b> </li>
                <li>Hundreds: <b> $ ${cashInDrawer
                  .get('ONE HUNDRED')
                  .toFixed(2)} </b> </li>
            </ul>
      `;
    this.addEventListener(); // binds events
  }

  handleInput(e) {
    const cash = e.target.value; // user input
    const numberPattern = /^\d+(.\d+)?$/; // regex
    if (numberPattern.test(cash)) {
      this.cash = parseFloat(cash);
    }
  }

  handlePurchase() {
    this.changeDueMap.clear(); // remove exisiting elements from previous tracking

    const $changeDue = getEl('#change-due');

    const regex = /^\d+(.\d+)?$/; // Number pattern
    if (!regex.test(getEl('#cash').value)) {
      console.error('Error: Invalid Input');
    } else if (this.cash < price) {
      alert('Customer does not have enough money to purchase the item');
    } else if (this.cash === price) {
      $changeDue.innerHTML = 'No change due - customer paid with exact cash';
    } else if (this.totalAmountInCid() == 0) {
      this.status = 'Status: CLOSED';
    } else {
      let change = this.cash - price; // change due
      // if the total amount in CID is less than change due, it indicates then we have an INSUFFICIENT FUNDS

      if (this.totalAmountInCid() < change) {
        this.status = 'Status: INSUFFICIENT_FUNDS';
      } else {
        const denominations = [
          ['ONE HUNDRED', 100.0],
          ['TWENTY', 20.0],
          ['TEN', 10.0],
          ['FIVE', 5.0],
          ['ONE', 1.0],
          ['QUARTER', 0.25],
          ['DIME', 0.1],
          ['NICKEL', 0.05],
          ['PENNY', 0.01],
        ];

        denominations.forEach(([key, value]) => {
          // subtract the change due from the denomination value until it reaches 0
          while (change >= value && cashInDrawer.get(key) > 0) {
            change -= value;
            change = Math.round(change * 100) / 100; // To avoid floating-point precision issues
            cashInDrawer.set(
              key,
              Math.round((cashInDrawer.get(key) - value) * 100) / 100
            );

            // create a key-value pair in changeDueMap to keep track of the change given
            if (this.changeDueMap.has(key)) {
              this.changeDueMap.set(key, this.changeDueMap.get(key) + value);
            } else {
              this.changeDueMap.set(key, value);
            }
          }
        });
        // If the remaining cash amount in the drawer we gave as change to the customer would equal to 0, then we close and print the change due
        if (change === 0 && this.totalAmountInCid() === 0) {
          let changeDetails = '';
          changeDetails += `<p>Status: CLOSED</p>`;
          this.changeDueMap.forEach((value, key) => {
            changeDetails += `<p>${key}: $${value.toFixed(2)}</p>`;
          });
          this.status = `${changeDetails}`;
        } else if (this.totalAmountInCid() === change) {
          this.status = 'Status: CLOSED';
        } else {
          // if total cash amount in the drawer is greather than change due then it indicates we're still open and allows for returning change due
          let changeDetails = '';
          changeDetails = `<p>Status: OPEN</p>`;
          this.changeDueMap.forEach((value, key) => {
            changeDetails += `<p>${key}: $${value.toFixed(2)}`;
          });
          this.status = `${changeDetails}`;
        }
      }

      getEl('#cash').value = ''; // remove exisiting / current value in form input
      // finally render the status and it's change due details
      $changeDue.innerHTML = this.status;
      this.render(); // Re-render to reflect changes
    }
  }

  totalAmountInCid() {
    // check the cash in drawer total
    let totalAmount = 0;
    cashInDrawer.forEach((amount) => {
      totalAmount += amount;
    });
    return totalAmount;
  }

  // Binder
  addEventListener() {
    getEl('#cash').addEventListener('input', (e) => this.handleInput(e));
    getEl('#purchase-btn').addEventListener('click', () =>
      this.handlePurchase()
    );
  }
}

new App();

/* my css */

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/17.6 Safari/605.1.15

Challenge Information:

Build a Cash Register Project - Build a Cash Register

There are no known bugs in the testing code and other users have used OOP to code a solution though it is not needed for this project.

For your code like the line below:

This code will only run in the global scope once and never again. The test cases do not reload the code each time, they run continuously without that. So a line of code like the one above will only run once and not perform properly when the cid is constantly being updated by the test cases.

What about for the alert test case here? It didn’t even pass, lol, one of the easiest test cases.

For the cashInDrawer, thanks for the info. I’ll put this somewhere in where it’s some kind of state. I didn’t know that test cases were continuous.

there’s no point debugging this until the global scope issues are fixed.
Once they’re fixed, you can add some console.log statements to check if your this.cash really is what it says it should be in the first alert test (10). If it’s not logging that, then more work is needed.

1 Like

I’m trying to simulate the test, but your app is not reacting to this

function test() {
price = 20
document.querySelector("#cash").value = 10
document.querySelector("#purchase-btn").click()
}

test()
1 Like

Mod edit: project code removed.

I’ve already finished it. I already adjusted my code so that it will pass the tests. I just added a getter function so that every time I call that getter function, the cashInDrawer will be updated or initialized when the test cases are running. As for the alert case, @ilenia 's comment was very helpful, so having an event handler like handleinput was useless if the test environment just accessed the input’s value directly.

Glad it worked out. I’ve erased the code though since we have a policy that disallows code sharing in the forum unless it is to request help or feedback. (Feedback can be requested in the code feedback category). Thanks.