VsixTesting icon indicating copy to clipboard operation
VsixTesting copied to clipboard

[Question] How to programmatically dismiss a modal dialog?

Open tgeng opened this issue 5 years ago • 1 comments

Hi I am trying to add a test that triggers our custom item template wizard, which opens a WPF form to collect user input for template instantiation. How could I programmatically control inputs and click the "Finish" button to dismiss the modal dialog to resume the action? Currently my experimental instance just got stuck waiting for user input at the following line in my test

        [VsFact(Version = "[15.0-16.0)", UIThread = true)]
        async Task Test()
        {
            // open solution and set up stuff ...
            // stuck at following line waiting for user to interact with the WPF dialog opened by our custom wizard
            projectItems.AddFromTemplate(solution.GetProjectItemTemplate(templateName, "VC"),
                    itemName)
        }

tgeng avatar Sep 11 '19 22:09 tgeng

I recommend using a UI automation library like FlaUI. Here's one of my tests automating the New Database Connection dialog:

[VsFact]
public void DataConnectionDialog_works()
{
    var dialogFactory = (IVsDataConnectionDialogFactory)ServiceProvider.GlobalProvider.GetService(typeof(IVsDataConnectionDialogFactory));

    var dialog = dialogFactory.CreateConnectionDialog();
    dialog.AddAllSources();
    dialog.SelectedSource = PackageGuids.guidSqliteDataSource;

    // Start another thread to automate interaction with the modal dialog.
    new Thread(AutomateConnectionCreation).Start(dialog);
    
    dialog.ShowDialog();

    Assert.Equal("Data Source=:memory:", dialog.SafeConnectionString);
}

static void AutomateConnectionCreation(object obj)
{
    var dataConnectionDialog = (IVsDataConnectionDialog)obj;

    var application = Application.Attach(Process.GetCurrentProcess().Id);
    var automation = new UIA2Automation();
    var conditionally = automation.ConditionFactory;
    var mainWindow = application.GetMainWindow(automation);

    // Wait for the dialog to be shown
    Window dialog;
    do
    {
        Thread.Yield();
        dialog = mainWindow.ModalWindows.FirstOrDefault(w => w.Name == dataConnectionDialog.Title);
    }
    while (dialog == null);

    // Input file name
    dialog
        .FindFirstDescendant(
            conditionally.ByName("Database file name").And(conditionally.ByControlType(ControlType.Edit)))
        .AsTextBox()
        .Text = ":memory:";

    // Click OK
    dialog
        .FindFirstDescendant(
            conditionally.ByName(dataConnectionDialog.AcceptButtonText))
        .AsButton()
        .Invoke();
}

bricelam avatar Oct 12 '21 16:10 bricelam