My Pomodoro clock is functioning properly however I cannot pass test 14 and 16 even though I’ve been working on these project for almost 3 weeks now.
Test 14: When I click the element with the id of “session-decrement”, the value within id=“session-length” decrements by a value of 1, and I can see the updated value.
Test 16: I should not be able to set a session or break length to <= 0.
Specifically, test 16 is what bothering me since it’s properly the one causing the test 14 to not pass as well as the FFC tests taking too long to complete. One thing I noticed about test 16 it is says less or equal to zero. But when you looked at other projects, they’re all doing the same approach like me that is they are not allowing the session/break length be less than 1 and yet their code is passing.
What I find strange about these tests is my incrementing and decrementing functions are identical. If I can pass the incrementing tests, then I should be able to pass the decrementing tests too.
function App() {
const [sessionTimer, setSessionTimer] = React.useState(25);
const [breakTimer, setBreakTimer] = React.useState(5);
const [timerLeft, setTimerLeft] = React.useState(sessionTimer * 60);
const [timerType, setTimerType] = React.useState("Session");
const [pause, setPause] = React.useState(true);
const starter = React.useRef(null);
// Create function that will play the audio
const playAudio = () => {
const sound = document.getElementById("beep");
sound.play();
}
// Create function that will stop the audio
// const stopAudio = () => {
// const sound = document.getElementById("beep");
// sound.pause();
// }
// Create function that handles countdown
// If the timer greater than 0, decrement the timer by 1
const changeTime = () => {
if (timerLeft > 0) {
setTimerLeft((timerLeft) => timerLeft - 1)
}
// If the timer reaches 0, change the type of timer
if (timerLeft == 0) {
// If the type of timer is session, switch the type to break, set the timer to break, and play the audio
if (timerType == "Session") {
setTimerType("Break")
setTimerLeft(breakTimer * 60)
playAudio()
}
// If the type of timer is break, switch the type to session, set the timer to session, and play the audio
else {
setTimerType("Session")
setTimerLeft(sessionTimer * 60)
playAudio()
}
}
}
// If the timer is not paused, start the timer countdown
React.useEffect(() => {
if(!pause) {
const interval = setInterval(changeTime, 1000)
return () => clearInterval(interval)
}
})
// Create function that will handle time starter
const startTimer = () => {
setPause(false)
}
// Create function that will handle time stopper
const stopTimer = () => {
setPause(true)
clearInterval(starter.current)
}
// Create a function that will handle start and pause timer
const startAndPause = () => {
// If the timer is already paused, start the timer
if (pause) {
startTimer()
} else {
// If the timer is already started, pause the timer
stopTimer()
}
}
// Create a function that will reset the timer, timer type, and timer length to default and pause the timer
const handleReset = () => {
setSessionTimer(25);
setBreakTimer(5);
setTimerLeft(1500);
setTimerType("Session");
stopTimer();
};
// Create a function that will handle the decrement of session length
const handleSessionDecrement = () => {
if (sessionTimer === 1) {
return;
}
setSessionTimer(sessionTimer - 1);
if (timerType == "Session") {
setTimerLeft((sessionTimer - 1) * 60)
}
};
// Create a function that will handle the increment of session length
const handleSessionIncrement = () => {
if (sessionTimer >= 60) {
return;
}
setSessionTimer(sessionTimer + 1);
if (timerType == "Session") {
setTimerLeft((sessionTimer + 1) * 60)
}
};
// Create a function that will handle the decrement of break length
const handleBreakDecrement = () => {
if (breakTimer === 1) {
return;
}
setBreakTimer(breakTimer - 1);
if (timerType == "Break") {
setBreakTimer((breakTimer - 1) * 60)
}
};
// Create a function that will handle the increment of break length
const handleBreakIncrement = () => {
if (breakTimer >= 60) {
return;
}
setBreakTimer(breakTimer + 1);
if (timerType == "Break") {
setBreakTimer((breakTimer + 1) * 60)
}
};
// Create a function that will convert the timer into mm:ss format instead of seconds
const formatTime = () => {
let minutes = Math.floor(timerLeft / 60);
let seconds = timerLeft - minutes * 60;
if (minutes < 10) {
minutes = "0" + minutes;
}
if (seconds < 10) {
seconds = "0" + seconds;
}
return `${minutes}:${seconds}`;
};
return (
<div className='bg-dark'>
<div className="container">
<h1 className="text-light">Pomodoro Clock</h1>
<div id="break-label" className="text-light">Break Length</div>
<div id="break-length" className="text-light">{breakTimer}</div>
<button id="break-increment" className="btn btn-success btn-lg" onClick={handleBreakIncrement}><i className="fas fa-arrow-up"></i></button>
<button id="break-decrement" className="btn btn-danger btn-lg" onClick={handleBreakDecrement}><i className="fas fa-arrow-down"></i></button>
<div id="session-label" className="text-light">Session Length</div>
<div id="session-length" className="text-light">{sessionTimer}</div>
<button id="session-increment" className="btn btn-success btn-lg" onClick={handleSessionIncrement}><i className="fas fa-arrow-up"></i></button>
<button id="session-decrement" className="btn btn-danger btn-lg"><i className="fas fa-arrow-down" onClick={handleSessionDecrement}></i></button>
<div id="timer-label" className="text-light">{timerType}</div>
<div id="time-left" className="text-light"><h1>{formatTime()} </h1></div>
<button id="start_stop" className="btn btn-warning btn-lg" onClick={startAndPause}>{pause ? <i className="fas fa-play"></i> : <i className="fas fa-pause"></i>}</button>
<button id="reset" className="btn btn-warning btn-lg" onClick={handleReset}><i className="fas fa-sync-alt"></i></button>
<audio id="beep" src="https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav"/>
</div>
</div>
)
}
ReactDOM.render(
<App/>,
document.getElementById('root')
);
Hi, all! I’ve finished building 25 + 5 clock project and almost all features are working when tested manually. However, there are 4 tests that are still failing and they are:
When I click the element with the id of “session-decrement”, the value within id=“session-length” decrements by a value of 1, and I can see the updated value. Error: expected ‘25’ to equal ‘21’
I should not be able to set a session or break length to <= 0.
Value in element with id of “session-length” is less than 1.: expected ‘25’ to equal ‘1’
When a countdown reaches zero (NOTE: timer MUST reach 00:00), a sound indicating that time is up should play. This should utilize an HTML5 <audio> tag and have a corresponding id=“beep”. Error: Timer has reached zero but audio is not playing while it should.: expected true to be false
The audio element with id of “beep” must stop playing and be rewound to the beginning when the element with the id of “reset” is clicked.
Error: Audio element was not stopped when reset was clicked.: expected false to be true
I tried to fix these bugs for long time and read countless forum posts related to this challenge. Despite my best efforts, I wasn’t able to figure out what is causing this issues. Also, I tried to fix test 4 by creating a stopAudio() function but if I did this, it will cause other tests to fail and hence I comment out temporary.
Can you please guide me why this tests are failing? Thank you.
Not sure if you’ve already debugged this. I found a few things which could be causing the tests to fail.
For #1 and #2 tests, the issue is that you’ve placed onClick handler of session decrement inside the font awesome , i tag. Hence, the session decrement is triggered only if the button is clicked exactly at the center -on the arrow-down icon and doesn’t work if you click on the corners of the button.
For test #3, there seems to be a time lag although the time interval has been set to 1000. The below link could be useful.
Finally for test #4, setting the currentTime = 0 attribute for your audio ‘beep’ element inside the reset button handler should help.
That was very helpful, @manjupillai16! I didn’t noticed that I placed the session decrement function on the wrong place. This explains why that particular button is kinda acting funny whenever I clicked it.
Only 2 audio tests are left now. I will keep you updated when I stuck again.
Updated: 28/29 passed! Only third test is left and this one is kind of complicated. I’ll use the link you provided as a reference and see if this will fix it.
So when the timer reaches 00:00, it supposed to play sound and change the type of timer. But what it actually happens is there is a one second delay before the sound is played.
For example: what I expect is when the session reaches 00:00, it will change to break length 01:00 and play the sound. Instead of playing the sound at 01:00 precise, it plays the sound when the timer is 00:59. This explains why the last test is not passing.
One possible thing I can do is to play the sound when the time hits zero or at least below one. Problem is when I try change the timerLeft == 0 to timerLeft < 1 or timerLeft <= 0 or simply making any kind of change to the timer, not only it will fail the test, but it will also broke other tests.
All I’m saying is getting the last test to pass is going to be tough.
New update: I managed to pass test 3. It can now play sound at exact 00:00.
However, the 4th test is now failing and I don’t know why this happens. The test claims that the sound is not stopping to play when reset is clicked but this is not true. It definitely is stopping the sound from playing when I click the button.
I wonder if it’s because of the way I structured the code that prevents the test suite from recognizing that the sound has indeed rewind. Or maybe the test suite has a preferred way of stopping the sound as the error message has point out the hints: use the currentTime property of the audio element to rewind.
Anyhow, I’ll try to use currentTime property and see if this will satisfy the test requirements. Here’s the updated code:
function App() {
const [sessionTimer, setSessionTimer] = React.useState(25);
const [breakTimer, setBreakTimer] = React.useState(5);
const [timerLeft, setTimerLeft] = React.useState(sessionTimer * 60);
const [timerType, setTimerType] = React.useState("Session");
const [pause, setPause] = React.useState(true);
const starter = React.useRef(null);
// Create function that will play the audio
const playAudio = () => {
const sound = document.getElementById("beep");
sound.play();
}
// Create function that will stop the audio
const stopAudio = () => {
const sound = document.getElementById("beep");
sound.pause();
}
// Create function that handles countdown
// If the timer is greater than 0, decrement the timer by 1
const changeTime = () => {
if (timerLeft > 0) {
setTimerLeft((timerLeft) => timerLeft - 1)
}
// If the timer reaches 0, play the audio
if (timerLeft == 1){
playAudio();
}
// If the timer reaches 0, change the type of timer
if (timerLeft == 0) {
// If the type of timer is session, switch the timer type to break, set the timer left to break
if (timerType == "Session") {
setTimerType("Break");
setTimerLeft(breakTimer * 60);
}
// If the type of timer is break, switch the timer type to session, set the timer left to session
else {
setTimerType("Session");
setTimerLeft(sessionTimer * 60);
}
}
}
// If the timer is not paused, start the timer countdown
React.useEffect(() => {
if(!pause) {
const interval = setInterval(changeTime, 1000);
return () => clearInterval(interval);
}
})
// Create function that will handle time starter
const startTimer = () => {
setPause(false);
}
// Create function that will handle time stopper
const stopTimer = () => {
setPause(true);
clearInterval(starter.current);
}
// Create a function that will handle start and pause timer
const startAndPause = () => {
// If the timer is already paused, start the timer
if (pause) {
startTimer();
} else {
// If the timer is already started, pause the timer
stopTimer();
}
}
// Create a function that will reset the timer, timer type, and timer length to default and pause the timer
const handleReset = () => {
setSessionTimer(25);
setBreakTimer(5);
setTimerLeft(1500);
setTimerType("Session");
stopTimer();
stopAudio();
};
// Create a function that will handle the decrement of session length
const handleSessionDecrement = () => {
if (sessionTimer == 1) {
return;
}
setSessionTimer(sessionTimer - 1);
if (timerType == "Session") {
setTimerLeft((sessionTimer - 1) * 60)
}
};
// Create a function that will handle the increment of session length
const handleSessionIncrement = () => {
if (sessionTimer >= 60) {
return;
}
setSessionTimer(sessionTimer + 1);
if (timerType == "Session") {
setTimerLeft((sessionTimer + 1) * 60)
}
};
// Create a function that will handle the decrement of break length
const handleBreakDecrement = () => {
if (breakTimer == 1) {
return;
}
setBreakTimer(breakTimer - 1);
if (timerType == "Break") {
setBreakTimer((breakTimer - 1) * 60)
}
};
// Create a function that will handle the increment of break length
const handleBreakIncrement = () => {
if (breakTimer >= 60) {
return;
}
setBreakTimer(breakTimer + 1);
if (timerType == "Break") {
setBreakTimer((breakTimer + 1) * 60)
}
};
// Create a function that will convert the timer into mm:ss format instead of seconds
const formatTime = () => {
let minutes = Math.floor(timerLeft / 60);
let seconds = timerLeft - minutes * 60;
if (minutes < 10) {
minutes = "0" + minutes;
}
if (seconds < 10) {
seconds = "0" + seconds;
}
return `${minutes}:${seconds}`;
};
return (
<div className='bg-dark'>
<div className="container">
<h1 className="text-light">Pomodoro Clock</h1>
<div id="break-label" className="text-light">Break Length</div>
<div id="break-length" className="text-light">{breakTimer}</div>
<button id="break-increment" className="btn btn-success btn-lg" onClick={handleBreakIncrement}><i className="fas fa-arrow-up"></i></button>
<button id="break-decrement" className="btn btn-danger btn-lg" onClick={handleBreakDecrement}><i className="fas fa-arrow-down"></i></button>
<div id="session-label" className="text-light">Session Length</div>
<div id="session-length" className="text-light">{sessionTimer}</div>
<button id="session-increment" className="btn btn-success btn-lg" onClick={handleSessionIncrement}><i className="fas fa-arrow-up"></i></button>
<button id="session-decrement" className="btn btn-danger btn-lg" onClick={handleSessionDecrement}><i className="fas fa-arrow-down"></i></button>
<div id="timer-label" className="text-light">{timerType}</div>
<div id="time-left" className="text-light"><h1>{formatTime()} </h1></div>
<button id="start_stop" className="btn btn-warning btn-lg" onClick={startAndPause}>{pause ? <i className="fas fa-play"></i> : <i className="fas fa-pause"></i>}</button>
<button id="reset" className="btn btn-warning btn-lg" onClick={handleReset}><i className="fas fa-sync-alt"></i></button>
<audio id="beep" src="https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav"/>
</div>
</div>
)
}
ReactDOM.render(
<App/>,
document.getElementById('root')
);
As it turns out, I should’ve use the currentTime property to pass the final test as suggested by Manju Nair and FFC test. I thought I should only stop the sound from playing on click but nope! I should’ve stop the sound and rewind the sound length back to zero at the same time.
I still have one more test to pass from JavaScript Calculator and after that, I can claim the front end libraries certification.