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?

RonaldMcdonald
  • 576
  • 6
  • 7
  • 1
    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? – Hans Passant Jun 25 '18 at 14:46
  • 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 seeing – RonaldMcdonald Jun 28 '18 at 09:59
  • 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. – Roemer Aug 13 '18 at 07:12

4 Answers4

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);
Tanya G.
  • 136
  • 5
  • 1
    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). – Roemer Aug 13 '18 at 07:10
  • How do we implement that in a WPF progress bar? The visibility property is not showing up – Apoorv Mar 07 '20 at 20:28
2

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

}

Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178
0
private void RunProc()
{
Process.Start("exeName");
}


public async Task StartProcessAsync()
{
var result= await Task.Run(()=>RunProc());
//optional
Task.Delay(new TimeSpan.FromSeconds(5));
}
Vitalii
  • 86
  • 2
-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();
        }
    }
Antoine V
  • 6,998
  • 2
  • 11
  • 34
  • 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 problem – RonaldMcdonald Jun 28 '18 at 10:00