How to find a JavaScript alert that is already open with WatiN

I am using a combination of SpecFlow, MSTests for unit testing, and WatiN for browser control to test our web application.

  • Visual Studio 2010
  • Class Library Style Project
  • SpecFlow
  • MS Test
  • WatiN

If a user submits our forms without filling in all the required fields, JavaScript appears alert

. I am trying to detect this popup using WatiN. The SpecFlow step that triggers the alert is different from the SpecFlow step, which asserts the popup exists, so waiting for the WatiN dialog handler doesn't work because the alert is already open.

Example Scenario SpecFlow:

Scenario: Form Fields are required
    # This step spawns the alert dialog
    When I click the "Save and Continue" button
    # Test fails here because the alert is already open
    Then I should see the validation error alert

      

Determining the step for When I click the "Save and Continue" button

[When(@"I click the ""(.*)"" button")]
public void WhenIClickTheButton(string buttonText)
{
    Button button = BitWeb.Browser.Button(Find.ByValue(buttonText).Or(Find.ByText(buttonText)));
    Assert.IsTrue(button.Exists, "No button with text '{0}' was found", buttonText);
    button.Click();
    browser.WaitForComplete();
}

      

Step definition for Then I should see the ... alert

:

[Then(@"I should see the validation error alert")]
public void ThenIShouldSeeTheValidationErrorAlert()
{
    var alert = new WatiN.Core.DialogHandlers.AlertDialogHandler();

    alert.WaitUntilExists();

    StringAssert.Contains(alert.Message, "An error has occurred. Check entire", "The validation error alert was not visible.");
}

      

The call alert.WaitUntilExists();

throws an exception:

WatiN.Core.Exceptions.WatiNException: The dialog is unavailable for 30 seconds.

By the time I assert that the alert dialog is visible, DialogHandler does not find the alert because it is already open.

How do I find an alert dialog that is already open with WatiN?

Update # 1: I'm leaning towards a solution that uses an object ScenarioContext.Current

, I'm just not sure how to wire everything together so that the browser doesn't wait 30 seconds every time it clicks a button to see if an alert box appears.

Update # 2: . After some research, clicking a button in one step causes the entire test environment to pause until the dialog is dismissed alert

. Clicking the OK button rejected the dialog, which allowed the test winner to proceed to the next step, in which I assert that the dialog is visible - a chicken or an egg scenario. The call button.ClickNoWait()

fixed the problem.

+3


source to share


3 answers


Let me write a more complete example of this for you:

public partial class Form1 : Form
{
    //
    // Your class properites/variables
    //
    AlertDialogHandler dialogHandler;


    [DllImport("User32.dll")]
    public static extern Int32 FindWindow(String lpClassName, String lpWindowName);

    //
    // Some methods/functions declarations
    //

    public void SomeInitMethod()
    {
          dialogHandler = new AlertDialogHandler()
          browse.AddDialogHandler(dialogHandler);
    }

    public void SampleMethod()
    {
       IntPtr hwndTmp = (IntPtr)FindWindow("#32770", "Dialog Title");
       WatiN.Core.Native.Windows.Window popUpDialog = new Window(hwndTmp);
       dialogHandler.HandleDialog(popUpDialog);
       //
       // The line above will find the OK button for you and click on it, 
       // from here you continue with the rest of your code.

    }

}

      



Hope this is a little bit, but clearer.

+1


source


As with the Win32 dialog box, you can get the handle of the popup (you know the style and you know the name of the window, if you don’t know the style you can recognize with WinSpy ++, just open the tool and bulls eye on the warning and it will give you all the details for that window)

// #32770 is the window style, just to make the search more confined.
IntPtr hwndTmp = (IntPtr)FindWindow("#32770", "This should be the title of the alert");
Window alertDialog = new Window(hwndTmp);

      



from here you should be able to treat it like a normal dialog inside WatiN (you have to use HandleDialog passing alertDialog as parameter etc., if not clear let me know and I'll amplify the answer).

0


source


I tagged @ ProgrammerV5's answer as a real answer since it led me to this code. I am only posting this answer because it relates directly to SpecFlow and WatiN.

I had three different SpecFlow steps, which clicked the button that spawned alert

, claim the alert box has the text I was expecting, and finally the final step to click OK.

Sample SpecFlow Script

Scenario: Doing something really important
    When I click the "Save and Continue" button
    Then I should see the validation error alert
    When I click OK in the validation error alert
    Then I continue on with the rest of this Scenario...

      

First, I created a quick helper method for finding a dialog alert

:

TestProject / helpers / StepHelper.cs

public static class StepHelper
{
    [DllImport("User32.dll")]
    public static extern Int32 FindWindow(String lpClassName, String lpWindowName);

    public static WatiN.Core.Native.Windows.Window GetAlertBox()
    {
        IntPtr hwndTmp = (IntPtr)FindWindow("#32770", "Message from webpage");
        return new WatiN.Core.Native.Windows.Window(hwndTmp);
    }
}

      

This allows you to capture a field alert

in Internet Explorer 8

Screenshot of an alert box in Internet Explorer 8

Step definition for When I click the "Save and Continue" button

:

[When(@"I click the ""(.*)"" button")]
public void WhenIClickTheButton(string buttonText)
{
    Button button = browser.Button(Find.ByValue(buttonText).Or(Find.ByText(buttonText)));
    Assert.IsTrue(button.Exists, "No button with text '{0}' was found", buttonText);
    button.ClickNoWait();
}

      

When called button.Click()

or button.ClickNoWait()

a warning window is displayed. Simply calling the method Click()

will cause WatiN to wait for this event to complete before returning from the method call. Since the warning window was open and blocking the page, the click event did not complete, which caused the call Click()

to be stopped completely. I got around this by calling ClickNoWait()

which is a "shoot and forget" way to click an element on the page. A warning window now appears, but the test runner can proceed to the next SpecFlow step.

Step definition for Then I should see the validation error alert

:

[Then(@"I should see the validation error alert")]
public void ThenIShouldSeeTheValidationErrorAlert()
{
    var alert = StepHelper.GetAlertBox();

    Assert.IsTrue(alert.Message.Contains("An error has occurred"),
        "An alert was found, but contained the wrong message ('{0}')", alert.Message);
}

      

Here I am using the method StepHelper.GetAlertBox()

I created earlier to get the handle to the object WatiN.Core.Native.Windows.Window

that represents the alert box. Then the simple Assert.IsTrue

, provisioning message shown in the alert is actually our Validation Failure message (we have another alert on this page).

Finally, we need to close the warning window.

Step definition for When I click OK in the validation error alert

:

[When(@"I click OK in the validation error alert")]
public void WhenIClickOKInTheValidationErrorAlert()
{
    var alert = StepHelper.GetAlertBox();

    Assert.IsTrue(alert.Message.Contains("An error has occurred"),
        "An alert was found, but contained the wrong message ('{0}')", alert.Message);

    alert.ForceClose();
}

      

Here we just get the alert box object from the helper and call ForceClose

to close the alert box, since clicking the OK or X in the top right corner does the same.

0


source







All Articles