Wait for application launch without using Thread.Sleep() using FLAUI
Asked Answered
J

4

7

I am new to using FLAUI and Automation Testing and would like to use it to test my system. At the moment I am using a Thread.Sleep() to wait till the application launches to then find the Login textbox. Is there a more efficient way to do this rather than using Thread.Sleep()?

At the moment i launch the application and use Thread.sleep(10000) to wait until the applicationis fully launched and that the logIn textbox is find-able before clicking on the control to input the password to enter the application. However I understand that Thread.Sleep is the worst way to tell the system to wait especially in automated tests. Could anyone offer any other things i could test out?

Jabez answered 25/6, 2018 at 14:40 Comment(3)
The code samples provided in the Github project docs don't do anything special after the Application.Launch() call. As you'd expect from a decent automation library. Did you try it? If that "doesn't work", have you considered asking the author for assistance?Cayenne
Believe me i have tried to ask for help, but at the moment there has been no reply. Not sure if they are just too busy or did not feel my question was worth an answer. Maybe there is an easy solution that i am not seeingJabez
Where did you ask for help? Don't see an issue in github and the tag flaui is missing here in your stackoverflow question. Also see the answer below with the Retry, which is the correct way.Warford
S
7

It is always the best to use Retry mechanism and wait until your main window loads and controls are visible. For example, after calling Application.Launch you can retry up to 30 seconds to find main window, and txtLogin in it:

        Retry.WhileException(() =>
        {
            using (var automation = new UIA3Automation())
            {
                Window mainWindow = Application.GetMainWindow(automation, TimeSpan.FromSeconds(60));

                Assert.IsNotNull(Mainwindow, "Main window is not found");

                TextBox loginTextBox = mainWindow.FindFirstDescendant(x => x.ByAutomationId("txtLogin")).AsTextBox();

                Assert.IsNotNull(loginTextBox, "txtLogin is not found");
            }

        }, TimeSpan.FromSeconds(30), null, true);
Sheepcote answered 2/8, 2018 at 11:33 Comment(2)
This is the correct way. Always try to use Retry instead of sleeps. Not only for startup but also for waiting for data to be loaded (like a retry while loading spinner is visible or other similar retry loops).Warford
How do we implement that in a WPF progress bar? The visibility property is not showing upMezereon
H
4

The question already has good answers, but I found another way to wait for any element (including main window) using the Retry class in FlaUI.Core.Tools.Retry class

[TestFixture]
public class SmokeTests
{
    private Application _theApp;
    private UIA3Automation _automation;
    private Window _mainWindow;
    private const int BigWaitTimeout = 3000;
    private const int SmallWaitTimeout = 1000;

    [SetUp]
    public void Setup()
    {
        _theApp = FlaUI.Core.Application.Launch(new ProcessStartInfo("YOUR_APPLICATION.exe", "/quickStart"));
        _automation = new UIA3Automation();
        _mainWindow = _theApp.GetMainWindow(_automation);
    }

    [TearDown]
    public void Teardown()
    {
        _automation?.Dispose();
        _theApp?.Close();
    }

    [Test]
    public void Foo()
    {
        // This will wait until the element is available, or timeout passed
        var examplesWrapPanel = WaitForElement(() => _mainWindow.FindFirstDescendant(cf => cf.ByAutomationId("ExamplesWrapPanel")));

        // This will wait for the child element or timeout 
        var exampleButton = WaitForElement(() => examplesWrapPanel?.FindFirstDescendant(cf => cf.ByAutomationId("Another Automation Id")).AsButton());

        // Do something with your elements 
        exampleButton?.WaitUntilClickable();
        exampleButton?.Invoke();
    }

    private T WaitForElement<T>(Func<T> getter)
    {
        var retry = Retry.WhileNull<T>(
            () => getter(),
            TimeSpan.FromMilliseconds(BigWaitTimeout));

        if (!retry.Success)
        {
            Assert.Fail("Failed to get an element within a wait timeout");
        }

        return retry.Result;
    }
}

}

Histogen answered 9/11, 2019 at 14:54 Comment(0)
O
0
private void RunProc()
{
Process.Start("exeName");
}


public async Task StartProcessAsync()
{
var result= await Task.Run(()=>RunProc());
//optional
Task.Delay(new TimeSpan.FromSeconds(5));
}
Osseous answered 28/6, 2018 at 20:23 Comment(0)
E
-1

Did you try this solution?

public static void LaunchApplication(string exePath, string arguments, bool waitForExit, bool waitForStart, int waitForStartTimeout)
    {
        ProcessStartInfo thisProcessInfo = new ProcessStartInfo();
        thisProcessInfo.CreateNoWindow = true;
        thisProcessInfo.UseShellExecute = false;
        thisProcessInfo.RedirectStandardOutput = false;
        thisProcessInfo.FileName = exePath;
        thisProcessInfo.Arguments = arguments;
        using(Process thisProcess = Process.Start(thisProcessInfo))
        {
            if(waitForStart)
                thisProcess.WaitForInputIdle(waitForStartTimeout);
            if(waitForExit)
                thisProcess.WaitForExit();
        }
    }
Enchantress answered 25/6, 2018 at 14:45 Comment(1)
Thankyou, however i do not believe it is what I am looking for. I have tried to implement it, there has been no change in terms of where i started with the problemJabez

© 2022 - 2024 — McMap. All rights reserved.