asticode / go-astilectron

Build cross platform GUI apps with GO and HTML/JS/CSS (powered by Electron)
MIT License
4.9k stars 344 forks source link

How to test astilectron UI - chromedp? #248

Open chinenual opened 4 years ago

chinenual commented 4 years ago

I'm considering writing some integration tests for my astilectron based app -- but I can't find a way to get a testing tool to attach to the electron instance. Even when I have DevTools open and enabled, I don't see anything listening on a port that appears to be something I could specify as a websocket URL for devtools.

Has anyone else successfully driven their astilectron application from a test harness?

I'm specifically looking at chromedp since it's go based, but would consider other alternatives if others are having success.

asticode commented 4 years ago

I have not tried to write integration tests for an astilectron based app but here are 2 issues that could point you to the right direction:

https://github.com/asticode/go-astilectron/issues/170 https://github.com/asticode/go-astilectron/issues/90

chinenual commented 4 years ago

90 looks relevant, but I am not able to connect the dots - not sure how the referenced pull request makes it possible to run Selenium tests.

Perhaps still related, chromedp wants to connect to ChromeDevTools via a websocket -- and I've seen some howto's for "javascript electron" on how to pass arguments to enable it (e.g. https://stackoverflow.com/questions/30294600/how-to-include-chrome-devtools-in-electron#30638448) . I don't understand go-astilectron's magic sauce enough to know where to look to try to add something like this for go-astilectron. Hints?

asticode commented 4 years ago

I think the idea of this PR is:

1) You set a custom Executer that does not execute astilectron 2) You remove the TCP timeout so that go-astilectron doesn't return an error if no astilectron connects after 30s 3) You execute astilectron manually using a bash script or something else in which you also run Selenium

I've never used Selenium so I may be wrong

chinenual commented 4 years ago

I'm trying a different tact. I've added options to enable the dev tools websocket via ElectronSwitches:

            ElectronSwitches: []string{
                "remote-debugging-port", "8315",
                "host-rules", "MAP * 127.0.0.1",

and for now I'm not worrying about launching the executable automatically from the test harness. I'm able to connect to the dev tools socket, but so far I've been unsuccessful getting chromedp to drive the application (it's getting 404 errors when trying to connect). Will keep at it and report back if I make any progress...

chinenual commented 4 years ago

Update .. Still no joy. I've made more progress such that I think I'm calling the remote debugging websocket properly (the same style URL works on "normal chrome" - but doesn't work on my astilectron application, even when I enable the debugging port (and verify that it works - can access the http://localhost:8315/json/version API URL and get back good response. Can even remotely debug using a remote browser via the URLs returned by the API. But when I try to connnect chromedp , I get an error (I believe chrome/electron is returning a "not supported" error code to chromedp. I've submitted an issue to that project as https://github.com/chromedp/chromedp/issues/628).

When I try to connect a nodejs based spectron test harness, it just hangs. So there's still something not quite right.

If anyone has any other ideas of things I should try, I'm all ears. I don't see any other electron command line switches that might be relevant...

chinenual commented 4 years ago

@asticode - while I don't fully understand how it will work, I am trying to use the Executer support to defer creating the electron process as described in #90

However, I'm using go-astilectron-bootstrap and can't figure out where to set the Executer function. I've set a long timeout via bootstrap's AstilectronOptions.AcceptTCPTimeout, but I can't pass the executer there -- I tried calling a.SetExectuter in the OnWait callback, but it seems to be too late in the lifecycle. Where can I get my hands on the astilectron instance soon enough to prevent it from calling the default executer?

    if err := bootstrap.Run(bootstrap.Options{
        AstilectronOptions: astilectron.Options{
...
            AcceptTCPTimeout: acceptTimeout,
        },
        OnWait: func(as *astilectron.Astilectron, ws []*astilectron.Window, _ *astilectron.Menu, _ *astilectron.Tray, _ *astilectron.Menu) error {
            a = as
            w = ws[0]

            if *uitest {
                a.SetExecuter(executer)
            }
asticode commented 4 years ago

If you use the Adapter attribute of bootstrap.Options, you should be able to manipulate your *astilectron.Astilectron and therefore use a.SetExecuter.

chinenual commented 4 years ago

Thanks @asticode ! That, of course, works. Now to try to get chromedp or selenium to talk to the electron process...

        var executer = astilectron.DefaultExecuter
    var acceptTimeout = astilectron.DefaultAcceptTCPTimeout
    var adapter bootstrap.AstilectronAdapter = nil

    if *uitest {
        executer = func(l astikit.SeverityLogger, a *astilectron.Astilectron, cmd *exec.Cmd) (err error) {
            l.Infof("======= NOT STARTING CMD %s\n", strings.Join(cmd.Args, " "))
            return
        }

        acceptTimeout = time.Minute * 3

        adapter = func(a *astilectron.Astilectron) {
            l.Printf("======= In UI Test adapter - supressing executor\n")
            a.SetExecuter(executer)
        }
    }
chinenual commented 4 years ago

While I've not had any luck getting the go-based chromedp to work, I have finally cracked the code of getting a nodejs based Spectron (selenium webdriver) test working.

@asticode would it be helpful for me to add this to the boostrap demo? I can work on a PR in the next few days...

asticode commented 4 years ago

If that's not too much trouble for you, I'm curious what the PR would look like. I can't promess it will be merged though

chinenual commented 4 years ago

OK - I've created a PR (https://github.com/asticode/go-astilectron-demo/pull/62). See the comments for a known problem with Linux and more generally a possible improvement with the provisioner.

carmel commented 2 years ago

Thanks @asticode ! That, of course, works. Now to try to get chromedp or selenium to talk to the electron process...

        var executer = astilectron.DefaultExecuter
  var acceptTimeout = astilectron.DefaultAcceptTCPTimeout
  var adapter bootstrap.AstilectronAdapter = nil

  if *uitest {
      executer = func(l astikit.SeverityLogger, a *astilectron.Astilectron, cmd *exec.Cmd) (err error) {
          l.Infof("======= NOT STARTING CMD %s\n", strings.Join(cmd.Args, " "))
          return
      }

      acceptTimeout = time.Minute * 3

      adapter = func(a *astilectron.Astilectron) {
          l.Printf("======= In UI Test adapter - supressing executor\n")
          a.SetExecuter(executer)
      }
  }

Hi, @chinenual Did you implement the test function you mentioned using chromedp?