Scripted tests are failing even with good code

Tell us what’s happening:
The scripted tests are telling me I’m failing. However, I’m running it manually and either the scripted tests are wrong or I am not understating the user stories properly. Can someone look at the testing and give me a push in the right direction?
specifically this item
8. I can see an element with corresponding id=“time-left”. NOTE: Paused or running, the value in this field should always be displayed in mm:ss format (i.e. 25:00).
time-left is not formatted correctly: expected ‘59’ to equal ‘60’
AssertionError: time-left is not formatted correctly: expected ‘59’ to equal ‘60’

Your code so far
https://cdpn.io/lkodanko/debug/xxbjOXX/YvMgOemwQYxM

Your browser information:

User Agent is: Mozilla/5.0 (X11; CrOS x86_64 12607.58.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.86 Safari/537.36.

Challenge: Build a Pomodoro Clock

Link to the challenge:
https://www.freecodecamp.org/learn/front-end-libraries/front-end-libraries-projects/build-a-pomodoro-clock

This is the test that is failing, specifically the second half:

      it(`I can see an element with corresponding id="time-left".
      NOTE: Paused or running, the value in this field should always be
      displayed in mm:ss format (i.e. 25:00).`, function() {
        const target = document.getElementById('time-left');
        assert.isNotNull(target);
        assert.strictEqual(
          getMinutes(target.innerText),
          '25',
          'time-left is not formatted correctly'
        );
        // Set session length to 60
        clickButtonsById(Array(35).fill(seshPlus));
        assert.strictEqual(
          getMinutes(target.innerText),
          '60',
          'time-left is not formatted correctly'
        );
      });

This line:

clickButtonsById(Array(35).fill(seshPlus));

is clicking the plus button 35 times to get it up to 60 minutes.

This:

        assert.strictEqual(
          getMinutes(target.innerText),
          '60',
          'time-left is not formatted correctly'
        );

is saying that it expects the time in the clock to be 60. Your test message says:

time-left is not formatted correctly: expected '59' to equal '60'

So, it is saying that it expected “60” but found “59”.

Not that when I refresh your app, and hit the plus button 35 times, the number near the plus is “60”, but the number in the clock is “59”. Specifically, the number in the clock does not increment on the first press.

Oh, and I forgot to mention - as a React developer, I would had that if I were grading this, I’d say that you component is too “large”, as in, there is too much JSX there. React practice would be to break those up into their own components instead of having one “god” component. I would have done something like:

- Clock
  - Title
  - Controls
    - Control
    - Control
  - Clock
  - Buttons
    - Button
    - Button

And I would reuse the component for the two controls, and just pass in what they need.

It may seem unnecessary for an app this small, but these are good habits that will save your life as the app gets bigger.

Kevin,

Thanks so much I had totally missed that. I literally set the code minLeft =sessionLength immediately after the increment.
case ‘session-increment’:
(this.state.sessionLength<=59)&&this.setState({sessionLength: this.state.sessionLength+1});
break;
default:
}
this.setState({minLeft: this.state.sessionLength});
Is it possible the setState on the increment hasn’t completed processing before I try to use is to update the timeLeft?
Either way I was able to fixed it by setting a local variable and using it in both places. Is there a better way to do that or is that the best way?
Thanks again for your help.
Luke

Is it possible the setState on the increment hasn’t completed processing before I try to use is to update the timeLeft?

I can’t see all of your original code so I can’t see what the problem was. I do have a couple of comments on the use of setState.

Remember that setState is async. If you run setState, There is no guarantee that it will be done by the time the next line of code gets run. If you need something that is dependent on state that is being set by setState, it is best to pass a callback function as the second parameter to setState.

Also, remember that there are two ways to call setState: with an object (the old way) and with a function (the new way). (We’re talking about the first parameter to setState. The new way is important if your new state is dependent on your old state or if you are calling setState in rapid succession. setState sill sometimes bundle them - not necessarily in order - and make adjustments that may get odd results. The new way of calling setState is supposed to fix that. So, when I see:

this.setState({sessionLength: this.state.sessionLength+1});

I see a new state that is depending on the old state and think it should be the new/functional way:

this.setState(oldState =>  ({ sessionLength: oldState.sessionLength + 1 });

Was that causing the problem? I don’t know. I look at what you have now and it seems OK, although I would probably still use the functional setState because your new state is sill dependent on the old state - it’s just hidden by a layer of abstraction. I don’t know if it matters, but that’s what I’d do. You can read about setState here.

Another comment - I see that you have multiple divs in your HTML. Traditionally that should all be in your JS if you’re doing react. Usually you just have one div that you target with your ReactDOM.render.

Kevin,

Again, your feedback is super helpful. Thank you!

Luke

Thank you, I’m not there yet but this does help to get unstuck.