electron-userland / spectron

DEPRECATED: 🔎 Test Electron apps using ChromeDriver
http://electronjs.org/spectron
MIT License
1.68k stars 229 forks source link

Can I run an unmodified WebDriverIO test with Spectron? #357

Open jnealb opened 5 years ago

jnealb commented 5 years ago

We have built an Electron application without any Spectron api calls or specific debugging port support. We have a JS WebDriverIO test for the previous web version of the app that we hope to run against our Electron build by simply modifying its wd.conf.js profile according to the instructions found here: https://electronjs.org/docs/tutorial/using-selenium-and-webdriver

Is this testing configuration supported with Spectron? The Electron app is launched and we receive the "RESPONSE InitSession ERROR unknown error: DevToolsActivePort file doesn't exist" error and the tests do not progress. We have not been able to overcome the error with any of the recommended arguments that can be passed to the Chrome session.

Do we need to incorporate Spectron into our app or can we just update the wdio config file?

Thanks for any help or insights,

Neal

PS We are current with our "npm installs" and versions of Chrome. Attached is our wdio config file for reference.

wdio.conf.txt

onekiloparsec commented 5 years ago

Using Spectron for a newly created app, we get the same error message:

      (unknown error: DevToolsActivePort file doesn't exist)
      (The process started from chrome location /root/mystique/node_modules/spectron/lib/launcher.js is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
      (Driver info: chromedriver=2.45 (7154f3777129c2f32d160297120b6e200ec29830),platform=Linux 4.18.0-25-generic x86_64)

      at new RuntimeError (node_modules/webdriverio/build/lib/utils/ErrorHandler.js:143:12)
      at Request._callback (node_modules/webdriverio/build/lib/utils/RequestHandler.js:318:39)
      at Request.self.callback (node_modules/request/request.js:185:22)
      at Request.<anonymous> (node_modules/request/request.js:1161:10)
      at IncomingMessage.<anonymous> (node_modules/request/request.js:1083:12)

It seems related to options passed to the ChromeDriver. We are unable to pass any option (no effect whatsoever). It seems that the following options help:

In orther words, with these options, I am able to launch manually the ChromeDriver without any problem. But Spectron don't do it, and I couldn't find a way to tell it to do so...

OrangeDog commented 5 years ago

I couldn't find a way to tell it to do so

Pass chromeDriverArgs in the Application constructor.

However that still doesn't work. Here is the driver log:

[1565172664.714][INFO]: Starting ChromeDriver 2.45 (7154f3777129c2f32d160297120b6e200ec29830)
[1565172664.714][INFO]: Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.
[1565172664.718][SEVERE]: bind() failed: Cannot assign requested address (99)
[1565172664.718][INFO]: listen on IPv6 failed with error ERR_ADDRESS_INVALID
[1565172664.779][INFO]: [2a2dd34ea88b2885d087e771830c37a8] COMMAND InitSession {
   "desiredCapabilities": {
      "browserName": "electron",
      "chromeOptions": {
         "args": [ "spectron-path=/opt/my-project/node_modules/electron/dist/electron", "spectron-arg0=/opt/my-project/js/main.js", "--no-sandbox", "--disable-dev-shm-usage", "--whitelisted-ips=" ],
         "binary": "/opt/my-project/node_modules/spectron/lib/launcher.js",
         "windowTypes": [ "app", "webview" ]
      },
      "handlesAlerts": true,
      "javascriptEnabled": true,
      "locationContextEnabled": true,
      "loggingPrefs": {
         "browser": "ALL",
         "driver": "ALL"
      },
      "requestOrigins": {
         "name": "webdriverio",
         "url": "http://webdriver.io",
         "version": "4.14.4"
      },
      "rotatable": true
   }
}
[1565172664.781][INFO]: Populating Preferences file: {
   "alternate_error_pages": {
      "enabled": false
   },
   "autofill": {
      "enabled": false
   },
   "browser": {
      "check_default_browser": false
   },
   "distribution": {
      "import_bookmarks": false,
      "import_history": false,
      "import_search_engine": false,
      "make_chrome_default_for_user": false,
      "skip_first_run_ui": true
   },
   "dns_prefetching": {
      "enabled": false
   },
   "profile": {
      "content_settings": {
         "pattern_pairs": {
            "https://*,*": {
               "media-stream": {
                  "audio": "Default",
                  "video": "Default"
               }
            }
         }
      },
      "default_content_setting_values": {
         "geolocation": 1
      },
      "default_content_settings": {
         "geolocation": 1,
         "mouselock": 1,
         "notifications": 1,
         "popups": 1,
         "ppapi-broker": 1
      },
      "password_manager_enabled": false
   },
   "safebrowsing": {
      "enabled": false
   },
   "search": {
      "suggest_enabled": false
   },
   "translate": {
      "enabled": false
   }
}
[1565172664.781][INFO]: Populating Local State file: {
   "background_mode": {
      "enabled": false
   },
   "ssl": {
      "rev_checking": {
         "enabled": false
      }
   }
}
[1565172344.637][INFO]: Launching chrome: /opt/my-project/node_modules/spectron/lib/launcher.js --disable-background-networking --disable-client-side-phishing-detection --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-popup-blocking --disable-prompt-on-repost --disable-sync --disable-web-resources --enable-automation --enable-blink-features=ShadowDOMV0 --enable-logging --force-fieldtrials=SiteIsolationExtensions/Control --ignore-certificate-errors --load-extension=/tmp/.org.chromium.Chromium.bUTBao/internal --log-level=0 --metrics-recording-only --no-first-run --no-sandbox --password-store=basic --remote-debugging-port=0 --spectron-arg0=/opt/my-project/js/main.js --spectron-path=/opt/my-project/node_modules/electron/dist/electron --test-type=webdriver --use-mock-keychain --user-data-dir=/tmp/.org.chromium.Chromium.H67so9 --whitelisted-ips data:,
_stream_readable.js:671
    dest.end();
         ^

TypeError: dest.end is not a function
    at Socket.onend (_stream_readable.js:671:10)
    at Object.onceWrapper (events.js:286:20)
    at Socket.emit (events.js:203:15)
    at endReadableNT (_stream_readable.js:1145:12)
    at process._tickCallback (internal/process/next_tick.js:63:19)
[1565172344.766][INFO]: [e0169295f6ff3bdfa500f3bdbb09e706] RESPONSE InitSession ERROR unknown error: Chrome failed to start: exited abnormally
  (unknown error: DevToolsActivePort file doesn't exist)
  (The process started from chrome location /opt/my-project/node_modules/spectron/lib/launcher.js is no longer running, so ChromeDriver is assuming that Chrome has crashed.)
[1565172344.770][DEBUG]: Log type 'driver' lost 4 entries on destruction
[1565172344.770][DEBUG]: Log type 'browser' lost 0 entries on destruction

That is spectron 7.0.0 running in this docker image

FROM node:10-slim

RUN apt-get update && apt-get install -qy \
    libasound2 \
    libgconf-2-4 \
    libgtk2.0-0 \
    libnss3 \
    libxss1 \
    libxtst6 \
    xvfb \
 && rm -rf /var/lib/apt/lists/*

with these commands

export DISPLAY=:9.0
Xvfb :9 -screen 0 1024x768x24 &
npm ci
npx mocha

As far as I can tell, the IPv6 failure shouldn't affect anything.

I haven't been able to get it to write a chrome_debug.log anywhere to be able to check it. I don't see any core dumps (with ulimit -c unlimited) either.

onekiloparsec commented 5 years ago

Pass chromeDriverArgs in the Application constructor.

This is what we were doing already, but I changed a few details (electron path). Not running inside a container, but a classical Ubuntu 16.04. The following code fails. As far as I can tell, app.start is never reached. I don't have a webdriver option failure anymore, just a timeout error.

test('Window Loads Properly', async () => {
  var app = new Application({
    path: path.join(__dirname, '../../node_modules/electron/dist/electron'),
    chromeDriverArgs: [
      '--no-sandbox',
      '--whitelisted-ips=',
      '--disable-dev-shm-usage'
    ],
    args: [path.join(__dirname, '../../src/main.js')]
  })

  await app.start()
//  await app.client.waitUntilWindowLoaded()

  const win = app.browserWindow
  const client = app.client

  expect(await client.getWindowCount()).toBe(1)

  app.stop()
})
fspinillo commented 4 years ago

Try setting the remote debugging port in your capabilities file:

'--remote-debugging-port=9515'

Powersource commented 4 years ago

I think maybe I have the same issue, or I'm getting the same errors at least for some reason, no luck on fixing stuff. I don't think I'm doing anything too weird

The spectron readme says that stuff won't work if you use --remote-debugging-port (changed the error for me but still didn't work) and refers to this issue https://github.com/electron-userland/spectron/issues/19

This is my latest (still not working) code (I've also tried some of the suggestions in this issue).

toams69 commented 4 years ago

I have the same issue here. Does anyone find a way to fix this ?

MatthijsBurgh commented 4 years ago

I have the same issue with Spectron version 4-10 (with the matching electron version) on ubuntu 18.04 running with xvfb. And with xvfb on a xenial, 16.04, image in travis

MatthijsBurgh commented 4 years ago

Update I experienced the issue for only two days. Late yesterday, after a npm install my problem was solved. I was in development, so I hadn't committed my changes in my package-lock.json yet. So I can't say what solved the problem for me. Right now my application works with an empty chromeDriverArgs and with the following xvfb commands:

export DISPLAY=':99.0'
Xvfb :99 -screen 0 1024x600x24 > /dev/null 2>&1 &

If you want to determine if your problems are related to your system or your app. Try my app, hero-display, https://github.com/tue-robotics/hero-display.

daisyjanepueblos commented 4 years ago

I am also experiencing this issue. An I am also new with automation. can you please suggest on what steps to do?

Application launch "before each" hook for "Shows an initial window": Error: Failed to create session. unknown error: Chrome failed to start: was killed. (unknown error: DevToolsActivePort file doesn't exist)

I am using Node.js 12.14.1, Chromium 83.0.4103.122, and Electron 9.1.2.

dlqqq commented 4 years ago

Same issue. Running on CircleCI's circleci/node:latest-browser Docker image, ships w/ Node v14.6.0 and Chromium 83.0. Absolutely no idea how to resolve this. I've passed all the above flags to Chromium, exported $DISPLAY, started a Xvfb session, even ran a JS webcrawler to find every SE/SO question on this damn error. Of course, nothing works at all and I have probably just lost 2 months off of my lifespan. I'd rather pass kidney stones than to do any more of this

zhex900 commented 3 years ago

Same issue. Did anyone get a solution?

MatthijsBurgh commented 3 years ago

@zhex900 did you check my earlier comment? https://github.com/electron-userland/spectron/issues/357#issuecomment-645843885

nvdai2401 commented 3 years ago

Hi everyone, I can run Spectron tests with Github actions now after working around every solution in this issue. Hope this helps!

name: CI

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - name: Setup Node.js 14.x
        uses: actions/setup-node@v2.1.5
        with:
          node-version: 14.x

      - name: Install yarn
        run: npm install -g yarn

      - name: Install dependencies
        run: yarn install

      - name: Install xvfb
        run: sudo apt-get install xvfb

      - name: Run tests with xvfb
        run: xvfb-run --auto-servernum yarn test
{
  "main": "./dist/index.js",
  "scripts": {
    "compile": "tsc",
    "pretest": "yarn compile",
    "test": "jest --detectOpenHandles --forceExit",
  },
  ...
  "devDependencies": {
    ...
    "electron": "12.0.5",
    ...
    "jest": "^27.0.6",
    ...
    "spectron": "14.0.0",
    ...
    "typescript": "^4.0.2"
  },
  ...
}

Set up tests with Spectron:

import { Application } from 'spectron'
import electronPath from 'electron'
import path from 'path'

jest.setTimeout(60000)

let app: Application

beforeAll(() => {
  app = new Application({
    path: electronPath,
    args: ['--no-sandbox', path.join(__dirname, '../')],
    env: {
      NODE_ENV: 'test',
      SPECTRON: true,
      ELECTRON_ENABLE_LOGGING: true,
      ELECTRON_ENABLE_STACK_DUMPING: true,
    },
    port: 9515,
    chromeDriverLogPath: 'chromedriverlog.txt',
    chromeDriverArgs: [`remote-debugging-port=9222`],
  })
})

afterAll(() => {
  if (app && app.isRunning()) {
    return app.stop()
  }
})

test('Login', async () => {...})