UIVERI5 actions not waiting each other - sapui5

I have the following test:
it('Set month work schedule', function () {
Given.iLoadPage();
Given.iGoToCurrentWeek();
Given.iGoToToday();
When.onTheCalendarPage.iClearSelections();
When.onTheCalendarPage.iSelectMonthView();
// Here I have busy indicator and the application loads a bit
When.onTheCalendarPage.iMarkAllEmployees(true);
When.onTheCalendarPage.iCickAButton();
...
});
The problem is that the statements are not waiting each other and while my application is loading on the commented (in the code sample) place, The test is already on the "iClickAButton" which clicks a button that is still not visible because the app is loading.
What might be the reason for that? I tried every button click to go through isDisplayed() but id does not help as well.

Related

Why would fireEvent work but userEvent not work?

In short, I have a table row with an onclick event. I am getting this via
const row = screen.getByRole('row', { name: /My row/i })
await userEvent.click(row)
This does not trigger the event handler. However, if I do:
const row = screen.getByRole('row', { name: /My row/i })
fireEvent.click(row)
This works fine.
I know userEvent uses more events to simulate a row click, but the event handler works fine in the live application too. Are there any reasons why userEvent might not work?
Like most very strange things, the problem lied elsewhere. But for documentation purposes, this was due to the app rerendering while doing my assertions. What would happen was this:
App renders, making a bunch of API calls
My API call for my test finishes, say, get user
findByText('My User') passes and gets me my DOM element
Another API call finishes, re-rendering the component to show this data
The result of findByText is no longer the current active DOM element
click fires
As its no longer in the document, there's nothing to click/fire an event
I changed my previous lines to check for ALL data loads before grabbing my row and it seems to consistently be working. This means I have to assert things unrelated to my tests, but that may be due to my app having poor UX with things popping in as they load?
Either way, I'm not 100% confident this is the reason, but if
userEvent.click is not firing events, or
toBeInTheDocument is failing, even if findBy worked
It may be due to your app rerendering after you've asserted everything has loaded. Hope I can save someone else 3 days of suffering like I had to to find that simple fact...

When I am testing a GUI, an element appears and disappears too quickly

I am testing the GUI using the tools of Webdriver.io and mocha. The tests themselves are written in CoffeeScript. Some interface elements are loaded for a long time, and a rotating loading indicator appears. In order to continue the testing process, it is necessary to wait for the data to be fully loaded (that is, to wait until the loading indicator disappears). This process was performed using function (1):
wait_for_page_load = () ->
$('... load indicator selector ...').waitForDisplayed(20000)
$('... load indicator selector ...').waitForDisplayed(20000, true)
In the first line, I expect the moment when the download indicator becomes visible. In the second term I expect the disappearance of the loading indicator.
However, in the process, I was faced with a situation in which the download indicator appears and disappears too quickly. At the same time, I simply do not have time to “catch” the loading indicator, because at that moment, when I expect it to appear, it already disappears. At the same time, an error message is displayed in the console:
element ("... load indicator selector ...") still not displayed after 20000ms
I found a way out of this situation. When a similar problem occurred, I fixed only the disappearance of the loading indicator. This process was performed using function (2):
wait_for_page_load = () ->
$('... load indicator selector ...').waitForDisplayed(20000, true)
It should be noted that with the fast disappearance of the loading indicator, it is also impossible to do without waiting at all - in this case, new data will not have time to load.
However, in some situations, I cannot determine in advance exactly how long the loading indicator will be visible: sometimes it disappears almost immediately, and I cannot track the moment it appears, in these cases I have to use function (2); sometimes it rotates for a long time, and it is possible to track the moment of its appearance using the function (1).
Is it possible to write a universal function that will fix the appearance and disappearance of a graphic element, even if the element appears and disappears very quickly?
So far I have found the following way to solve the problem. In situations where it is necessary to wait for the loading indicator to disappear, I first time out one second, and then wait for the loading indicator to disappear.
utilities.wait_for_page_load = () ->
browser.pause(1000)
$('... селектор индикатора загрузки ...').waitForDisplayed(20000, true)
Thus, if the download indicator appeared and disappeared too quickly, then at the end of the timeout, it will no longer be on the screen, respectively, we automatically waited for the download indicator to disappear. If the download indicator hangs on the screen for a long time, then at the end of the timeout, we simply continue to wait for it to disappear.
The method is not ideal. Its main drawback is an increase in the total test run time. However, the method is universal and allows you to handle both situations described in the question.

Can I trigger sleeping background trigger from secondary tile of UWP app?

I have this code for creation of secondary tile:
var logo = new Uri( "ms-appx:///Assets/Square150x150Logo.png" );
var tile = new SecondaryTile( "TileID", "Tile Text", "ActivateChange", logo, TileSize.Default );
await tile.RequestCreateAsync();
then I have code in my App's OnLaunched(LaunchActivatedEventArgs args) for checking if App was launched with "ActivateChange" arguments:
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
if (!string.IsNullOrEmpty(args.Arguments) && args.Arguments == "ActivateChange")
{
//Doing some work
this.Exit();
return;
}
...
The problem is that when I click on secondary tile then splash screen appears, after it dissappears then it does some of my work and after that it exits the app.
What I would like for it to do is that when I click on secondary tile it will trigger some background task asociated with my App and this background task will do some of my work and then changes its state to sleeping or exits. I don't know how they work. I just know that I can have background task that is running all the time and triggers periodically on some time. But can I have background task that is somehow sleeping and can be triggered from secondary tile?
Thanks!
Live tiles are only meant for starting the app. The only difference between the primary and the secondary tile is that the secondary tile can pass an additional launch argument to the application, and you are already taking advantage of that.
In my opinion, it would be a strange experience for the user anyhow, if nothing seemed to happen when he clicked on the tile. Well, even having the application automatically quit when clicking on the secondary tile (as you are doing it now) is a strange behavior, akin to application crashing unless the user knows better.
It's difficult to suggest an appropriate alternative without knowing what you are trying to achieve. There is no way to trigger a background task by a user action from outside the application. You could use the ApplicationTrigger inside the app instead of doing the work directly which would allow you to close the app sooner. You can also look at the complete list of available triggers - it's all the classes ending in Trigger on the linked page. Maybe there's one there that would work better for you.

How do I implement "Cancel" button inside the method building data source in ModelController.m for Page View Controller

I have a Page View Controller that's implemented in 3 files. One of them, the ModelController.m implements "generateData" method, which basically just builds and formats all the pages for this Page View Controller. Inside this method, the first thing I do is I create a Progress Bar popup with "Cancel" button. Then, inside the while() loop, I keep building the pages and at the same time, every 10th page, I update the progress bar for the user to see that the application is still generating the output.
Once the "generateData" method completes, i.e. builds all the pages (and there may be over 1,000 or even 10,000 pages depending on user input), it returns "self" to a method inside RootViewController.m, which in turn passes that generated data in "dataObject" to "viewWillAppear" in DataViewController.m, which finally displays pages in that object to the user.
It all works great, except the "Cancel" button. Because "generateData" method runs on the main thread, it blocks and the "Cancel" button becomes totally unresponsive. By "blocks" I of course mean it takes all CPU cycles, not allowing anyting else to execute, and it may take over a minute to generate 10,000 pages so I really want to allow the user to cancel the operation.
I tried to create a separate thread for the Progress Bar popup which contains Cancel button, but that won't work because all UI operations need to be performed on the application's main thread.
What almost seems to work, is when I put the "generateData" method on a separate thread and keep the Progress Bar on the main thread. This would work just fine, except that now "generateData" is put on another thread to execute in the background and returns immediately, hence returning empty "self" or rather empty "dataObject", causing a crash because there is nothing in that object yet to display.
So how can I check if the "generateData" thread is done, and "return self" ONLY when it's done? I can't really have some BOOL true/false variable and do it in a loop, because that loop on the main thread would be again blocking the "Cancel" button.
Or, alternatively, what is the correct way to implement the "Cancel" button on a lengthy method in iOS? Maybe I'm doing it all wrong, but for the life of me I can't find the right recipe for this.
Thank you in advance for the help, the code is rather extensive and that's why I didn't include any, but I hope my description gives you a good idea of what's going on. I can provide code if that would help.
The correct way to do this is to load the data asynchronously (on a background thread) and update the main (UI) thread to update the progress bar, etc... But you probably don't need a progress bar since you can probably load those pages faster than a user can flip them, so load 100 and let the user play while you continue to load the next 99,900... Except those may not be the exact numbers you should use....
If you continue to use the progress view and cancel button, then you would cancel the background thread when the user presses "Cancel", which would respond since your data generation is on a background thread...
Look into either Grand Central Dispatch or NSInvocationOperations
Here's a good tutorial by Ray Wenderlich to get you started.

lift disabling back button actions

I'm creating a transaction related site using lift. In here, there's a requirement to show a success page after the user action.
when i make action happen and press the browser's back button. it again goes to the previous page(before transaction page) making the transaction doable again. I need to limit this behavior. Is there any way of limiting the access to previous page by browser back button in lift.
There is no way to reliably stop the user from returning to the URL, but you can stop them from invoking the action more than once. Take a look at S.oneShot. From the Scala Doc:
All functions created inside the oneShot scope will only be called
once and their results will be cached and served again if the same
function is invoked
If you wrap the function that occurs when the button is pressed, even if the user does return to the page and click the button a second time, the body of the function shouldn't be invoked again.