The error is warning: logic (L(COUNTDOWN_ADD)-1) is still running after 60s, forget to call done()? For non-ending logic, set warnTimeout: 0
I am building a countdown, in which someone can input a start time and end time. This may be running for an hour -- any idea why this console.log message is appearing?
This is intended behavior for v0.12. See changelog.
To fix it just do what error says - set warnTimeout to 0.
Here is the example.
const fooLogic = createLogic({
...
warnTimeout: 0, // default: 60000 (one minute)
})
Related
My React web application, reports errors to users via the Snackbar component. By default, Snackbars don't autohide for accessibility what if we do want to hide Snackbars automatically using the autoHideDuration parameter? In my case, I'm using 6000 milliseconds (i.e. 6 seconds).
How can I use Cypress to verify that no error message appeared on the screen?
I tried to detect that no Snackbar appeared with the following logic:
function errorSnackbarDoesNotExist(errorMessagePrefix) {
cy.get(".MuiSnackbar-root").should("not.exist");
cy.get("[id=idErrorSnackbar]").should("not.exist");
cy.get("[id=idErrorAlert]").should("not.exist");
cy.contains(errorMessagePrefix).should("not.exist");
}
However, when I forced an error to ensure that this function would detect an actual error, it did not work: none of the assertions in errorSnackbarDoesNotExist() failed as I wanted them to.
I could not find a Cypress recipe for testing a Snackbar/Toast which is asynchronous.
I did try adding a { timeout: 10000 } to the cy.get() statements, but that didn't work. I thought this was supposed to wait for 10 seconds (which is longer than the 6 seconds of my autoHideDuration). It seems like the timeout was not working, as reported also as a Cypress issue Timeout option not respected for .should('not.exist') #7957.
Someone asked a similar question but they wanted to know how to manipulate the system internally (e.g. by a stub) to cause an error. In my case, I'm not asking about how to cause the error, I'm asking about how to detect that NO error was reported to the end user.
I got it to work by adding a short timeout instead of a long one, as follows:
function errorSnackbarDoesNotExist(errorMessagePrefix) {
cy.get(".MuiSnackbar-root", { timeout: 1 }).should("not.exist");
cy.get("[id=idErrorSnackbar]", { timeout: 1 }).should("not.exist");
cy.get("[id=idErrorAlert]", { timeout: 1 }).should("not.exist");
cy.contains(errorMessagePrefix, { timeout: 1 }).should("not.exist");
}
An article about the Cypress "should" assertion helped me understand that a short timeout, not a long timeout was what's needed. With the long timeout, Cypress may have detected the Snackbar but since it waited long enough for the Snackbar to disappear, maybe it only paid attention to the final state of the screen at the end of the timeout period.
I'll provide a deeper analysis as to why cy.get(".MuiSnackbar-root", { timeout: 10000 }).should("not.exist"); may not have been doing what I intended. Here's what I think happened, second by second:
Second
Activity
0
Application threw an error and displayed the Snackbar. Snackbar detected so should("not.exist") was false but the timeout was 10 seconds so it tried again.
1
Snackbar still detected but there's 9 seconds left to wait for cy.get(".MuiSnackbar-root", { timeout: 10000 }).should("not.exist") to become true
2
Snackbar still detected but there's 8 seconds left to wait for cy.get(".MuiSnackbar-root", { timeout: 10000 }).should("not.exist") to become true
...
...
6
Snackbar hidden and since cy.get(".MuiSnackbar-root", { timeout: 10000 }).should("not.exist") is now true, it stops waiting for the timeout and Cypress considers the validation as passed
So I think the solution is to change the Cypress timeout to a duration shorter than the autoHideDuration instead of longer. I found that a timeout of 1 millisecond was enough to make Cypress detect the unwanted Snackbar. I'm not sure if that is long enough. Maybe it needs to be something squarely in the middle of the 6 seconds.
Just a note about { timeout: 10000 } - its not a wait, it's the period of time that the command will retry if it fails.
On that basis, it's possible if the snackbar is hidden, then you trigger the error the code runs before the snackbar is displayed.
I'm assuming that even with the auto-hide feature, the snackbar will always appear on errormessage and then disappear after 6 seconds.
In which case you need an on-off type test
function errorSnackbarDoesNotExist(errorMessagePrefix) {
cy.get(".MuiSnackbar-root").should("be.visible"); // existence is implied
cy.get(".MuiSnackbar-root", { timeout: 6100 }).should("not.exist");
...
}
Or if you don't like your test waiting the 6 seconds, try adding cy.clock()
function errorSnackbarDoesNotExist(errorMessagePrefix) {
cy.get(".MuiSnackbar-root").should("be.visible"); // existence is implied
cy.clock()
cy.tick(6000) // move app timers +6s
cy.get(".MuiSnackbar-root").should("not.exist");
...
cy.clock().then(clock => clock.restore()) // unfreeze timers
}
I'm trying to make a timer for my quiz app. I have a setinterval that runs every 20 ms and increments a number by 0.1 starting from 0 to 100. I have noticed however that it actually runs for 21 seconds instead of 20 while both the timer and the progress bar seemingly works fine.
Here's a minimum example of a stackblitz to showcase my problem.
I've been using multiple phone's stopwatches to check and it always runs for 21 seconds which bothers my ocd.
Can someone explain to me why it happens? It's the same if i use bigger values for the setinterval frequency.
Hmm, it's hard to see exactly what the problem is, but you've got a few issues in the code that could be the cause.
First, you don't need to have the timerWidth as a state property - this is essentially derived state that you can calculate based on secondsRemaining. If we create some constants to represent the timing:
const TIMEOUT_SECS = 20;
const INTERVAL_MILLIS = 50;
Then we can calculate the width based on how many seconds are remaining:
const timerWidth = ((TIMEOUT_SECS - secondsRemaining) / TIMEOUT_SECS) * 100;
Now, you can simplify your useEffect where you create the timer - and crucially, we can add answer as a dependency for the effect, because you don't need to run this effect on every render. You only need to re-run the effect if answer changes.
useEffect(() => {
if (answer === null) {
timerRef.current = setInterval(() => {
setSecondsRemaining(prev => Math.max(0, prev - (INTERVAL_MILLIS / 1000)));
}, INTERVAL_MILLIS);
}
return () => {
clearInterval(timerRef.current);
};
}, [answer]);
Notice here I'm also using the form of setState which modifies the state based on its previous value - this is crucial because if we change the code to this:
setSecondsRemaining(Math.max(secondsRemaining- (INTERVAL_MILLIS / 1000), 0));
We've introduced a bug - the value of secondsRemaining is captured when the effect runs (i.e. we've created a closure). Using this code will cause the timer to look like it only updates once.
Finally - you need to make sure you stop the timer once it reaches zero (or reset the timer, or whatever you want to do):
useEffect(() => {
if (secondsRemaining <= 0) {
clearInterval(timerRef.current);
}
}, [secondsRemaining]);
Here's a StackBlitz that puts it all together. I added some logging for starting/stopping the timer, and when I ran it I got:
START 2021-08-02T07:09:05.630Z
STOP 2021-08-02T07:09:25.631Z
One more thing to remember - using the interval to count time is super unreliable - you're not guaranteed that you'll get called at the interval you specify (it all depends on the browser). A more reliable way would be to instead store the time when the timer starts, and then work out how much it's changed each time the interval is called back.
About 6 months or so ago I started developing an automated test suite for an AngularJS application developed by my company, using Protractor.
After I had been working on this for a couple of months, some other work came up which I had to prioritise over the test suite, and so I haven't looked at it since around the end of November/ December last year.
When I stopped working on it, I made sure that everything that I had done up to that date was in a fully working state (commented/ removed the tests I had started working on but hadn't finished, etc), and committed that git branch. At this point, I was able to run all of the tests I had written up until then using the command protractor conf.js, and I could see that they were all passing as expected.
I recently checked my testing branch out again, as I have a day or two in between other projects, and thought I could make use of the time by working on the testing again.
The first thing I did once I had checked out the testing branch, was to try running my test scripts again, to ensure everything I had implemented so far was still working.
However, while most of the tests do still pass, a few of them are now failing due to time outs, even though I had made sure that all of the timing elements were working correctly before I shelved the testing for a while.
I have tried increasing the times that my tests should sleep or wait for things at the points at which they are failing, but this doesn't seem to have made a difference.
The particular tests that are now failing due to time outs are:
1.
it('should navigate to the Config/Platform page & check the values are all correct', function() {
browser.waitForAngularEnabled(false);
browser.actions().mouseMove(configMenuBtn).perform();
browser.wait(EC.visibilityOf(pageConfigPlatformBtn), 8000).then(browser.sleep(5000).then( /*ERF(14/11/2017 # 1630) browser.sleep() required to give DialogMgr service time to complete */
pageConfigPlatformBtn.click().then(function(){
browser.sleep(10000); /*ERF(14/11/2017 # 1640) This line is needed- because of how the form HTML is created, it needs time to be replaced by configured HTML that is displaying the required fields */
var eth0Mode = element(by.model('modelinstances.platform.eth_0_mode'));
var eth0Address = element(by.model('modelinstances.platform.static_ip.eth_0_address'));
var eth0Netmask = element(by.model('modelinstances.platform.static_ip.eth_0_netmask'));
var eth0gateway = element(by.model('modelinstances.platform.static_ip.eth_0_gateway'));
var eth1mode = element(by.model('modelinstances.platform.eth_1_mode'));
var eth1Address = element(by.model('modelinstances.platform.static_ip.eth_1_address'));
var eth1netmask = element(by.model('modelinstances.platform.static_ip.eth_1_netmask'));
var eth1gateway = element(by.model('modelinstances.platform.static_ip.eth_1_gateway'));
expect(browser.getCurrentUrl()).toMatch(moxaConfigPlatformUrlRegExpPattern);
expect(eth0Mode.getAttribute('value')).toBe("Static IP");
expect(eth0Address.getAttribute('value')).toBe("192.168.1.127");
expect(eth0Netmask.getAttribute('value')).toBe("255.255.255.0");
expect(eth0gateway.getAttribute('value')).toBe("192.168.1.1");
expect(eth1mode.getAttribute('value')).toBe("Static IP");
expect(eth1Address.getAttribute('value')).toBe("192.168.2.127");
expect(eth1netmask.getAttribute('value')).toBe("255.255.255.0");
expect(eth1gateway.getAttribute('value')).toBe("");
})));
})
The failure message for this test is:
App should navigate to the Config/Platform page & check the values are all correct
Message:
Failed: Wait timed out after 8002ms
Stack:
TimeoutError: Wait timed out after 8002ms
2.
it('should navigate to the Config/Date/Time page', function() {
browser.waitForAngularEnabled(false);
browser.actions().mouseMove(configMenuBtn).perform();
browser.wait(EC.visibilityOf(pageConfigDateTimeBtn), 2000).then(browser.sleep(1000).then( /*ERF(14/11/2017 # 1630) browser.sleep() required to give DialogMgr service time to complete */
pageConfigDateTimeBtn.click().then(function() {
expect(browser.getCurrentUrl()).toBe(VM + '/#/config/systemtime');
})));
})
The failure message for this test is:
App should navigate to the Config/Date/Time page
Message:
Failed: Wait timed out after 2023ms
Stack:
TimeoutError: Wait timed out after 2023ms
3.
it('should navigate to the Tag Browser page (final test)', function() {
console.log("Start final Tag Browser page test");
browser.waitForAngularEnabled(false);
browser.wait(EC.visibilityOf(pagesMenuBtn), 10000).then(
browser.actions().mouseMove(pagesMenuBtn).perform().then(
browser.wait(EC.visibilityOf(pageConfigDateTimeBtn), 2000).then(browser.sleep(1000)).then( /*ERF(14/11/2017 # 1650) browser.sleep() required to give DialogMgr service time to complete */
browser.wait(EC.visibilityOf(pageTagBrowserBtn), 12000).then(
pageTagBrowserBtn.click().then(
function() {
console.log("Tag Browser menu button clicked");
}).then(
browser.wait(EC.visibilityOf(tagBrowserPageTagsLink), 20000).then(
function(){
console.log("End Tag Browser page test (then call)");
expect(browser.getCurrentUrl()).toBe(VM + '/#/pages/tagbrowser');
}
)
)
)
)
)
);
});
The failure message for this test is:
App should navigate to the Tag Browser page (final test)
Message:
Failed: Wait timed out after 2009ms
Stack:
TimeoutError: Wait timed out after 2009ms
I have tried increasing the times that the wait() calls are being passed, but this hasn't resolved the issue.
I have read in the past that automated testing can be quite flakey, and that changes to the environment in which they're run can cause them to fail- so I'm guessing it's possible that because my computer will have changed since the tests were last run successfully (i.e. new software installed), this may be causing the tests to fail...?
Is there a method of 'best practice' for resolving this sort of issue with automated testing, or is just a case of having to go back and tweak my test scripts until they start passing again?
It's probably worth mentioning that all of my test are written in a spec.js file, and that these tests which failed are the last 3 of 18 test scripts in that file (i.e. the first 15 all still pass).
Anyone have any ideas how I can resolve this/ get my tests passing again?
I'm attempting to create a test plan when a certain value is reached, then some functionality happens. The test plan consists of multiple threads running with a loop, and when some condition is reached I'd like to fire an HTTP request .
I'll drill down to the guts of it:
In my test I have logic in a looping way with multiple threads, and when a condition is met (the condition is met every 10 seconds) then I need to iterate through a value that it's value should be saved from the previous iteration - that value which I defined is a property (inside user.properties) - startIndex = 0 (initialized to 0).
So I've made a While Controller which it's condition is like this:
${__javaScript(${__P(startIndex,)}<=${currBulk},)}
And I expect the HTTP request, which depends on startIndex value inside the while to be executed when startIndex<=currBulk variable.
Inside the While Controller the HTTP request should to be fired until all indexes are covered, and I've written it like this inside BeanShell PostProcessor:
int startIndexIncInt = Integer.parseInt(props.getProperty("startIndex")); //get the initiated index of the loop
startIndexIncInt = startIndexIncInt + 1; //increment it and see if needed to fire the request again, by the original While condition
vars.put("startIndexIncIntVar", String.valueOf(startIndexIncInt));
props.put("startIndex",vars.get("startIndexIncIntVar")); //the property incremental and update
So, I designed it like in order that in the next time (after 10 more seconds) I'll have an updated startIndex that will be compared to the new currBulk (which is always updated by my test plan).
And I just cant have it done . I keep receiving errors like:
startIndexIncInt = Integer.parseInt(props.ge . . . '' : Typed variable declaration : Method Invocation Integer.parseInt
Needless to say that also the var startIndexIncIntVar I defined isn't setted (I checked via debug sampler).
Also, my problem isn't with the time entering the while, my problems are basically with the variable that I should increment and use inside my HTTP request (the while condition, and beanshell post processor script)
Just for more info on it, if I'd written it as pseudo code it would look like this:
startInc = 0
----Test plan loop----
------ test logic, currBulk incremented through the test-----
if(time condition to enter while){
while (startIndex <= currBulk){
Send HTTP request (the request depends on startIndex value)
startIndex++
}
}
Please assist
It appears to be a problem with your startIndex property as I fail to see any Beanshell script error, the code is good so my expectation is that startIndex property is unset or cannot be cast to the integer. You can get a way more information regarding the problem in your Beanshell script in 2 ways:
Add debug() command to the beginning of your script - you will see a lot of debugging output in the console window.
Put your code inside try block like:
try {
int startIndexIncInt = Integer.parseInt(props.getProperty("startIndex")); //get the initiated index of the loop
startIndexIncInt = startIndexIncInt + 1; //increment it and see if needed to fire the request again, by the original While condition
vars.put("startIndexIncIntVar", String.valueOf(startIndexIncInt));
props.put("startIndex", vars.get("startIndexIncIntVar")); //the property incremental and update
} catch (Throwable ex) {
log.error("Beanshell script failure", ex);
throw ex;
}
this way you will be able to see the cause of the problem in jmeter.log file
Actually it appears that you are overscripting as incrementing a variable can be done using built-in components like Counter test element or __counter() function. See How to Use a Counter in a JMeter Test article for more information on the domain.
My requirement was that whenever there was an error in the Jmeter execution, there should be a delay before starting the next iteration.
"Start Next Thread Loop" is selected at the Thread Group level for Sampler error. Due to this Jmeter will start a new Iteration if there is any error during the execution.
For this purpose I have used Beanshell Timer at the start of the Iteration. Following code is added for delay if the response code is anything other than "200"
String code = prev.getResponseCode();
if(code!="200"){
log.info("::::::::::::::::::::::::::::Response Code = "+code);
log.info("sleep for 10sec");
return 10000;
}
else
return 0;
Please let me know if there are any better ways of doing this.
I believe the prev.getResponseCode() can also be used to do any kind of cleanup task, in case there is any error.
Like for example, if a user logs into the application and got an error before doing logout. We can test at the start of the iteration if the previous response code is in error, if so, we can make the user logout of the application.
You can do this using:
If Controller that will check if last response was in error or not using
${__jexl2("${JMeterThread.last_sample_ok}" == "false",)}
Test Action that will be used to Start Next Thread Loop
Test plan would have the following layout: