JS Calculator test failing

This is beta version, with some flaws, such as unfinished interface. But I launch tests
and noticed that there is a bug that I can not understand or fix, it is related to eval().

You also can run launch tests on this link.

Code
  import logo from './logo.svg';
  import './App.css';
  import React from 'react';
  
  class App extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        display: '',
        displayFormula: '0',
        isEqual: '0' 
      };
      this.charHandler = this.charHandler.bind(this);
      this.acHandler = this.acHandler.bind(this);
      this.equalHandler = this.equalHandler.bind(this);
    }
  
    charHandler(event) {
      if (/\d/.test(event.target.value)) {
      this.setState({
          display: Number(event.target.value)
      });
      } else {
        this.setState({
          display: event.target.value
      });
      }
      console.log(this.state.display);
      console.log(event.target.value);
      console.log(this.state.displayFormula);
      if (this.state.displayFormula === '0' && this.state.displayFormula.length === 1) {
        console.log('0');
        if (event.target.value === '.') {
          this.setState({
            displayFormula: this.state.displayFormula + event.target.value
          })
        } else if (/\d|\-/.test(event.target.value)) {
          this.setState({
            displayFormula: event.target.value
          })
        }
      } else if (this.state.displayFormula.length >= 1) {
          if (/^\-$/.test(this.state.displayFormula)) {
            if (/\d/.test(event.target.value)) {
              this.setState({
                displayFormula: this.state.displayFormula + event.target.value
              })
            } else {
              this.setState({
                  displayFormula: this.state.displayFormula
                })
            }
          } else if (/[^\.\d]\d+\.+\d+$|^\d+\.+\d+$/.test(this.state.displayFormula)) {
            console.log('1');
            if (this.state.isEqual === '0') {
              if (/\d|[^\.\d]/.test(event.target.value)){
                this.setState({
                  displayFormula: this.state.displayFormula + event.target.value
                })
              } else {
                  this.setState({
                    displayFormula: this.state.displayFormula
                  })
              }
            } else {
              if (/\d/.test(event.target.value)) {
                this.setState({
                  displayFormula: event.target.value,
                  isEqual: '0'
                })
              } else {
                this.setState({
                  displayFormula: this.state.displayFormula + event.target.value,
                  isEqual: '0'
                })
              }
            }
          } else if (/[^\.\d]\d+\.+$|^\d+\.+$/.test(this.state.displayFormula)) {
              console.log('1.1');
              if (/\d/.test(event.target.value)) {
                this.setState({
                  displayFormula: this.state.displayFormula + event.target.value
                })
              } else {
                  this.setState({
                    displayFormula: this.state.displayFormula
                  })
              }
          } else if (/[^\.\d]\d+$|^\d+$/.test(this.state.displayFormula)) {
              console.log('2');
              if (this.state.isEqual === '0') {
                if (/[^\.\d]0$/.test(this.state.displayFormula)) {
                  if (/0/.test(event.target.value)) {
                    this.setState({
                      displayFormula: this.state.displayFormula
                    })
                  } else if (/[1-9]/.test(event.target.value)) {
                      this.setState({
                        displayFormula: this.state.displayFormula.replace(/.$/, event.target.value)
                      })
                  } else {
                      this.setState({
                        displayFormula: this.state.displayFormula + event.target.value
                      })
                  }
                } else { 
                    this.setState({
                      displayFormula: this.state.displayFormula + event.target.value
                    })
                }
              } else {
                if (/\d/.test(event.target.value)) {
                  this.setState({
                    displayFormula: event.target.value,
                    isEqual: '0'
                  })
                } else {
                  this.setState({
                    displayFormula: this.state.displayFormula + event.target.value,
                    isEqual: '0'
                  })
                }
              }
          } else if (/[^\.\d]\d+\.+\d+\D+$|^\d+\.+\d+\D+$|[^\.\d]\d+\D+$|^\d+\D+$/.test(this.state.displayFormula)) {
              console.log('3');
              if (/[^\d\.\-]/.test(event.target.value)) {
                this.setState({
                  displayFormula: this.state.displayFormula
                })
              } else if (/\-/.test(event.target.value) && !/\D{2}$/.test(this.state.displayFormula)) {
                  this.setState({
                    displayFormula: this.state.displayFormula + event.target.value
                  })
              } else if (/\d/.test(event.target.value)) {
                this.setState({
                    displayFormula: this.state.displayFormula + event.target.value
                  })
              }
          }
      }
    }
  
    acHandler() {
      this.setState({
        displayFormula: '',
        display: ''
      })
      setTimeout(() => this.setState({
        displayFormula: '0',
        display: '0'
      }), 200)
    }
  
    equalHandler() {
      let result = Number(eval(this.state.displayFormula).toFixed(10)).toString();
      this.setState({
        displayFormula: result,
        display: Number(result),
        isEqual: '1'
      })
    }
    
    render () {
      return (
        <div className='App'>
            <img src={logo} className='App-logo' alt='logo' />
            <div id='calculator'>
              <div id='displayFormula'>{this.state.displayFormula}</div>
              <div id='display'>{this.state.display}</div>
              <div className='buttons'>
                <button value='AC' onClick={this.acHandler} id='clear'>AC</button>
                <button value='/' onClick={this.charHandler} id='divide'>/</button>
                <button value='*' onClick={this.charHandler} id='multiply'>x</button>
                <button value='7' onClick={this.charHandler} id='seven'>7</button>
                <button value='8' onClick={this.charHandler} id='eight'>8</button>
                <button value='9' onClick={this.charHandler} id='nine'>9</button>
                <button value='-' onClick={this.charHandler} id='subtract'>-</button>
                <button value='4' onClick={this.charHandler} id='four'>4</button>
                <button value='5' onClick={this.charHandler} id='five'>5</button>
                <button value='6' onClick={this.charHandler} id='six'>6</button>
                <button value='+' onClick={this.charHandler} id='add'>+</button>            
                <button value='1' onClick={this.charHandler} id='one'>1</button>
                <button value='2' onClick={this.charHandler} id='two'>2</button>
                <button value='3' onClick={this.charHandler} id='three'>3</button>
                <button value='=' onClick={this.equalHandler} id='equals'>=</button>
                <button value='0' onClick={this.charHandler} id='zero'>0</button>
                <button value='.' onClick={this.charHandler} id='decimal'>.</button>
              </div>
            </div>
        </div>
      );
      }
  }
  
  export default App;

You are more likely to get help if you post a GitHub repo or a StackBlitz/CodeSandbox.


Remove the setTimeout code inside the acHandler

Numbers do not display correctly within id=“display” : expected ‘3’ to equal ‘123’

Your display element is not updating correctly, entering 123 is only going to show each number, it needs to show all of them as the displayFormula element does.

Yes, thank you. I will deal with this. It is unlikely that this is due to an eval() error, so most likely the question remains open.

When I fixed what you were talking about, the error with eval() disappeared, empirically, I found out that it appears due to the timer. I still don’t understand why, but thank you.

I think the point is that the test doesn’t want to wait for the timer.

Just curious, why were you using a timer?

It reminded me of how old calculators worked. There was always a delay before the appearance of zero after a reset.
:upside_down_face:

Of course, it was possible to do this with CSS, but the idea came to me when I was writing the JS part, and the implementation was very simple.

Re-open!

I did some reworking of the code, it became much shorter, and I even noticed a bug that tests skip (this is due to two minuses in the expression, in the previous version of the code, for example, the expression 5–5 caused the error “invalid increment/decrement operand”, but the test did not notice it, I fixed it using replace() in equalHandler, see code).

But now the tests accurately interpret my application incorrectly, you can see for yourself, those operations to which it refers are performed correctly by hands.

Code
import logo from './logo.svg';
import './App.css';
import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      display: '0',
      displayFormula: '',
    };
    this.charHandler = this.charHandler.bind(this);
    this.acHandler = this.acHandler.bind(this);
    this.equalHandler = this.equalHandler.bind(this);
  }

  charHandler(event) {
    this.scrollToBottom();
    if (/0/.test(event.target.value)) {
      if (/^\-?0$/.test(this.state.display)) {
        this.setState({
          display: this.state.display
        });
      } else if (/^\D$/.test(this.state.display)) {
          if (/\-$/.test(this.state.display)) {
            if (this.state.displayFormula.length === 0 || /\D$/.test(this.state.displayFormula)) {
              this.setState({
                display: this.state.display + event.target.value,
              });
            } else {
              this.setState(state => ({
                display: event.target.value,
                displayFormula: this.state.displayFormula + state.display
              }));
            }
          } else {
              this.setState(state => ({
                display: event.target.value,
                displayFormula: this.state.displayFormula + state.display
              }));
          }
      } else {
          this.setState({
            display: this.state.display + event.target.value,
          });
      }
    } else if (/[1-9]/.test(event.target.value)) {
        if (/^0$/.test(this.state.display)) {
          this.setState({
            display: event.target.value
          });
        } else if (/^\-0$/.test(this.state.display)) {
            this.setState({
              display: '-' + event.target.value
            });
        } else if (/^\D$/.test(this.state.display)) {
            if (/\-$/.test(this.state.display)) {
              if (this.state.displayFormula.length === 0 || /\D$/.test(this.state.displayFormula)) {
                this.setState({
                  display: this.state.display + event.target.value,
                });
              } else {
                this.setState(state => ({
                  display: event.target.value,
                  displayFormula: this.state.displayFormula + state.display
                }));
              }
            } else {
                this.setState(state => ({
                  display: event.target.value,
                  displayFormula: this.state.displayFormula + state.display
                }));
            }
        } else {
          this.setState({
            display: this.state.display + event.target.value,
          });
        }
    } else if (/\./.test(event.target.value)) {
        if (/\./.test(this.state.display)) {
          this.setState({
            display: this.state.display
          });
        } else {
          this.setState({
            display: this.state.display + event.target.value
          });
        }
    } else if (/[^\d\.]/.test(event.target.value)) {
          if (/\d$/.test(this.state.display)) {
            if (/^0$/.test(this.state.display) && /\-/.test(event.target.value)) {
              this.setState({
                display: event.target.value
              });
            } else {
                this.setState(state => ({
                  display: event.target.value,
                  displayFormula: this.state.displayFormula + state.display
                }));
            }
          } else if (/[^\d\.]$/.test(this.state.display)) {
              if (/\-/.test(event.target.value)) {
                if (/\d$/.test(this.state.displayFormula)) {
                  this.setState(state => ({
                    display: event.target.value,
                    displayFormula: this.state.displayFormula + state.display
                  }));
                } else {
                    this.setState({
                      display: this.state.display
                    });
                }
              } else {
                  this.setState({
                    displayFormula: this.state.displayFormula.replace(/.$/, ''),
                    display: event.target.value
                  });
              }
            } else if (/\.$/.test(this.state.display)) {
                this.setState({
                  display: this.state.display
                });
            }
    }
  }

  acHandler() {
    this.setState({
      displayFormula: '',
      display: '0'
    })
  }

  equalHandler() {
    if (/\d$/.test(this.state.display)) {
      let fullFormula = this.state.displayFormula + this.state.display;
      let result = Number(eval(fullFormula.replace(/-{2}/g, '+')).toFixed(10)).toString();
      this.setState({
        displayFormula: '',
        display: Number(result),
      })
    }
  }

  scrollToBottom() {
    this.disp.scrollIntoView({
                              inline: 'end',
                              behavior: 'smooth'
                          });
  }

  render () {
    return (
      <div className='App'>
          <img src={logo} className='App-logo' alt='logo' />
          <div id='calculator'>
            <div id='fullDisplay'>
              <div id='displayFormula'>{this.state.displayFormula}
                <div id='display' ref={disp => { this.disp = disp; }}>{this.state.display}</div>
              </div>
            </div>
            <div className='buttons'>
              <button value='AC' onClick={this.acHandler} id='clear'>AC</button>
              <button value='/' onClick={this.charHandler} id='divide'>/</button>
              <button value='*' onClick={this.charHandler} id='multiply'>x</button>
              <button value='7' onClick={this.charHandler} id='seven'>7</button>
              <button value='8' onClick={this.charHandler} id='eight'>8</button>
              <button value='9' onClick={this.charHandler} id='nine'>9</button>
              <button value='-' onClick={this.charHandler} id='subtract'>-</button>
              <button value='4' onClick={this.charHandler} id='four'>4</button>
              <button value='5' onClick={this.charHandler} id='five'>5</button>
              <button value='6' onClick={this.charHandler} id='six'>6</button>
              <button value='+' onClick={this.charHandler} id='add'>+</button>            
              <button value='1' onClick={this.charHandler} id='one'>1</button>
              <button value='2' onClick={this.charHandler} id='two'>2</button>
              <button value='3' onClick={this.charHandler} id='three'>3</button>
              <button value='=' onClick={this.equalHandler} id='equals'>=</button>
              <button value='0' onClick={this.charHandler} id='zero'>0</button>
              <button value='.' onClick={this.charHandler} id='decimal'>.</button>
            </div>
          </div>
      </div>
    );
    }
}

export default App;

I only have a build version on github, if you need particulars, write about it. I will be grateful for your help!

P.s. And another test bug I found, in the original version of the code, when pressing “=” with a sequence of, for example, “2+”, the application threw out an error, but the test did not notice it.

I would really suggest you make it as easy as possible for people to test your code. Otherwise, you are much less likely to get help.


Switching to the old render method fixes it (or you can downgrade to React 17).

import React from 'react';
// import ReactDOM from 'react-dom/client'
import ReactDOM from 'react-dom';
import App from './App.jsx';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

More info


Then all that is left is the 5 + + 5 test.

I would really suggest you make it as easy as possible for people to test your code…

Yes, I understand that. The following project cycles should be uploaded to github in two versions of build and dev. On current projects, I also studied the deployment, so I implemented only the build version.

Thank you so much for your help, now everything is working as it should! FreeCodeCamp is Awesome! :smiling_face_with_three_hearts:

It may be worth placing links to the github, to the most common problems, somewhere in a more prominent place, this will help beginners better navigate.

We tried to fix the tests but they are still a problem. I have opened an issue asking where we should put the note about the test incompatibility with React 18.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.