Automate validation of result based on auto clicking a button - protractor

There is a button on a webpage, If I click that button first time, it takes some time to get the status in progress. once it is in progress then If I click after sometime say 3 minutes then the status is coming as successful.
The problem here is I have to give sleep time between two clicks to verify the status and sometimes because of this sleep time, a status not in sync. For example I click a button and status in progress and if I click after 3 minutes, sometimes status is successful or sometimes it remains in progress which is failing my TC.
isn't there any way that button should be clicked automatically until status comes in progress and then I can verify the status. same for successful status as well.
I am using sleep between two clicks
browser.sleep(25000)
button.click();
expect(inprogress_class.getText()).toContain('in progress');
browser.sleep(100000) // waiting for a defined time to click a buttonassuming that status will be successful
button.click();
expect(successful_class.getText()).toContain('successful);
Expected: Button keeps on getting clicked until status changes
Actual: giving sleep time between click and waiting for status to change

Try the below option
To click for the first time and wait for InProgress State
await button.click();
await browser.wait(ExpectedConditions.textToBePresentInElement(await inprogress_class), 25000, 'The wait for inProgress state');
To click the button until we get the success try the below one
while (await successful_class.getText() !== 'successful') {
await button.click();
await browser.sleep(10000); // update the time with how often the button needs to be clicked
}
expect(await successful_class.getText()).toContain('successful);
Hope it helps you

If you can use async/await then it would be more easier otherwise you will have to use Promises chaining.
try with async/await approach :
await browser.wait(async () => {
await button.click();
var buttonText = await inprogress_class.getText();
return buttonText === 'in progress';
}, 180000);
expect(inprogress_class.getText()).toContain('in progress');
await browser.wait(async () => {
await button.click();
var buttonText = await successful_class.getText();
return buttonText === 'successful';
}, 180000);
expect(successful_class.getText()).toContain('successful);

Related

Timer.periodic is not cancelled when the condition is true

I"m using a method that checks if the user's email is verified every 5 seconds, the checkIsEmailVerified() is asynchronous since it needs to send a request to check if the user has verified his email.
void checkEveryDurationUserVerification() {
Timer.periodic(
Duration(seconds: 5),
(timer) async {
if (isUserVerified) {
timer.cancel();
}
print("another check");
await checkIsEmailVerified();
},
);
}
so here is what happens, when this method is executing, it shows "another check" every 5 seconds as I want, and so the checkIsEmailVerified().
so what I have ? is a fully working email verification checker every 5 seconds, and the email is not verified yet.
when I open my email inbox and verify my email, In the app it works the listener I gave to the isUserVerified is working because it's true, and it navigates me to the home page as I want, but the Timer is not canceled even the isUserVerified is true
The "another check" is still printing in the debug console, even if the isUserVerified is true and so it should cancel that Timer**
what I think:
that this behavior is related to making the Timer's callback asynchronous
what I expect:
I want the when the isUserVerified is true the Timer to be canceled, so it stopped working after verifying the user

Cancel execution of method after it starts in Flutter

Consider this method:
Future<void> methodWithAlotOfSteps()async{
callMethodA();
await callMethodB();
...
return ...;
}
which makes some computation. Suppose I want the user to be able to stop this process at any point in time (when he taps cancel button for example).
How can I stop the execution of the above method no matter what line in the method the "program counter" has reached when the user presses cancel.
I am looking for something like methodWithAlotOfSteps.cancel();.
I tried using CancelableCompleter, but even though the Future is cancelled and onCancel method of the completer is called, but the function continues execution.
I know I can set a boolean flag and check it after each "step" ("line", "call to a method"),such as :
Future<void> methodWithAlotOfSteps()async{
if(!completer.isCancelled)
callMethodA();
if(!completer.isCancelled)
await callMethodB();
...
return ...;
}
but is there a better way of doing this?
As #Jamesdlin suggested, the apparent way is to check the cancelable completer's state after each async gap:
class MyService{
CancelableCompleter completer = CancelableCompleter();
Future<void> doSomething() async {
doSomeSyncWork(); // Sync work
doAnotherSyncWork(); // Sync work
await doSomeAsyncWork(); // Async work, this will return control to event loop and make it possible to, for example, press a button to cancel the future.
// here we know we have lost control for a while, so we must check if we have been cancelled
if (completer.isCompleted) {
return;
}
doSomeMoreSyncWork();
await doSomeMoreAsyncWork();
// here we know we have lost control for a while, so we must check if we have been cancelled
if (completer.isCompleted) {
return;
}
...
completer.complete();
}
}

Execute a code after await function finishes

I have this scenario where I have a list of books that is populated with a listview builder via an API. And each list has an add button where a user can add the books into the local db (sqlite). I am trying to check on the tap the add button if the book already exists, the user will be alerted with a pop and won't be able to add.
This is the code where I check if the book exists in the DB or not. The function _checkBookExist gets called on the onPressed in button in the list.
My problem is, till the time SQL query gets executed, the rest of the statements finishes. Any elegant way to address the issue ? I tried using .then() and .whenComplete() but those didn't work either.
_checkBookExist(id, author, title, thumbnail) async {
final List<BookShelf> result = await bookshelfDb.bookExists(id);
// below statements where I check if the book exist
if (result.length == 0 || result[0].volumeid == id) {
final booksToAdd = BookShelf(
author: author,
volumeid: id,
thumbnail: thumbnail,
title: title,
dateAdded: date.toString());
// below statements adds the book into the DB
await bookshelfDb.addItem(booksToAdd).then((value) => {
SnackBarMessage.snackBar(context, "Added to Bookshelf", "Ok", 2000),
});
} else {
print("Book Exist");
}
}
await waits until asynchronous addItem is executed and only after the execution of the rest continues.
await bookshelfDb.addItem(booksToAdd);
SnackBarMessage.snackBar(context, "Added to Bookshelf", "Ok", 2000);

Forced to re-query element in order to fire click handler

I have a test that where I assert that my API request is supplying the correct params. I am using MSW to mock the api, and I supply a spy for the request handler:
test("supplies order direction descending if header button is clicked twice", async () => {
const mockHandler = jest.fn(handler);
server.use(rest.get(`${config.apiHost}/targets`, mockHandler));
// First request to /targets happens on render
render(<Route>{(props) => <TargetList history={props.history} />}</Route>);
const button = await screen.findByRole("button", { name: "Port" });
// Second request to /targets happens on button click
userEvent.click(button);
await waitFor(() => {
expect(mockHandler).toHaveBeenCalledTimes(2);
});
// Third request to /targets SHOULD happen here but doesn't
userEvent.click(button);
await waitFor(() => {
expect(mockHandler).toHaveBeenCalledTimes(3);
const lastCall = mockHandler.mock.calls[2];
const requestArg = lastCall[0];
expect(requestArg.url.searchParams.get("orderby")).toBe("port");
expect(requestArg.url.searchParams.get("direction")).toBe("descending");
});
});
The above code doesn't work, as firing the click event a second time on the button appears to do nothing. However, if I requery for the button, then I can successfully fire the handler:
test("supplies order direction descending if header button is clicked twice", async () => {
...
const button = await screen.findByRole("button", { name: "Port" });
// Second request to /targets happens on b utton click
userEvent.click(button);
await waitFor(() => {
expect(mockHandler).toHaveBeenCalledTimes(2);
});
// Third request to /targets now works!
const button2 = await screen.findByRole("button", { name: "Port" });
userEvent.click(button2);
await waitFor(() => {
expect(mockHandler).toHaveBeenCalledTimes(3); // SUCCESS!
...
});
});
Why do I have to re-query for the same element? Am I doing something incorrectly?
I do not have complete source code but I would assume you are doing something on your click event handler that would force react to render again and in that case old element would no longer be present on DOM and hence click event handler will not be invoked.
P.S: You can use react life cycle hooks to determine if component was re-rendered.

How to wait till progressbar disapper?

I want enter window and wait till element is present. Problem is, when i enter this window, this element is present and clickable, but after short time progressbar apper, and window is blocked till this progressbar works. How to wait properly for elements ?
I tried below code, doesn't work, but it show what i want obtain (click addButton, wait for progressbar or 5sec passed, and then wait for element id displayed.
this.openWindow = function(addButton, progressbar, targetElement){
addButton.click().then(function(){
browser.driver.wait(progressbar.isDisplayed(), 5000).then(function(){
browser.driver.wait(targetElement.isDisplayed(), 5000);
});
});
};
Checkout official documentation for stalenessOf:
You should do something like this
this.openWindow = function(addButton, progressbar) {
var EC = protractor.ExpectedConditions;
return addButton.click().then(function(){
return browser.driver.wait(EC.stalenessOf(progressbar), 5000, 'Progress bar was not hidden within 5 sec');
});
};
And then you can use your function like this
openWindow(addButton, progressbar).then(...)
The code above will be resolved when progress bar has been hidden or will fail if time is out.
If progress bar is not completely removed from DOM, you can also try invisibilityOf