VsixTesting
VsixTesting copied to clipboard
[Question] How to programmatically dismiss a modal dialog?
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)
}
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();
}