microsoft / WinAppDriver

Windows Application Driver
MIT License
3.69k stars 1.4k forks source link

Tests with Selenium from inside WPF Application don't work #620

Open GrahamDo opened 5 years ago

GrahamDo commented 5 years ago

Hi,

We have a WPF application that's designed to run tests against a particular website, and we're trying to test the WPF application using the WinAppDriver.

We can successfully test everything else about that application (Finding elements on the form, clicking them, etc, etc), but as soon as it comes to clicking a button that is supposed to open a Chrome window to perform tests on the website, nothing happens.

I've confirmed it's due to running from within my Appium Framework by running a test that does nothing other than logging in to our app, hitting a breakpoint, and manually taking over. By the time I get to clicking the aforementioned button, nothing happens.

Obviously, when I run the application outside of the test framework, and perform all the steps manually, everything works, Chrome is opened, it browses to the website, and does what it should (so it's not our code).

I've also tried running WinAppDriver.exe on a different port (thinking it may just be that Selenium uses the same port or something), but that had no effect.

Any help or suggestions you could give would be appreciated.

Graham

GrahamDo commented 5 years ago

Quick update: I had a suspicion it might be the chromedriver.exe that's now not present in the bin\debug of the Test project (when running the application from it's own project, it expects to find that executable in its startup folder).

I copied chromedriver.exe into the bin\debug directory of the test project, but that had no effect.

PandaMagnus commented 5 years ago

For my own understanding: is the button you're trying to click a WpfButton, and it's that button that launches Chrome?

Is the button being clicked and chrome isn't being launched, or is the button just not found?

GrahamDo commented 5 years ago

Thanks for your response.

It's a standard WpfButton. It is being found and clicked, but Chrome isn't being launched.

It's difficult to give you a code snippet that runs when that button is clicked, because in this particular case, there's quite a bit of abstraction going on (We use the Prism framework), but essentially it uses Selenium to launch Chrome and execute some steps. Then closes Chrome.

paulcam206 commented 5 years ago

Have you tried changing the button to do something like pop a message box? I'm curious whether the click is really happening or not...

PandaMagnus commented 5 years ago

I'm also curious as to whether the click is actually happening or not. As an additional question, is there an exception being throw after the click occurs and Chrome fails to launch?

GrahamDo commented 5 years ago

@paulcam206 @PandaMagnus I changed the code for the button click to 'MessageBox.Show("Hello World!");' and re-ran my test. It worked fine, and the message popped up.

GrahamDo commented 5 years ago

@PandaMagnus There are no exceptions being thrown by our app. Nor (as I've just noticed) is anything displayed in the WinAppDriver console output when clicking that button.

PandaMagnus commented 5 years ago

Hmmm... I wonder if WAP or Selenium is trying to click the wrong element while trying to click the "right" one. Is there an element in the XAML that's a parent for the button besides the window?

A possible way to test this is to see if you can tab to the button and then hit enter use WAP (using Actions class, not Sendkeys on the element). If that works, I'd highly suspect that the driver is the culprit (we see this very very rarely on websites that we automate with Selenium. I'm still not 100% sure what causes it, but I've found references to at least the InternetExplorer driver trying to "guess" what a user would really click on... so E.G., if a button has a parent div, the click will sometimes go to the div.)

GrahamDo commented 5 years ago

Thanks, @PandaMagnus. I will give that a try and revert later today. :-)

GrahamDo commented 5 years ago

I'm afraid that moving to the button and sending ENTER to it isn't working either. As before, the button gets focus and is depressed, but nothing happens. I tried it first with the following code:

` var action = new Actions(Session);

        action.MoveToElement(executeButton);

        action.SendKeys(Keys.Enter);

        action.Perform();`

And then manually in the session that my WAP project opened. :-(

In the XAML, the button is part of a StackPanel, which is part of a Border, which is part of a Grid, and the whole thing is inside another element because it's a Prism module.

So you might have a point about it "clicking" the wrong thing, but then why would it work just fine when I change that button to do nothing but display a simple MessageBox? :/

PandaMagnus commented 5 years ago

Ugh, I wouldn't think a StackPanel or Grid would get in the way, particularly if you've got other elements that are siblings to the button.

Okay, purely just for troubleshooting purposes, go back to the regular code you have where you just click on the button like normal, and see if Selenium knows what the active property is... After clicking, you'll have to invoke Selenium's JavaScriptExecutor with... I think it's document.activeElement and assign the result to a variable. Set a break point after that line and inspect the variable to see if it's the button.

GrahamDo commented 5 years ago

I'm afraid we've now reached the limits of my understanding. :-(

I don't think I'm able to do any debugging on the website after clicking the button from within our app. I can debug our app, sure, but we don't even have the code for the website.

It's a third-party web application which we've developed a consumer-driven test framework for. The test framework is a WPF application that users install on their local PCs, and it's THAT application that I'm trying to write our own test framework for using the WinAppDriver.

It's a bit of an "Inception" situation, but I hope it gives you some more clarity on what I'm trying to do.

To put it another way, all I'm trying to test with my WinAppDriver framework is whether I can click the "Execute Action" button from within our app, wait up to two minutes for a certain button to become available again. My test framework will have no interest or control over what actually HAPPENS during those two minutes - that's when Selenium is doing its thing in the web browser; testing that is beyond the scope of what I'm trying to do.

PandaMagnus commented 5 years ago

WinAppDriver uses Selenium (well, more accurately, it uses Appium, which uses Selenium,) to drive the interactions with the desktop app. WinAppDriver, as I understand it, just converts the desktop app into a form Appium/Selenium can understand. I'm hoping, although I haven't tried this yet, that if you use Appium/Selenium to execute JavaScript, it will get interpreted correctly before interacting with your WPF app. I don't actually know for sure, but it might be worth a shot.

GrahamDo commented 5 years ago

That kind of makes sense. But the problem is I'm not sure how to do it. How would I "convert" the WPF code that's running into JavaScript when that button is clicked, and then debug that JavaScript?

Let me ask you this: have YOU ever used WinAppDriver to test clicking a button which launches a web browser via Selenium?

I have a suspicion that that scenario is actually the whole problem. Something to do with only one "instance" of Selenium being allowed on a machine at one time, maybe?

PandaMagnus commented 5 years ago

Not specifically that scenario, but I have worked on projects where we spin up multiple Selenium instances in parallel to keep our test run time down (both the same browser and cross-browser tests.) So I do know you can spin up a second Selenium instance. The problem would be trying to get it to connect to the web page in question that launched (if the test was working).

WinAppDriver already converts the WPF code to XML. The part I don't know is when Selenium executes JavaScript, is it actually Selenium doing it, or the browser-specific driver. If the latter, then you're absolutely right, I wouldn't expect the suggestion to work. If the former, then it might work. Doing it would look something like (probably would need some tinkering):

IJavaScriptExecutor executor = (IJavaScriptExecutor)driver; executor.ExecuteScript("document.getElementById('elementID').click()");

If the source code is available, I'd be happy to pull it down and give it a shot this week. Otherwise, I'll see if I have the time to build a quick example app.

GrahamDo commented 5 years ago

Cool. Sorry it's taken me so long to reply. I've been pretty busy myself, and this issue isn't being given a particularly high priority by the Powers That Be over here. They'd rather I focus on testing the rest of our application. But I really want it to work. ;)

If you can spin up a quick example app, that'd be great. All it needs to do is run Selenium using the Chrome Driver (which is the only one we support) on click of a button, hit a website, and do something.

If you can't get it working using the Chrome driver, maybe it'll work with a different driver?

PandaMagnus commented 5 years ago

(Edit: Sorry for the formatting. It's not pretty)

Two things: 1) Thank you for the reminder. I didn't have time for a few days, and then totally forgot about this. :( I did, however, have time today. 2) Holy shit, it's totally possible to connect to an existing Chrome window using Selenium. SO, here's my setup...

WPF app with this as the (truncated) XAML: `