electron-userland / spectron

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

Working docker image to run electron test headless #1021

Closed zhex900 closed 2 years ago

zhex900 commented 2 years ago

Hi,

Is there a working example of how to to run electron tests in a docker container headlessly?

What I have here does not work.

I can run my tests headlessly in the Ubuntu terminal.

##Dockerfile
FROM node:lts-stretch

RUN apt-get update && apt-get install \
    g++-multilib \
    lib32z1 \
    lib32ncurses5 \
    rpm \
    fakeroot \
    dpkg \
    libdbus-1-dev \
    libx11-dev \
    libavahi-compat-libdnssd-dev \
    g++ \
     # Install display server dependencies
    libgtk2.0-0 \
    libgtk2.0-dev \
    xvfb \
    libxtst6 \
    libgbm-dev \
     # Install core libraries for chromium driver
    libxss1 \
    libnss3 \
    libasound2 \
    libgconf-2-4 \
    git libx11-xcb1 libxcb-dri3-0 libxtst6 libnss3 libatk-bridge2.0-0 libgtk-3-0 libxss1 libasound2 \
    -yq --no-install-suggests --no-install-recommends 

COPY /entrypoint.sh /entrypoint.sh
RUN chmod 777 /entrypoint.sh

RUN export ELECTRON_ENABLE_STACK_DUMPING=true
RUN export ELECTRON_ENABLE_LOGGING=true

WORKDIR /app
USER node

ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]
#entrypoint
#!/bin/bash

echo "Starting Xvfb"
Xvfb :99 -screen 0 1440x2560x24 > /dev/null 2>&1 &
sleep 3

export DISPLAY=:99
echo "Executing command $@"

exec "$@"

This is the error.

    Failed to create session.
    unknown error: Chrome failed to start: exited abnormally.
      (unknown error: DevToolsActivePort file doesn't exist)
      (The process started from chrome location /app/packages/kiosk-app/node_modules/spectron/lib/launcher.js is no longer running, so ChromeDriver is assuming that Chrome has crashed.)

      at Object.startWebDriverSession (node_modules/webdriver/build/utils.js:34:15)
      at Function.newSession (node_modules/webdriver/build/index.js:35:45)
      at Object.<anonymous>.exports.remote (node_modules/webdriverio/build/index.js:53:22)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        25.147 s
Ran all test suites.
Jest did not exit one second after the test run has completed.

This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with `--detectOpenHandles` to troubleshoot this issue.
zhex900 commented 2 years ago

I have made a little progress but I still cannot run the tests in the docker container.

The above error meant my electron app did not even run . I fixed it by doing these

chown root /out/App/chrome-sandbox
chmod 4755 /out/App/chrome-sandbox

Now I get a different error

    waitUntilWindowLoaded waitUntil condition failed with the following reason: invalid session id

      at node_modules/webdriverio/build/commands/browser/waitUntil.js:26:15
      at Browser.wrapCommandFn (node_modules/@wdio/utils/build/shim.js:63:29)
      at Browser.waitUntilWindowLoaded (node_modules/@wdio/utils/build/shim.js:63:29)

  ● Test suite failed to run

    invalid session id: invalid session id

      at Object.getErrorFromResponseBody (node_modules/webdriver/build/utils.js:94:12)
      at WebDriverRequest._request (node_modules/webdriver/build/request.js:134:31)
      at Browser.wrapCommandFn (node_modules/@wdio/utils/build/shim.js:63:29)
      at Browser.wrapCommandFn (node_modules/@wdio/utils/build/shim.js:63:29)
      at Browser.electron.remote.app.quit (node_modules/@wdio/utils/build/shim.js:63:29)

My electron app did run this time. I can see the logs. I guess webdriver cannot connect to it. Any suggestions?

zhex900 commented 2 years ago

Here are more logs

    console.warn
      2021-08-11T04:38:32.577Z WARN webdriver: Request failed with status 500 due to unknown error: session deleted because of page crash
      from unknown error: cannot determine loading status
      from tab crashed
        (Session info: chrome=91.0.4472.106)
ode@f09b253b1d56:/app$ cat /tmp/chromeDriverLogPath.log 
[1628656710.716][INFO]: Starting ChromeDriver 91.0.4472.69 (2a355ebfd51bdd7f4a2a3a979d4cd4c5dd320cda-refs/heads/master@{#878767}) on port 9515
[1628656710.716][INFO]: Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
[1628656710.717][SEVERE]: bind() failed: Cannot assign requested address (99)
[1628656710.717][INFO]: listen on IPv6 failed with error ERR_ADDRESS_INVALID
[1628656711.790][INFO]: [bedf087722f7e6b37111b526de7fde0f] COMMAND InitSession {
   "capabilities": {
      "alwaysMatch": {
         "goog:chromeOptions": {
            "args": [ "spectron-path=/app/packages/kiosk-app/node_modules/electron/dist/electron", "spectron-arg0=/app/packages/kiosk-app", "spectron-arg1=--no-sandbox" ],
            "binary": "/app/packages/kiosk-app/node_modules/spectron/lib/launcher.js",
            "windowTypes": [ "app", "webview" ]
         }
      },
      "firstMatch": [ {

      } ]
   },
   "desiredCapabilities": {
      "goog:chromeOptions": {
         "args": [ "spectron-path=/app/packages/kiosk-app/node_modules/electron/dist/electron", "spectron-arg0=/app/packages/kiosk-app", "spectron-arg1=--no-sandbox" ],
         "binary": "/app/packages/kiosk-app/node_modules/spectron/lib/launcher.js",
         "windowTypes": [ "app", "webview" ]
      }
   }
}
[1628656711.791][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
   }
}
[1628656711.791][INFO]: Populating Local State file: {
   "background_mode": {
      "enabled": false
   },
   "ssl": {
      "rev_checking": {
         "enabled": false
      }
   }
}
[1628656711.791][INFO]: Launching chrome: /app/packages/kiosk-app/node_modules/spectron/lib/launcher.js --allow-pre-commit-input --disable-background-networking --disable-client-side-phishing-detection --disable-default-apps --disable-hang-monitor --disable-popup-blocking --disable-prompt-on-repost --disable-sync --enable-automation --enable-blink-features=ShadowDOMV0 --enable-logging --log-level=0 --no-first-run --no-service-autorun --password-store=basic --remote-debugging-port=0 --spectron-arg0=/app/packages/kiosk-app --spectron-arg1=--no-sandbox --spectron-path=/app/packages/kiosk-app/node_modules/electron/dist/electron --test-type=webdriver --use-mock-keychain --user-data-dir=/tmp/.org.chromium.Chromium.pvWay1 data:,
[1628656712.143][DEBUG]: DevTools HTTP Request: http://localhost:42703/json/version
[1628656712.154][DEBUG]: DevTools HTTP Response: {
   "Browser": "Chrome/91.0.4472.106",
   "Protocol-Version": "1.3",
   "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) PAM-Kiosk/1.0.0 Chrome/91.0.4472.106 Electron/13.1.4 Safari/537.36",
   "V8-Version": "9.1.269.36",
   "WebKit-Version": "537.36 (@9a6958a11033ef3c45446ec5e6366810e848c1b7)",
   "webSocketDebuggerUrl": "ws://localhost:42703/devtools/browser/d63e90d8-47a6-40cf-a37f-813417d73ec1"
}

[1628656712.154][DEBUG]: DevTools HTTP Request: http://localhost:42703/json/list
[1628656712.156][DEBUG]: DevTools HTTP Response: [ {
   "description": "",
   "devtoolsFrontendUrl": "/devtools/inspector.html?ws=localhost:42703/devtools/page/0B5987E10A2107BFEE81CC2223E21993",
   "id": "0B5987E10A2107BFEE81CC2223E21993",
   "title": "",
   "type": "page",
   "url": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.html",
   "webSocketDebuggerUrl": "ws://localhost:42703/devtools/page/0B5987E10A2107BFEE81CC2223E21993"
} ]

[1628656712.156][DEBUG]: DevTools HTTP Request: http://localhost:42703/json/list
[1628656712.157][DEBUG]: DevTools HTTP Response: [ {
   "description": "",
   "devtoolsFrontendUrl": "/devtools/inspector.html?ws=localhost:42703/devtools/page/0B5987E10A2107BFEE81CC2223E21993",
   "id": "0B5987E10A2107BFEE81CC2223E21993",
   "title": "",
   "type": "page",
   "url": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.html",
   "webSocketDebuggerUrl": "ws://localhost:42703/devtools/page/0B5987E10A2107BFEE81CC2223E21993"
} ]

[1628656712.157][INFO]: resolved localhost to ["127.0.0.1","::1"]
[1628656712.158][DEBUG]: DevTools WebSocket Command: Page.addScriptToEvaluateOnNewDocument (id=1) 0B5987E10A2107BFEE81CC2223E21993 {
   "source": "(function () {window.cdc_adoQpoasnfa76pfcZLmcfl_Array = window.Array;window.cdc_adoQpoasnfa76pfcZLmcfl_Promise = window.Promise;window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol = window.Symbol;}) ();"
}
[1628656712.158][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=2) 0B5987E10A2107BFEE81CC2223E21993 {
   "expression": "(function () {window.cdc_adoQpoasnfa76pfcZLmcfl_Array = window.Array;window.cdc_adoQpoasnfa76pfcZLmcfl_Promise = window.Promise;window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol = window.Symbol;}) ();"
}
[1628656712.158][DEBUG]: DevTools WebSocket Command: Log.enable (id=3) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.158][DEBUG]: DevTools WebSocket Command: DOM.getDocument (id=4) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.158][DEBUG]: DevTools WebSocket Command: Target.setAutoAttach (id=5) 0B5987E10A2107BFEE81CC2223E21993 {
   "autoAttach": true,
   "flatten": true,
   "waitForDebuggerOnStart": false
}
[1628656712.158][DEBUG]: DevTools WebSocket Command: Page.enable (id=6) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.158][DEBUG]: DevTools WebSocket Command: Page.enable (id=7) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.198][DEBUG]: DevTools WebSocket Response: Page.addScriptToEvaluateOnNewDocument (id=1) 0B5987E10A2107BFEE81CC2223E21993 {
   "identifier": "1"
}
[1628656712.229][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=2) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "type": "undefined"
   }
}
[1628656712.229][DEBUG]: DevTools WebSocket Response: Log.enable (id=3) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.229][DEBUG]: DevTools WebSocket Response: DOM.getDocument (id=4) 0B5987E10A2107BFEE81CC2223E21993 {
   "root": {
      "backendNodeId": 1,
      "baseURL": "about:blank",
      "childNodeCount": 1,
      "children": [ {
         "attributes": [  ],
         "backendNodeId": 2,
         "childNodeCount": 2,
         "children": [ {
            "attributes": [  ],
            "backendNodeId": 3,
            "childNodeCount": 0,
            "localName": "head",
            "nodeId": 3,
            "nodeName": "HEAD",
            "nodeType": 1,
            "nodeValue": "",
            "parentId": 2
         }, {
            "attributes": [  ],
            "backendNodeId": 4,
            "childNodeCount": 0,
            "localName": "body",
            "nodeId": 4,
            "nodeName": "BODY",
            "nodeType": 1,
            "nodeValue": "",
            "parentId": 2
         } ],
         "frameId": "0B5987E10A2107BFEE81CC2223E21993",
         "localName": "html",
         "nodeId": 2,
         "nodeName": "HTML",
         "nodeType": 1,
         "nodeValue": "",
         "parentId": 1
      } ],
      "documentURL": "",
      "localName": "",
      "nodeId": 1,
      "nodeName": "#document",
      "nodeType": 9,
      "nodeValue": "",
      "xmlVersion": ""
   }
}
[1628656712.229][DEBUG]: DevTools WebSocket Response: Target.setAutoAttach (id=5) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.229][DEBUG]: DevTools WebSocket Response: Page.enable (id=6) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.229][DEBUG]: DevTools WebSocket Response: Page.enable (id=7) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.229][DEBUG]: DevTools WebSocket Command: Runtime.enable (id=8) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.229][DEBUG]: DevTools WebSocket Event: Page.frameStartedLoading 0B5987E10A2107BFEE81CC2223E21993 {
   "frameId": "0B5987E10A2107BFEE81CC2223E21993"
}
[1628656712.252][DEBUG]: DevTools WebSocket Event: Page.frameNavigated 0B5987E10A2107BFEE81CC2223E21993 {
   "frame": {
      "adFrameType": "none",
      "crossOriginIsolatedContextType": "NotIsolated",
      "domainAndRegistry": "",
      "gatedAPIFeatures": [ "SharedArrayBuffersTransferAllowed" ],
      "id": "0B5987E10A2107BFEE81CC2223E21993",
      "loaderId": "47D4E29AFE4D569F8CD521C313CBE200",
      "mimeType": "text/html",
      "secureContextType": "Secure",
      "securityOrigin": "file://",
      "url": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.html"
   }
}
[1628656712.252][DEBUG]: DevTools WebSocket Event: DOM.documentUpdated 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.252][DEBUG]: DevTools WebSocket Command: DOM.getDocument (id=9) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.252][DEBUG]: DevTools WebSocket Event: Runtime.executionContextCreated 0B5987E10A2107BFEE81CC2223E21993 {
   "context": {
      "auxData": {
         "frameId": "0B5987E10A2107BFEE81CC2223E21993",
         "isDefault": true,
         "type": "default"
      },
      "id": 2,
      "name": "",
      "origin": "file://",
      "uniqueId": "-1901612941796004346.7940496625299686345"
   }
}
[1628656712.252][DEBUG]: DevTools WebSocket Response: Runtime.enable (id=8) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.252][DEBUG]: DevTools WebSocket Command: Page.enable (id=10) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.258][DEBUG]: DevTools WebSocket Response: DOM.getDocument (id=9) 0B5987E10A2107BFEE81CC2223E21993 {
   "root": {
      "backendNodeId": 5,
      "baseURL": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.html",
      "childNodeCount": 2,
      "children": [ {
         "backendNodeId": 6,
         "localName": "",
         "nodeId": 6,
         "nodeName": "html",
         "nodeType": 10,
         "nodeValue": "",
         "parentId": 5,
         "publicId": "",
         "systemId": ""
      }, {
         "attributes": [ "lang", "uk" ],
         "backendNodeId": 7,
         "childNodeCount": 2,
         "children": [ {
            "attributes": [  ],
            "backendNodeId": 8,
            "childNodeCount": 5,
            "localName": "head",
            "nodeId": 8,
            "nodeName": "HEAD",
            "nodeType": 1,
            "nodeValue": "",
            "parentId": 7
         }, {
            "attributes": [  ],
            "backendNodeId": 9,
            "childNodeCount": 1,
            "localName": "body",
            "nodeId": 9,
            "nodeName": "BODY",
            "nodeType": 1,
            "nodeValue": "",
            "parentId": 7
         } ],
         "frameId": "0B5987E10A2107BFEE81CC2223E21993",
         "localName": "html",
         "nodeId": 7,
         "nodeName": "HTML",
         "nodeType": 1,
         "nodeValue": "",
         "parentId": 5
      } ],
      "documentURL": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.html",
      "localName": "",
      "nodeId": 5,
      "nodeName": "#document",
      "nodeType": 9,
      "nodeValue": "",
      "xmlVersion": ""
   }
}
[1628656712.258][DEBUG]: DevTools WebSocket Response: Page.enable (id=10) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.258][DEBUG]: DevTools WebSocket Command: Runtime.enable (id=11) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.289][DEBUG]: DevTools WebSocket Event: DOM.childNodeCountUpdated 0B5987E10A2107BFEE81CC2223E21993 {
   "childNodeCount": 6,
   "nodeId": 8
}
[1628656712.290][DEBUG]: DevTools WebSocket Event: DOM.documentUpdated 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.290][DEBUG]: DevTools WebSocket Command: DOM.getDocument (id=12) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.290][DEBUG]: DevTools WebSocket Event: Page.domContentEventFired 0B5987E10A2107BFEE81CC2223E21993 {
   "timestamp": 801.216088
}
[1628656712.290][DEBUG]: DevTools WebSocket Response: Runtime.enable (id=11) 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.290][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=13) 0B5987E10A2107BFEE81CC2223E21993 {
   "awaitPromise": true,
   "expression": "(function() { // Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * Enum f...",
   "returnByValue": true
}
[1628656712.293][DEBUG]: DevTools WebSocket Response: DOM.getDocument (id=12) 0B5987E10A2107BFEE81CC2223E21993 {
   "root": {
      "backendNodeId": 5,
      "baseURL": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.html",
      "childNodeCount": 2,
      "children": [ {
         "backendNodeId": 6,
         "localName": "",
         "nodeId": 11,
         "nodeName": "html",
         "nodeType": 10,
         "nodeValue": "",
         "parentId": 10,
         "publicId": "",
         "systemId": ""
      }, {
         "attributes": [ "lang", "uk" ],
         "backendNodeId": 7,
         "childNodeCount": 2,
         "children": [ {
            "attributes": [  ],
            "backendNodeId": 8,
            "childNodeCount": 6,
            "localName": "head",
            "nodeId": 13,
            "nodeName": "HEAD",
            "nodeType": 1,
            "nodeValue": "",
            "parentId": 12
         }, {
            "attributes": [  ],
            "backendNodeId": 9,
            "childNodeCount": 1,
            "localName": "body",
            "nodeId": 14,
            "nodeName": "BODY",
            "nodeType": 1,
            "nodeValue": "",
            "parentId": 12
         } ],
         "frameId": "0B5987E10A2107BFEE81CC2223E21993",
         "localName": "html",
         "nodeId": 12,
         "nodeName": "HTML",
         "nodeType": 1,
         "nodeValue": "",
         "parentId": 10
      } ],
      "documentURL": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.html",
      "localName": "",
      "nodeId": 10,
      "nodeName": "#document",
      "nodeType": 9,
      "nodeValue": "",
      "xmlVersion": ""
   }
}
[1628656712.293][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=13) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "type": "object",
      "value": {
         "status": 0,
         "value": 1
      }
   }
}
[1628656712.293][INFO]: [bedf087722f7e6b37111b526de7fde0f] RESPONSE InitSession {
   "capabilities": {
      "acceptInsecureCerts": false,
      "browserName": "chrome",
      "browserVersion": "91.0.4472.106",
      "chrome": {
         "chromedriverVersion": "91.0.4472.69 (2a355ebfd51bdd7f4a2a3a979d4cd4c5dd320cda-refs/heads/master@{#878767})",
         "userDataDir": "/tmp/.org.chromium.Chromium.pvWay1"
      },
      "goog:chromeOptions": {
         "debuggerAddress": "localhost:42703"
      },
      "networkConnectionEnabled": false,
      "pageLoadStrategy": "normal",
      "platformName": "linux",
      "proxy": {

      },
      "setWindowRect": true,
      "strictFileInteractability": false,
      "timeouts": {
         "implicit": 0,
         "pageLoad": 300000,
         "script": 30000
      },
      "unhandledPromptBehavior": "dismiss and notify",
      "webauthn:extension:largeBlob": true,
      "webauthn:virtualAuthenticators": true
   },
   "sessionId": "bedf087722f7e6b37111b526de7fde0f"
}
[1628656712.303][INFO]: [bedf087722f7e6b37111b526de7fde0f] COMMAND ExecuteScript {
   "args": [ "require" ],
   "script": "return (function (requireName) {\n    return typeof window[requireName] === 'function';\n  }).apply(null, arguments)"
}
[1628656712.303][INFO]: Waiting for pending navigations...
[1628656712.303][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=14) 0B5987E10A2107BFEE81CC2223E21993 {
   "expression": "1"
}
[1628656712.304][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=14) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "description": "1",
      "type": "number",
      "value": 1
   }
}
[1628656712.310][DEBUG]: DevTools WebSocket Event: Page.loadEventFired 0B5987E10A2107BFEE81CC2223E21993 {
   "timestamp": 801.231475
}
[1628656712.310][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=15) 0B5987E10A2107BFEE81CC2223E21993 {
   "awaitPromise": false,
   "expression": "document.readyState",
   "returnByValue": true
}
[1628656712.310][DEBUG]: DevTools WebSocket Event: Page.frameStoppedLoading 0B5987E10A2107BFEE81CC2223E21993 {
   "frameId": "0B5987E10A2107BFEE81CC2223E21993"
}
[1628656712.311][DEBUG]: DevTools WebSocket Event: Runtime.consoleAPICalled 0B5987E10A2107BFEE81CC2223E21993 {
   "args": [ {
      "type": "string",
      "value": "%cElectron Security Warning (Insecure Content-Security-Policy)"
   }, {
      "type": "string",
      "value": "font-weight: bold;"
   }, {
      "type": "string",
      "value": "This renderer process has either no Content Security\n    Policy set or a policy with \"unsafe-eval\" enabled. This exposes users of\n    this app to unnecessary security risks.\n\nFor more information a..."
   } ],
   "executionContextId": 2,
   "stackTrace": {
      "callFrames": [ {
         "columnNumber": 3370,
         "functionName": "",
         "lineNumber": 112,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      } ]
   },
   "timestamp": 1.628656712310113e+12,
   "type": "warning"
}
[1628656712.311][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=15) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "type": "string",
      "value": "complete"
   }
}
[1628656712.311][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=16) 0B5987E10A2107BFEE81CC2223E21993 {
   "expression": "1"
}
[1628656712.320][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=16) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "description": "1",
      "type": "number",
      "value": 1
   }
}
[1628656712.320][INFO]: Done waiting for pending navigations. Status: ok
[1628656712.320][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=17) 0B5987E10A2107BFEE81CC2223E21993 {
   "awaitPromise": true,
   "expression": "(function() { // Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * Enum f...",
   "returnByValue": true
}
[1628656712.321][DEBUG]: DevTools WebSocket Event: Runtime.consoleAPICalled 0B5987E10A2107BFEE81CC2223E21993 {
   "args": [ {
      "className": "Object",
      "description": "Object",
      "objectId": "-3582440360695042919.2.1",
      "preview": {
         "description": "Object",
         "overflow": false,
         "properties": [ {
            "name": "payload",
            "type": "string",
            "value": "test_ad432f2cb0c28bbcd1f87a20199237f9"
         } ],
         "type": "object"
      },
      "type": "object"
   } ],
   "executionContextId": 2,
   "stackTrace": {
      "callFrames": [ {
         "columnNumber": 319423,
         "functionName": "",
         "lineNumber": 1,
         "scriptId": "151",
         "url": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.js"
      }, {
         "columnNumber": 19,
         "functionName": "emit",
         "lineNumber": 314,
         "scriptId": "89",
         "url": "events.js"
      }, {
         "columnNumber": 1116,
         "functionName": "onMessage",
         "lineNumber": 92,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      } ]
   },
   "timestamp": 1.6286567123155972e+12,
   "type": "log"
}
[1628656712.321][DEBUG]: DevTools WebSocket Event: Runtime.consoleAPICalled 0B5987E10A2107BFEE81CC2223E21993 {
   "args": [ {
      "className": "Object",
      "description": "Object",
      "objectId": "-3582440360695042919.2.2",
      "preview": {
         "description": "Object",
         "overflow": false,
         "properties": [ {
            "name": "status",
            "type": "object",
            "value": "Object"
         } ],
         "type": "object"
      },
      "type": "object"
   } ],
   "executionContextId": 2,
   "stackTrace": {
      "callFrames": [ {
         "columnNumber": 319305,
         "functionName": "",
         "lineNumber": 1,
         "scriptId": "151",
         "url": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.js"
      }, {
         "columnNumber": 19,
         "functionName": "emit",
         "lineNumber": 314,
         "scriptId": "89",
         "url": "events.js"
      }, {
         "columnNumber": 1116,
         "functionName": "onMessage",
         "lineNumber": 92,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      } ]
   },
   "timestamp": 1.628656712317759e+12,
   "type": "log"
}
[1628656712.325][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=17) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "type": "object",
      "value": {
         "status": 0,
         "value": true
      }
   }
}
[1628656712.325][INFO]: Waiting for pending navigations...
[1628656712.325][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=18) 0B5987E10A2107BFEE81CC2223E21993 {
   "expression": "1"
}
[1628656712.327][DEBUG]: DevTools WebSocket Event: Runtime.consoleAPICalled 0B5987E10A2107BFEE81CC2223E21993 {
   "args": [ {
      "className": "Object",
      "description": "Object",
      "objectId": "-3582440360695042919.2.3",
      "preview": {
         "description": "Object",
         "overflow": false,
         "properties": [ {
            "name": "progressLog",
            "type": "object",
            "value": "Object"
         }, {
            "name": "message",
            "type": "string",
            "value": "Provision IoT device [PROGRESSING]"
         } ],
         "type": "object"
      },
      "type": "object"
   } ],
   "executionContextId": 2,
   "stackTrace": {
      "callFrames": [ {
         "columnNumber": 318886,
         "functionName": "",
         "lineNumber": 1,
         "scriptId": "151",
         "url": "file:///app/packages/kiosk-app/.webpack/renderer/main_window/index.js"
      }, {
         "columnNumber": 19,
         "functionName": "emit",
         "lineNumber": 314,
         "scriptId": "89",
         "url": "events.js"
      }, {
         "columnNumber": 1116,
         "functionName": "onMessage",
         "lineNumber": 92,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      } ]
   },
   "timestamp": 1.628656712324685e+12,
   "type": "log"
}
[1628656712.328][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=18) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "description": "1",
      "type": "number",
      "value": 1
   }
}
[1628656712.328][INFO]: Done waiting for pending navigations. Status: ok
[1628656712.328][INFO]: [bedf087722f7e6b37111b526de7fde0f] RESPONSE ExecuteScript true
[1628656712.331][INFO]: [bedf087722f7e6b37111b526de7fde0f] COMMAND ExecuteScript {
   "args": [ "require" ],
   "script": "return (function (requireName) {\n    const process = window[requireName]('process');\n    if (process != null && process.versions != null) {\n      return process.versions.electron;\n    }\n  }).apply(null, arguments)"
}
[1628656712.331][INFO]: Waiting for pending navigations...
[1628656712.331][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=19) 0B5987E10A2107BFEE81CC2223E21993 {
   "expression": "1"
}
[1628656712.335][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=19) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "description": "1",
      "type": "number",
      "value": 1
   }
}
[1628656712.335][INFO]: Done waiting for pending navigations. Status: ok
[1628656712.335][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=20) 0B5987E10A2107BFEE81CC2223E21993 {
   "awaitPromise": true,
   "expression": "(function() { // Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * Enum f...",
   "returnByValue": true
}
[1628656712.341][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=20) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "type": "object",
      "value": {
         "status": 0,
         "value": "13.1.4"
      }
   }
}
[1628656712.341][INFO]: Waiting for pending navigations...
[1628656712.341][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=21) 0B5987E10A2107BFEE81CC2223E21993 {
   "expression": "1"
}
[1628656712.348][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=21) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "description": "1",
      "type": "number",
      "value": 1
   }
}
[1628656712.348][INFO]: Done waiting for pending navigations. Status: ok
[1628656712.348][INFO]: [bedf087722f7e6b37111b526de7fde0f] RESPONSE ExecuteScript "13.1.4"
[1628656712.353][INFO]: [bedf087722f7e6b37111b526de7fde0f] COMMAND ExecuteScript {
   "args": [ "require" ],
   "script": "return (function (requireName) {\n    if (typeof window[requireName] !== 'function') {\n      throw new Error(\n        'Could not find global require method with name: ' + requireName\n      );\n    }\n    const electron = window[requireName]('electron');\n    const process = window[requireName]('process');\n\n    const api = {\n      browserWindow: {},\n      electron: {},\n      rendererProcess: {},\n      webContents: {}\n    };\n\n    function ignoreModule(moduleName) {\n      switch (moduleName) {\n        case 'CallbacksRegistry':\n        case 'deprecate':\n        case 'deprecations':\n        case 'hideInternalModules':\n        case 'Tray':\n          return true;\n        case 'inAppPurchase':\n          return process.platform !== 'darwin';\n      }\n      return false;\n    }\n\n    function isRemoteFunction(name) {\n      switch (name) {\n        case 'BrowserWindow':\n        case 'Menu':\n        case 'MenuItem':\n          return false;\n      }\n      return typeof electron.remote[name] === 'function';\n    }\n\n    function ignoreApi(apiName) {\n      switch (apiName) {\n        case 'prototype':\n          return true;\n        default:\n          return apiName[0] === '_';\n      }\n    }\n\n    function addModule(parent, parentName, name, api) {\n      api[name] = {};\n      for (const key in parent[name]) {\n        if (ignoreApi(key)) continue;\n        api[name][key] = parentName + '.' + name + '.' + key;\n      }\n    }\n\n    function addRenderProcessModules() {\n      Object.getOwnPropertyNames(electron).forEach(function (key) {\n        if (ignoreModule(key)) return;\n        if (key === 'remote') return;\n        addModule(electron, 'electron', key, api.electron);\n      });\n    }\n\n    function addMainProcessModules() {\n      api.electron.remote = {};\n      Object.getOwnPropertyNames(electron.remote).forEach(function (key) {\n        if (ignoreModule(key)) return;\n        if (isRemoteFunction(key)) {\n          api.electron.remote[key] = 'electron.remote.' + key;\n        } else {\n          addModule(\n            electron.remote,\n            'electron.remote',\n            key,\n            api.electron.remote\n          );\n        }\n      });\n      addModule(\n        electron.remote,\n        'electron.remote',\n        'process',\n        api.electron.remote\n      );\n    }\n\n    function addBrowserWindow() {\n      const currentWindow = electron.remote.getCurrentWindow();\n      for (const name in currentWindow) {\n        if (ignoreApi(name)) continue;\n        const value = currentWindow[name];\n        if (typeof value === 'function') {\n          api.browserWindow[name] = 'browserWindow.' + name;\n        }\n      }\n    }\n\n    function addWebContents() {\n      const webContents = electron.remote.getCurrentWebContents();\n      for (const name in webContents) {\n        if (ignoreApi(name)) continue;\n        const value = webContents[name];\n        if (typeof value === 'function') {\n          api.webContents[name] = 'webContents.' + name;\n        }\n      }\n    }\n\n    function addProcess() {\n      if (typeof process !== 'object') return;\n\n      for (const name in process) {\n        if (ignoreApi(name)) continue;\n        api.rendererProcess[name] = 'process.' + name;\n      }\n    }\n\n    addRenderProcessModules();\n    addMainProcessModules();\n    addBrowserWindow();\n    addWebContents();\n    addProcess();\n\n    return api;\n  }).apply(null, arguments)"
}
[1628656712.353][INFO]: Waiting for pending navigations...
[1628656712.353][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=22) 0B5987E10A2107BFEE81CC2223E21993 {
   "expression": "1"
}
[1628656712.353][DEBUG]: DevTools WebSocket Response: Runtime.evaluate (id=22) 0B5987E10A2107BFEE81CC2223E21993 {
   "result": {
      "description": "1",
      "type": "number",
      "value": 1
   }
}
[1628656712.353][INFO]: Done waiting for pending navigations. Status: ok
[1628656712.354][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=23) 0B5987E10A2107BFEE81CC2223E21993 {
   "awaitPromise": true,
   "expression": "(function() { // Copyright (c) 2012 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\n/**\n * Enum f...",
   "returnByValue": true
}
[1628656712.356][DEBUG]: DevTools WebSocket Event: Runtime.consoleAPICalled 0B5987E10A2107BFEE81CC2223E21993 {
   "args": [ {
      "type": "string",
      "value": "(electron) The remote module is deprecated. Use https://github.com/electron/remote instead."
   } ],
   "executionContextId": 2,
   "stackTrace": {
      "callFrames": [ {
         "columnNumber": 608,
         "functionName": "log",
         "lineNumber": 12,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      }, {
         "columnNumber": 739,
         "functionName": "",
         "lineNumber": 84,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      }, {
         "columnNumber": 6849,
         "functionName": "./lib/renderer/api/remote.ts",
         "lineNumber": 84,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      }, {
         "columnNumber": 169,
         "functionName": "__webpack_require__",
         "lineNumber": 0,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      }, {
         "columnNumber": 964,
         "functionName": "loader",
         "lineNumber": 76,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      }, {
         "columnNumber": 171,
         "functionName": "",
         "lineNumber": 24,
         "scriptId": "150",
         "url": "electron/js2c/renderer_init.js"
      }, {
         "columnNumber": 42,
         "functionName": "addMainProcessModules",
         "lineNumber": 69,
         "scriptId": "180",
         "url": ""
      }, {
         "columnNumber": 4,
         "functionName": "eval",
         "lineNumber": 122,
         "scriptId": "180",
         "url": ""
      }, {
         "columnNumber": 5,
         "functionName": "eval",
         "lineNumber": 128,
         "scriptId": "180",
         "url": ""
      }, {
         "columnNumber": 29,
         "functionName": "executeScript",
         "lineNumber": 446,
         "scriptId": "179",
         "url": ""
      }, {
         "columnNumber": 23,
         "functionName": "",
         "lineNumber": 451,
         "scriptId": "179",
         "url": ""
      }, {
         "columnNumber": 21,
         "functionName": "callFunction",
         "lineNumber": 414,
         "scriptId": "179",
         "url": ""
      }, {
         "columnNumber": 22,
         "functionName": "",
         "lineNumber": 428,
         "scriptId": "179",
         "url": ""
      }, {
         "columnNumber": 2,
         "functionName": "",
         "lineNumber": 429,
         "scriptId": "179",
         "url": ""
      } ]
   },
   "timestamp": 1.6286567123554138e+12,
   "type": "warning"
}
[1628656712.524][DEBUG]: DevTools WebSocket Event: Inspector.targetCrashed 0B5987E10A2107BFEE81CC2223E21993 {

}
[1628656712.525][DEBUG]: DevTools WebSocket Command: Runtime.evaluate (id=24) 0B5987E10A2107BFEE81CC2223E21993 {
   "expression": "1"
}
[1628656712.575][INFO]: [bedf087722f7e6b37111b526de7fde0f] RESPONSE ExecuteScript ERROR unknown error: session deleted because of page crash
from unknown error: cannot determine loading status
from tab crashed
  (Session info: chrome=91.0.4472.106)
[1628656712.575][DEBUG]: Log type 'driver' lost 0 entries on destruction
[1628656712.575][DEBUG]: Log type 'browser' lost 2 entries on destruction
GeorgDangl commented 2 years ago

FYI, we just updated an app from Electron 11 to 13, and could no longer get Spectron to run the E2E tests in a Docker container. We spent half a day on trying to resolve this, but without luck. Here's the Dockerfile we're using, I think that's mostly just cobbled together from some places until it finally worked😀

FROM node:14 AS node

FROM node AS headless
RUN apt-get update && \
    apt-get install -y xvfb \
    libgbm1 \
    libxss1 \
    libnss3 \
    libgtk-3-dev \
    libasound2-dev \
    unzip \
    dos2unix \
    && rm -rf /var/lib/apt/lists/*

FROM headless AS final
ADD docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
RUN dos2unix /docker-entrypoint.sh
EXPOSE 9515
ENV ELECTRON_ENABLE_STACK_DUMPING=true
ENV ELECTRON_ENABLE_LOGGING=true
ENTRYPOINT [ "/docker-entrypoint.sh" ]

As for getting the tests running: What we actually did now was switching to https://github.com/microsoft/playwright. I can't yet vouch for it, but the setup was incredibly easy.

zhex900 commented 2 years ago

@GeorgDangl So you switched to playwright to test your electron?

GeorgDangl commented 2 years ago

Yeah, exactly. We just have a handful of E2E tests, and we’re lucky to have a small abstraction layer for the Spectron API, so switching to it was quite fast.

zhex900 commented 2 years ago

How did you run playWright headlessly ? https://github.com/microsoft/playwright/issues/2609 Can you help me?

GeorgDangl commented 2 years ago

Well, strictly speaking it doesn't run headless, it just runs in Docker with xvfb without showing an UI. So the Dockerfile and the entrypoint are similar to what you have.

We've just got this for a common setup:

const path = require('path');

import { ElectronApplication, _electron } from 'playwright';

export default function setup(): void {
  beforeEach(async function () {
    this.electronApp = await _electron.launch({
      args: ['--disable_splash_screen', path.join(__dirname, '..')]
    });
  });

  afterEach(function () {
    if (this.electronApp) {
      return this.electronApp.close();
    }
  });
}

And then this (shortened) for the tests:

import { E2eAppConfigService } from './e2e-app-config-service';
import { Page } from 'playwright';
import commonSetup from './common-setup';
import { expect } from 'chai';

describe('myproject-ui App', function () {
  commonSetup.apply(this);

  let page: Page;
  let appConfig: { backendUrl: string };

  beforeEach(async function () {
    page = await this.electronApp.firstWindow();
    appConfig = new E2eAppConfigService().getAppConfig();
    await ensureUpdateCheckNotificationIsDisabled();
  });

  it('should display My Project Header in header', async function () {
    const text = await getText('dangl-header h1');
    expect(text).to.contain('some header text');
  });

  it('creates initial windows', async function () {
    const windows = await this.electronApp.windows();
    expect(windows.length).to.equal(1);
  });

});
GeorgDangl commented 2 years ago

I've summarized it a bit here in this blog post: https://blog.dangl.me/archive/running-fully-automated-e2e-tests-in-electron-in-a-docker-container-with-playwright/

zhex900 commented 2 years ago

@GeorgDangl Thank you for sharing your post. So you can run playWright electron test in docker headless?

I read your blog. But I still cannot get my tests to run.

Are you able to give me so help? Have you ever run into Unable to open X display.

https://github.com/microsoft/playwright/issues/8198

GeorgDangl commented 2 years ago

Sorry, didn't run into that problem before, but I replied to your other issue in the Playwright repository.