How to test a React Snackbar did not appear with Cypress - reactjs

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
}

Related

How to track time with an Observable?

I have http observable and I want to add a timer to run parallel with it. For example, I want to show loading in at least 3s, so if http response before that, I want it to wait till timer emit after 3s. But if http took too long, say more than 5s, I'd like to throw an timeout error.
My code looks like this:
const tracker$ = timer(3e3).pipe(take(1));
const timeout$ = timer(5e3).pipe(take(1), map(() => { throw new Error('timeout!!!') }));
const query$ = combineLatest(http$, tracker$).pipe(map(([httpRes, tracker]) => (httpRes)));
this.loadData$ = race(timeout$, query$).pipe(// do next)
I'm using combineLatest and it works. But if http$ response with error in less than 3s (before tracker$ emits value), then combineLatest complete immediately with error, without waiting tracker$ to emit.
pipe catchError to http$ seems to keep it going but I also want to throw error because I want to catch error after the race and do something about it.
How can I archive this 3s effect?

After adding more products to woocomerce wordpress store graphql fails

anyone knows how to fix this graphql error? It appeared after i've added more woocomerce products. Url seems to be good because after deleting part of the woocomerce prducts everything stars to work like normal again.
ERROR
timeout of 30000ms exceeded
ERROR #gatsby-source-wordpress_111006
gatsby-source-wordpress It took too long for https://my-web-url/graphql to respond (longer than 30 seconds).
Either your URL is wrong, you need to increase server resources, or you need to decrease the amount of resources each
request takes.
You can configure how much resources each request takes by lowering your `options.schema.perPage` value from the default
of 100 nodes per request.
Alternatively you can increase the request timeout by setting a value in milliseconds to `options.schema.timeout`, the
current setting is 30000.
GraphQL request to https://my-web-url/graphql failed.
The output is quite self-explanatory. You've reached the timeout threshold because of the addition of more data to fetch.
As it has been prompted, you can add a bunch of options to gatsby-sourde-wordpress to customize that limit:
{
resolve: `gatsby-source-wordpress`,
options: {
schema: {
timeout: 30000,
},
},
}
The timeout, by default takes the value of 30000ms.
Additionally, you can change the number of nodes fetched by page(perPage).
Mixing both customizations:
{
resolve: `gatsby-source-wordpress`,
options: {
schema: {
timeout: 30000,
perPage: 100,
},
},
}
Play around increasing those default values to see if your requests succeed.
To fix this issue you need to raise the timeout in your gatsby-config.js file by adding options schema.
options: {schema: { timeout: 1000000,},}
But solely doing this will probably not be enough as if you are getting timeout error your wordpress server is either already overloaded or will be shortly. You need to raise allocated memory in your wordpress server. You can do that by using some FTP software like filezilla and adding this line to wp.config file. define( ‘WP_MEMORY_LIMIT’, ‘512M’ ); If you don't have as much data you should chose lower number like 256MB.

React + redux warning logic running after 60 seconds

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)
})

AngularJS testing with Protractor- tests that used to pass now failing due to Waits timing out

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?

Background Geolocation Plugin: Track location and update database every 5 minutes

I'm currently developing a mobile app using AngularJS / Ionic 3.
I need to track at all time, if my users are within a radius of 100m of a certain geolocation (let's call it "Home Location". I need to know at all time which user is at his home location, and who is not (even when the app is running in background or is closed/ terminated).
I thought to realize this, using the Ionic Native Background-Geolocation plugin and the cordova-plugin-background-geolocation. My plan was, to check the users geolocation every 5 minutes and compare it to the home.
Case 1) If the distance between the two locations is < 100m I know the user is "at home". I would then update the user node in my database (Firebase) to mark the user as isAtHome: true and add a current timestamp.
Case 2) If the user is not within 100m of his home location I would mark him as isAtHome: false and add a current timestamp.
I need to update my database even in case the user didn't move, because I need to know that I received a current signal. Otherwise I don't know if he didn't move or turned off his smartphone, for example.
If I want to know, who of my users is at his home location, I would check the isAtHome-attributes and if they are set to true, I would check the timestamp to be sure that I have up-to-date data and the data was written within the last 15 minutes.
I tried many different things, but I'm not sure how to realize this with the Cordova Background Geolocation Plugin and if it's even possible.
My question is:
Is it possible to check the users geolocation every 5 minutes (even in background / terminated state) and call a function that updates my firebase DB accordingly? As described, I need to receive the location even if the user didn't move within the last 5 minutes.
If it isn't possible: Does anybody have an idea, of how to approach the requirements on another way?
Thank you very much for your help!
As described in the cordova-plugin-background-geolocation says, you can configure an interval in milliseconds for the plugin to get the location, see this example from the plugin github page:
backgroundGeolocation.configure(callbackFn, failureFn, {
desiredAccuracy: 10,
stationaryRadius: 20,
distanceFilter: 30,
url: 'http://192.168.81.15:3000/locations',
httpHeaders: { 'X-FOO': 'bar' },
maxLocations: 1000,
// Android only section
locationProvider: backgroundGeolocation.provider.ANDROID_ACTIVITY_PROVIDER,
interval: 60000, // <-- here
fastestInterval: 5000,
activitiesInterval: 10000,
notificationTitle: 'Background tracking',
notificationText: 'enabled',
notificationIconColor: '#FEDD1E',
notificationIconLarge: 'mappointer_large',
notificationIconSmall: 'mappointer_small'
});
The case is this interval property works only for Android. I would sugest a workaround like this:
public getLocation: boolean = true; // CREATE A BOOLEAN TO KNOW IF YOU CAN GET LOCATION
backgroundGeolocation.start( // i've never used this plugin, so i'm assuming this is what starts de background watcher
() => {
if(getLocation == true){
this.getLocation = false; // SET TO FALSE SO IT DON'T DO YOUR FUNCTION THE NEXT TIME IT GETS THE LOCATION
// DO YOUR CODE TO SAVE AND CHECK YOUR DATA
// IT'S BETTER IF YOU USE A PROMISE, ASYNC/AWAIT FOR THE SAVING CODE
yourSavingCodeFunction().then(() => {
setTimeout(()=>{
// AFTER 5 MINUTES, SET THE GETLOCATION TO TRUE SO IT CAN DO YOUR FUNCTION AGAIN
this.getLocation = true;
}, 500000);
});
}
},
(error) => {
// Tracking has not started because of error
// you should adjust your app UI for example change switch element to indicate
// that service is not running
}
);
If you haven't thought about your cases 1 and 2 we can work on this too. Hope this helps or can give you some ideas :D

Resources