CoffeeScript function syntax with nesting - coffeescript

I've come across a use of functions in JavaScript that I can't seem to convert, correctly, to CoffeeScript syntax. I'd appreciate it if someone could let me know how to do this:
JavaScript version:
node.addEventListener('mousedown', () => {
setTimeout(() => {
console.log('pressed');
return;
}, 3000);
});
The function setTimeout expects 2 parameters - a function and a duration in milliseconds.
Here's my first attempt at converting to CoffeeScript:
node.addEventListener 'mousedown', () =>
setTimeout () =>
console.log 'pressed'
return, 3000
return
This just gives me an error "unexpected comma" on line 4. So, I tried putting the duration on a separate line but, depending on whether I indent it one level or two, it just becomes part of the function code of either the function being passed to node.addEventListener (2nd parameter) or the function being passed to setTimeout (1st parameter).

You need to move both the comma and 3000 to a new line. The following code:
node.addEventListener 'mousedown', () =>
setTimeout () =>
console.log 'pressed'
return
, 3000
return
compiles to
node.addEventListener('mousedown', () => {
setTimeout(() => {
console.log('pressed');
}, 3000);
});
Tested here.
Another option is to wrap the inner function in parentheses:
node.addEventListener 'mousedown', () =>
setTimeout (() =>
console.log 'pressed'
return), 3000
return

Related

clearInterval and eventListener

My problem is, I'm not being able to use the 'setInterval' attached to a button and use another one to stop it with 'clearInterval'.
My thought process:
Since clearInterval() would need a target, I stored the setInterval() inside a variable. However, I noticed that setInterval() starts running without being triggered by the eventListener attached to it. I was expecting this behaviour of firing on its own only if I had put setInterval() out in the open without being stored on a variable and on the global scope.
So then I tried to encapsulate it inside a function, only this time the clearInterval() seemed to 'lose' the target.
I had a look on some situtations and couldn't find an explanation that would satisfy my case. Right now it looks like I can't have both ways (a btn to 'fire' the timer and a btn to shut it off).
I don't know if this is a matter of scope,event handling or targeting. Had a look on HTMLStandard but couldn't make much use of it.
Thank you
<script>
let repeater = function () {
setInterval(() => {
console.log('loading');
}, 1000);
};
const startButton = document.querySelector('#firstB');
const stopButton = document.querySelector('#secondB');
startButton.addEventListener('click', repeater);
stopButton.addEventListener('click', () => {
clearInterval(repeater);
console.log('finished');
});
</script>
const startButton = document.querySelector("#firstB");
const stopButton = document.querySelector("#secondB");
let repeater;
startButton.addEventListener("click", function () {
repeater = setInterval(() => {
console.log("loading");
}, 1000);
});
stopButton.addEventListener("click", () => {
clearInterval(repeater);
console.log("finished");
});
This should work.

How exactly does useEffect's return work? Why is the code preforming like it does?

I'm practicing react hooks and I'm creating a very simple stopwatch app. Currently, my code is doing exactly what I want it to do but I do not understand why it works. When I hit start, the setTimeouts run and constantly update the time state. When I hit stop, it clears the timeout. Why does it clear the timeout when I do not explicitly tell it to. Also, based on the react docs, the return in useEffect will only run when the component unmounts. However, I threw console.logs inside and saw that it runs the returned callback every time useEffect is called. Finally, I removed the returned callback and saw that it doesn't actually clear the timeout when I hit stop. Can someone help me dissect this?
import React, {useState, useEffect} from 'react';
function Stopwatch(){
const [time, setTime] = useState(0);
const [start, setStart] = useState(false);
useEffect(() => {
let timeout;
if (start) {
timeout = setTimeout(() => {setTime(currTime => currTime + 1);}, 1000);
}
return () => {
clearTimeout(timeout);
}
});
return(
<>
<div>{time}</div>
<button onClick={() => setStart(currStart => !currStart)}>{start ? "Stop" : "Start"}</button>
</>
)
}
export default Stopwatch
Why does it clear the timeout when I do not explicitly tell it to?
In your implementation useEffect runs after every re-render because you didn't specify the dependencies array, so if you start the timer and then in the middle press stop the clean up function is going to run and the last timeout will be cleared
It goes like this,
The component mounts -> useEffect callback fires and returns a function -> when the component re-renders, the returned function is executed and the cycle goes back to running the useEffect callback.
What you probably read in the docs had an empty dependencies array which is the second argument of useEffect
useEffect(() => {
console.log('will only run when the component mounts for the first time')
return () => {
console.log('will only run when the component unmounts')
}
}, []) // nothing inside the dependencies array, run this once
A better implementation of your component will be like this
function Stopwatch(){
const [time, setTime] = useState(0)
const [start, setStart] = useState(false)
useEffect(() => {
// when start is false there is no reason to set up a timer or return a
// cleanup function so lets just exit early
if (!start) return
// start is true, set up the interval
const intervalId = setInterval(() => setTime(prevTime => prevTime + 1), 1000)
// return a cleanup function that will run only when start changes
// to false
return () => clearInterval(intervalId)
}, [start]) // run this effect only when start changes
const toggleStart = () => setStart(prevStart => !prevStart)
return(
<>
<div>{time}</div>
<button onClick={toggleStart}>{start ? "Stop" : "Start"}</button>
</>
)
}

Protractor tests break when adding comments

Some protractor tests are breaking when I include a comment beside them or a
.then(() => console.log("hello")) statement beside a promise element.
Works:
menuIcon.click().then(function () { expect(isWorking).toBeTruthy(); });
Doesn't work:
menuIcon.click().then(function () { expect(isWorking).toBeTruthy(); }).then(() => console.log('Verified menu is working');
Error:
Failed: stale element reference: element is not attached to the page document
However, using different text for the comment makes this work such as:
menuIcon.click().then(function () { expect(isWorking).toBeTruthy(); }).then(() => console.log('comment');
Why might this be? Without them it always passes.
Thanks :)

Changing protractor default timeout inside function

I have a function to be called in some of my protractor tests which does some tasks that take more than the protractor default timeout (which seems to be 60 seconds)
I've read that you should be able to change the default timeout with "jasmine.DEFAULT_TIMEOUT_INTERVAL", however with the following code, the timeout still happens before the 4 minutes I have set up. Since I want to reuse this test part in the future, I cannot simply add it as a parameter to the test function.
Here is the sample code, can anyone tell me what I'm doing wrong?
describe('reset data', function() {
it('should reset data', function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 240000;
browser.ignoreSynchronization = true;
// ... test code here
});
});
I get the following error, after the test fails after roughly 60 seconds:
Error: Timeout - Async callback was not invoked within timeout
specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
I have created two functions to override, then restore the default protractor timeouts: (Only tested in Chrome)
import { browser } from 'protractor';
export function DefaultTimeoutOverride(milliseconds: number) {
browser.driver.manage().timeouts().setScriptTimeout(milliseconds);
}
export function DefaultTimeoutRestore() {
browser.driver.manage().timeouts().setScriptTimeout(browser.allScriptsTimeout);
}
EDIT
I have now created a helper function ('itTO') that wraps Jasmine's 'it' statement and applies the timeout automatically :)
import { browser } from 'protractor';
export function itTO(expectation: string, assertion: (done: DoneFn) => void, timeout: number): void {
it(expectation, AssertionWithTimeout(assertion, timeout), timeout);
}
function AssertionWithTimeout<T extends Function>(fn: T, timeout: number): T {
return <any>function(...args) {
DefaultTimeoutOverride(timeout);
const response = fn(...args);
DefaultTimeoutRestore();
return response;
};
}
function DefaultTimeoutOverride(milliseconds: number) {
browser.driver.manage().timeouts().setScriptTimeout(milliseconds);
}
function DefaultTimeoutRestore() {
browser.driver.manage().timeouts().setScriptTimeout(browser.allScriptsTimeout);
}
use like this:
itTO('should run longer than protractors default', async () => {
await delay(14000);
}, 15000);
const delay = ms => new Promise(res => setTimeout(res, ms))
Try his one instead:
By using a recursive function to identify if it is present.
function checkIfPresent(maxSec, elm, blnPresent) {
if (maxSec > 0) {
browser.sleep(1000).then(function() {
elm.isPresent().then(function(bln) {
if (bln != blnPresent) {
checkIfPresent(maxSec - 1, elm, blnPresent)
}
});
});
}
}
If you pass checkIfPresent(300000, elm, true)
It will check if the object is present every second, within 5mins.
Hope it helps. :)
Previous Comment:
I agree with the comment.
It should be declared on config file (conf.js)
jasmineNodeOpts: {
onComplete: null,
isVerbose: true,
showColors: true,
includeStackTrace: true,
defaultTimeoutInterval: 1000000
}

How to I find an element with protractor?

It seems if I use element(by.css('#id')); protractor sometimes finds it, sometimes doesn't. Depends if the DOM is settled down or not. I've gone and some this:
getElementsByCss: function (cssVal) {
// return element.all((by.css(cssVal)));
return self.wait(function () {
return element.all((by.css(cssVal))).then(function (els) {
return els;
}, function () {
return false; // Don't fail, we want to retry
});
}, GET_ELEMENT_TIMEOUT, 'Elements not found by css: ' + cssVal);
},
which plays a game of retrying to get the element for some timeout period. We use 5 seconds. This seems to work, most of the time. When running locally we have no issues.
When we run on the cloud (sauce labs) they have exceedingly slow VMs. We still get random issues. Unfortunately these games have to be played everywhere, for example:
getText: function (el) {
return self.wait(function () {
return el.getText();
}, 1000, 'Could not get element text.');
},
or
expectBulletin: function () {
var el, text;
return self.wait(function () {
// Find the bulleting element, make sure it's visible and grab its text.
// If any of those three fail, try all of them again.
return self.getElementByCss('.bulletin')
.then(function (elm) {
el = elm;
return self.isElementVisible(el);
}, function () {
return false;
})
.then(function () {
return self.getText(el).then(function (text) {
return text;
}, function () {
return false;
});
}, function () {
return false;
});
}, 10000, 'Count not get bulletin text.')
.then(function (result) {
text = result;
return self.executeScript('arguments[0].click();', el.getWebElement());
})
.then(function () {
return self.isElementNotVisible(el);
})
.then(function () {
return text;
});
},
all the self.waits are just a browser.driver.wait wrapper...
wait: function (fn, timeout, msg) {
return browser.driver.wait(fn, timeout, msg);
},
This feels like a big pack of bandaids and its not working all the time. expectBulletin works 99% of the time locally, but when run remotely on the slow VMs, it works about 50% of the time. Sometimes the text comes back blank, or issues about clicking an invisible element or just not finding the bulletin element.
Is there any better way to do this?
it seems if I use element(by.css('#id')); protractor sometimes finds
it, sometimes doesn't.
You know that it returns a promise right? If you want to get the absolute value of an element, you have to handle its promise first.
Protractor waits for the page to be ready before doing any assertions. If your page is "ready" but some data is missing, there is something wrong with your angular application.