Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. # <img src="https://cloud.githubusercontent.com/assets/378023/15063284/cf544f2c-1383-11e6-9336-e13bd64b1694.png" width="60px" align="center" alt="Spectron icon"> Spectron
  2. [![CI](https://github.com/electron-userland/spectron/workflows/CI/badge.svg)](https://github.com/electron-userland/spectron/actions) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/)
  3. [![dependencies](https://img.shields.io/david/electron/spectron.svg)](https://david-dm.org/electron/spectron) [![license:mit](https://img.shields.io/badge/license-mit-blue.svg)](https://opensource.org/licenses/MIT) [![npm:](https://img.shields.io/npm/v/spectron.svg)](https://www.npmjs.com/package/spectron) [![downloads](https://img.shields.io/npm/dm/spectron.svg)](https://www.npmjs.com/package/spectron)
  4. Easily test your [Electron](http://electron.atom.io) apps using
  5. [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver) and
  6. [WebdriverIO](http://webdriver.io).
  7. ## Version Map
  8. For given versions of Electron you must depend on a very specific version range of Spectron. Below is a version mapping table between Spectron version and Electron version.
  9. | Electron Version | Spectron Version |
  10. |------------------|------------------|
  11. | `~1.0.0` | `~3.0.0` |
  12. | `~1.1.0` | `~3.1.0` |
  13. | `~1.2.0` | `~3.2.0` |
  14. | `~1.3.0` | `~3.3.0` |
  15. | `~1.4.0` | `~3.4.0` |
  16. | `~1.5.0` | `~3.5.0` |
  17. | `~1.6.0` | `~3.6.0` |
  18. | `~1.7.0` | `~3.7.0` |
  19. | `~1.8.0` | `~3.8.0` |
  20. | `^2.0.0` | `^4.0.0` |
  21. | `^3.0.0` | `^5.0.0` |
  22. | `^4.0.0` | `^6.0.0` |
  23. | `^5.0.0` | `^7.0.0` |
  24. | `^6.0.0` | `^8.0.0` |
  25. | `^7.0.0` | `^9.0.0` |
  26. | `^8.0.0` | `^10.0.0`|
  27. | `^9.0.0` | `^11.0.0`|
  28. | `^10.0.0` | `^12.0.0`|
  29. | `^11.0.0` | `^13.0.0`|
  30. | `^12.0.0` | `^14.0.0`|
  31. | `^13.0.0` | `^15.0.0`|
  32. Learn more from [this presentation](https://speakerdeck.com/kevinsawicki/testing-your-electron-apps-with-chromedriver).
  33. :rotating_light: Upgrading from `1.x` to `2.x`/`3.x`? Read the [changelog](https://github.com/electron/spectron/blob/master/CHANGELOG.md).
  34. ## Installation
  35. ```sh
  36. npm install --save-dev spectron
  37. ```
  38. ## Usage
  39. Spectron works with any testing framework but the following example uses
  40. [mocha](https://mochajs.org):
  41. To get up and running from your command line:
  42. ```sh
  43. # Install mocha locally as a dev dependency.
  44. npm i mocha -D
  45. # From the project root, create a folder called test, in that directory, create a file called 'spec.js'
  46. touch test/spec.js
  47. # Change directory to test
  48. cd test
  49. ```
  50. Then simply include the following in your first `spec.js`.
  51. ```js
  52. const Application = require('spectron').Application
  53. const assert = require('assert')
  54. const electronPath = require('electron') // Require Electron from the binaries included in node_modules.
  55. const path = require('path')
  56. describe('Application launch', function () {
  57. this.timeout(10000)
  58. beforeEach(function () {
  59. this.app = new Application({
  60. // Your electron path can be any binary
  61. // i.e for OSX an example path could be '/Applications/MyApp.app/Contents/MacOS/MyApp'
  62. // But for the sake of the example we fetch it from our node_modules.
  63. path: electronPath,
  64. // Assuming you have the following directory structure
  65. // |__ my project
  66. // |__ ...
  67. // |__ main.js
  68. // |__ package.json
  69. // |__ index.html
  70. // |__ ...
  71. // |__ test
  72. // |__ spec.js <- You are here! ~ Well you should be.
  73. // The following line tells spectron to look and use the main.js file
  74. // and the package.json located 1 level above.
  75. args: [path.join(__dirname, '..')]
  76. })
  77. return this.app.start()
  78. })
  79. afterEach(function () {
  80. if (this.app && this.app.isRunning()) {
  81. return this.app.stop()
  82. }
  83. })
  84. it('shows an initial window', function () {
  85. return this.app.client.getWindowCount().then(function (count) {
  86. assert.equal(count, 1)
  87. // Please note that getWindowCount() will return 2 if `dev tools` are opened.
  88. // assert.equal(count, 2)
  89. })
  90. })
  91. })
  92. ```
  93. Create an npm task in your package.json file
  94. ```sh
  95. "scripts": {
  96. "test": "mocha"
  97. }
  98. ```
  99. And from the root of your project, in your command-line simply run:
  100. ```sh
  101. npm test
  102. ```
  103. By default, mocha searches for a folder with the name `test` ( which we created before ).
  104. For more information on how to configure mocha, please visit [mocha](https://mochajs.org).
  105. #### Limitations
  106. As stated in [issue #19](https://github.com/electron/spectron/issues/19), Spectron will not be able to start if your Electron app is launched using the `remote-debugging-port` command-line switch (i.e. `app.commandLine.appendSwitch('remote-debugging-port', <debugging-port-number>);`). Please make sure to include the necessary logic in your app's code to disable the switch during tests.
  107. ## Application API
  108. Spectron exports an `Application` class that when configured, can start and
  109. stop your Electron application.
  110. ### new Application(options)
  111. Create a new application with the following options:
  112. * `path` - **Required.** String path to the Electron application executable to
  113. launch.
  114. **Note:** If you want to invoke `electron` directly with your app's main
  115. script then you should specify `path` as `electron` via `electron-prebuilt`
  116. and specify your app's main script path as the first argument in the `args`
  117. array.
  118. * `args` - Array of arguments to pass to the Electron application.
  119. * `chromeDriverArgs` - Array of arguments to pass to ChromeDriver.
  120. See [here](https://sites.google.com/a/chromium.org/chromedriver/capabilities) for details on the Chrome arguments.
  121. * `cwd`- String path to the working directory to use for the launched
  122. application. Defaults to `process.cwd()`.
  123. * `env` - Object of additional environment variables to set in the launched
  124. application.
  125. * `host` - String host name of the launched `chromedriver` process.
  126. Defaults to `'localhost'`.
  127. * `port` - Number port of the launched `chromedriver` process.
  128. Defaults to `9515`.
  129. * `nodePath` - String path to a `node` executable to launch ChromeDriver with.
  130. Defaults to `process.execPath`.
  131. * `connectionRetryCount` - Number of retry attempts to make when connecting
  132. to ChromeDriver. Defaults to `10` attempts.
  133. * `connectionRetryTimeout` - Number in milliseconds to wait for connections
  134. to ChromeDriver to be made. Defaults to `30000` milliseconds.
  135. * `quitTimeout` - Number in milliseconds to wait for application quitting.
  136. Defaults to `1000` milliseconds.
  137. * `requireName` - Custom property name to use when requiring modules. Defaults
  138. to `require`. This should only be used if your application deletes the main
  139. `window.require` function and assigns it to another property name on `window`.
  140. * `startTimeout` - Number in milliseconds to wait for ChromeDriver to start.
  141. Defaults to `5000` milliseconds.
  142. * `waitTimeout` - Number in milliseconds to wait for calls like
  143. `waitUntilTextExists` and `waitUntilWindowLoaded` to complete.
  144. Defaults to `5000` milliseconds.
  145. * `debuggerAddress` - String address of a Chrome debugger server to connect to.
  146. * `chromeDriverLogPath` - String path to file to store ChromeDriver logs in.
  147. Setting this option enables `--verbose` logging when starting ChromeDriver.
  148. * `webdriverLogPath` - String path to a directory where Webdriver will write
  149. logs to. Setting this option enables `verbose` logging from Webdriver.
  150. * `webdriverOptions` - Object of additional options for Webdriver
  151. ### Node Integration
  152. The Electron helpers provided by Spectron require accessing the core Electron
  153. APIs in the renderer processes of your application. So, either your Electron
  154. application has `nodeIntegration` set to `true` or you'll need to expose a
  155. `require` window global to Spectron so it can access the core Electron APIs.
  156. You can do this by adding a [`preload`][preload] script that does the following:
  157. ```js
  158. if (process.env.NODE_ENV === 'test') {
  159. window.electronRequire = require
  160. }
  161. ```
  162. Then create the Spectron `Application` with the `requireName` option set to
  163. `'electronRequire'` and then runs your tests via `NODE_ENV=test npm test`.
  164. **Note:** This is only required if your tests are accessing any Electron APIs.
  165. You don't need to do this if you are only accessing the helpers on the `client`
  166. property which do not require Node integration.
  167. ### Properties
  168. #### client
  169. Spectron uses [WebdriverIO](http://webdriver.io) and exposes the managed
  170. `client` property on the created `Application` instances.
  171. The `client` API is WebdriverIO's `browser` object. Documentation can be found
  172. [here](http://webdriver.io/api.html).
  173. Several additional commands are provided specific to Electron.
  174. All the commands return a `Promise`.
  175. So if you wanted to get the text of an element you would do:
  176. ```js
  177. app.client.getText('#error-alert').then(function (errorText) {
  178. console.log('The #error-alert text content is ' + errorText)
  179. })
  180. ```
  181. #### electron
  182. The `electron` property is your gateway to accessing the full Electron API.
  183. Each Electron module is exposed as a property on the `electron` property
  184. so you can think of it as an alias for `require('electron')` from within your
  185. app.
  186. So if you wanted to access the [clipboard](http://electron.atom.io/docs/latest/api/clipboard)
  187. API in your tests you would do:
  188. ```js
  189. app.electron.clipboard.writeText('pasta')
  190. .electron.clipboard.readText().then(function (clipboardText) {
  191. console.log('The clipboard text is ' + clipboardText)
  192. })
  193. ```
  194. #### browserWindow
  195. The `browserWindow` property is an alias for `require('electron').remote.getCurrentWindow()`.
  196. It provides you access to the current [BrowserWindow](http://electron.atom.io/docs/latest/api/browser-window/)
  197. and contains all the APIs.
  198. So if you wanted to check if the current window is visible in your tests you
  199. would do:
  200. ```js
  201. app.browserWindow.isVisible().then(function (visible) {
  202. console.log('window is visible? ' + visible)
  203. })
  204. ```
  205. It is named `browserWindow` instead of `window` so that it doesn't collide
  206. with the WebDriver command of that name.
  207. ##### capturePage
  208. The async `capturePage` API is supported but instead of taking a callback it
  209. returns a `Promise` that resolves to a `Buffer` that is the image data of
  210. screenshot.
  211. ```js
  212. app.browserWindow.capturePage().then(function (imageBuffer) {
  213. fs.writeFile('page.png', imageBuffer)
  214. })
  215. ```
  216. #### webContents
  217. The `webContents` property is an alias for `require('electron').remote.getCurrentWebContents()`.
  218. It provides you access to the [WebContents](http://electron.atom.io/docs/latest/api/web-contents/)
  219. for the current window and contains all the APIs.
  220. So if you wanted to check if the current window is loading in your tests you
  221. would do:
  222. ```js
  223. app.webContents.isLoading().then(function (visible) {
  224. console.log('window is loading? ' + visible)
  225. })
  226. ```
  227. ##### savePage
  228. The async `savePage` API is supported but instead of taking a callback it
  229. returns a `Promise` that will raise any errors and resolve to `undefined` when
  230. complete.
  231. ```js
  232. app.webContents.savePage('/Users/kevin/page.html', 'HTMLComplete')
  233. .then(function () {
  234. console.log('page saved')
  235. }).catch(function (error) {
  236. console.error('saving page failed', error.message)
  237. })
  238. ```
  239. ##### executeJavaScript
  240. The async `executeJavaScript` API is supported but instead of taking a callback it
  241. returns a `Promise` that will resolve with the result of the last statement of the
  242. script.
  243. ```js
  244. app.webContents.executeJavaScript('1 + 2')
  245. .then(function (result) {
  246. console.log(result) // prints 3
  247. })
  248. ```
  249. #### mainProcess
  250. The `mainProcess` property is an alias for `require('electron').remote.process`.
  251. It provides you access to the main process's [process](https://nodejs.org/api/process.html)
  252. global.
  253. So if you wanted to get the `argv` for the main process in your tests you would
  254. do:
  255. ```js
  256. app.mainProcess.argv().then(function (argv) {
  257. console.log('main process args: ' + argv)
  258. })
  259. ```
  260. Properties on the `process` are exposed as functions that return promises so
  261. make sure to call `mainProcess.env().then(...)` instead of
  262. `mainProcess.env.then(...)`.
  263. #### rendererProcess
  264. The `rendererProcess` property is an alias for `global.process`.
  265. It provides you access to the renderer process's [process](https://nodejs.org/api/process.html)
  266. global.
  267. So if you wanted to get the environment variables for the renderer process in
  268. your tests you would do:
  269. ```js
  270. app.rendererProcess.env().then(function (env) {
  271. console.log('renderer process env variables: ' + env)
  272. })
  273. ```
  274. ### Methods
  275. #### start()
  276. Starts the application. Returns a `Promise` that will be resolved when the
  277. application is ready to use. You should always wait for start to complete
  278. before running any commands.
  279. #### stop()
  280. Stops the application. Returns a `Promise` that will be resolved once the
  281. application has stopped.
  282. #### restart()
  283. Stops the application and then starts it. Returns a `Promise` that will be
  284. resolved once the application has started again.
  285. #### isRunning()
  286. Checks to determine if the application is running or not.
  287. Returns a `Boolean`.
  288. #### getSettings()
  289. Get all the configured options passed to the `new Application()` constructor.
  290. This will include the default options values currently being used.
  291. Returns an `Object`.
  292. #### client.getMainProcessLogs()
  293. Gets the `console` log output from the main process. The logs are cleared
  294. after they are returned.
  295. Returns a `Promise` that resolves to an array of string log messages
  296. ```js
  297. app.client.getMainProcessLogs().then(function (logs) {
  298. logs.forEach(function (log) {
  299. console.log(log)
  300. })
  301. })
  302. ```
  303. #### client.getRenderProcessLogs()
  304. Gets the `console` log output from the render process. The logs are cleared
  305. after they are returned.
  306. Returns a `Promise` that resolves to an array of log objects.
  307. ```js
  308. app.client.getRenderProcessLogs().then(function (logs) {
  309. logs.forEach(function (log) {
  310. console.log(log.message)
  311. console.log(log.source)
  312. console.log(log.level)
  313. })
  314. })
  315. ```
  316. #### client.getSelectedText()
  317. Get the selected text in the current window.
  318. ```js
  319. app.client.getSelectedText().then(function (selectedText) {
  320. console.log(selectedText)
  321. })
  322. ```
  323. #### client.getWindowCount()
  324. Gets the number of open windows.
  325. `<webview>` tags are also counted as separate windows.
  326. ```js
  327. app.client.getWindowCount().then(function (count) {
  328. console.log(count)
  329. })
  330. ```
  331. #### client.waitUntilTextExists(selector, text, [timeout])
  332. Waits until the element matching the given selector contains the given
  333. text. Takes an optional timeout in milliseconds that defaults to `5000`.
  334. ```js
  335. app.client.waitUntilTextExists('#message', 'Success', 10000)
  336. ```
  337. #### client.waitUntilWindowLoaded([timeout])
  338. Wait until the window is no longer loading. Takes an optional timeout
  339. in milliseconds that defaults to `5000`.
  340. ```js
  341. app.client.waitUntilWindowLoaded(10000)
  342. ```
  343. #### client.windowByIndex(index)
  344. Focus a window using its index from the `windowHandles()` array.
  345. `<webview>` tags can also be focused as a separate window.
  346. ```js
  347. app.client.windowByIndex(1)
  348. ```
  349. #### client.switchWindow(urlOrTitleToMatch)
  350. Focus a window using its URL or title.
  351. ```js
  352. // switch via url match
  353. app.client.switchWindow('google.com')
  354. // switch via title match
  355. app.client.switchWindow('Next-gen WebDriver test framework')
  356. ```
  357. ### Accessibility Testing
  358. Spectron bundles the [Accessibility Developer Tools](https://github.com/GoogleChrome/accessibility-developer-tools)
  359. provided by Google and adds support for auditing each window and `<webview>`
  360. tag in your application.
  361. #### client.auditAccessibility(options)
  362. Run an accessibility audit in the focused window with the specified options.
  363. * `options` - An optional Object with the following keys:
  364. * `ignoreWarnings` - `true` to ignore failures with a severity of `'Warning'`
  365. and only include failures with a severity of `'Severe'`. Defaults to `false`.
  366. * `ignoreRules` - Array of String rule code values such as `AX_COLOR_01` to
  367. ignore failures for. The full list is available [here](https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules).
  368. Returns an `audit` Object with the following properties:
  369. * `message` - A detailed String message about the results
  370. * `failed` - A Boolean, `false` when the audit has failures
  371. * `results` - An array of detail objects for each failed rule. Each object
  372. in the array has the following properties:
  373. * `code` - A unique String accessibility rule identifier
  374. * `elements` - An Array of Strings representing the selector path of each
  375. HTML element that failed the rule
  376. * `message` - A String message about the failed rule
  377. * `severity` - `'Warning'` or `'Severe'`
  378. * `url` - A String URL providing more details about the failed rule
  379. ```js
  380. app.client.auditAccessibility().then(function (audit) {
  381. if (audit.failed) {
  382. console.error(audit.message)
  383. }
  384. })
  385. ```
  386. See https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules
  387. for more details about the audit rules.
  388. If you are using a `<webview>` tag in your app and want to audit both the outer
  389. page and the `<webview>`'s page then you will need to do the following:
  390. ```js
  391. // Focus main page and audit it
  392. app.client.windowByIndex(0).then(function() {
  393. app.client.auditAccessibility().then(function (audit) {
  394. if (audit.failed) {
  395. console.error('Main page failed audit')
  396. console.error(audit.message)
  397. }
  398. //Focus <webview> tag and audit it
  399. app.client.windowByIndex(1).then(function() {
  400. app.client.auditAccessibility().then(function (audit) {
  401. if (audit.failed) {
  402. console.error('<webview> page failed audit')
  403. console.error(audit.message)
  404. }
  405. })
  406. })
  407. })
  408. })
  409. ```
  410. ## Continuous Integration
  411. ### On Travis CI
  412. You will want to add the following to your `.travis.yml` file when building on
  413. Linux:
  414. ```yml
  415. before_script:
  416. - "export DISPLAY=:99.0"
  417. - "sh -e /etc/init.d/xvfb start"
  418. - sleep 3 # give xvfb some time to start
  419. ```
  420. Check out Spectron's [.travis.yml](https://github.com/electron/spectron/blob/master/.travis.yml)
  421. file for a production example.
  422. ### On AppVeyor
  423. You will want to add the following to your `appveyor.yml` file:
  424. ```yml
  425. os: unstable
  426. ```
  427. Check out Spectron's [appveyor.yml](https://github.com/electron/spectron/blob/master/appveyor.yml)
  428. file for a production example.
  429. ## Test Library Examples
  430. ### With Chai As Promised
  431. WebdriverIO is promise-based and so it pairs really well with the
  432. [Chai as Promised](https://github.com/domenic/chai-as-promised) library that
  433. builds on top of [Chai](http://chaijs.com).
  434. Using these together allows you to chain assertions together and have fewer
  435. callback blocks. See below for a simple example:
  436. ```sh
  437. npm install --save-dev chai
  438. npm install --save-dev chai-as-promised
  439. ```
  440. ```js
  441. const Application = require('spectron').Application
  442. const chai = require('chai')
  443. const chaiAsPromised = require('chai-as-promised')
  444. const electronPath = require('electron')
  445. const path = require('path')
  446. chai.should()
  447. chai.use(chaiAsPromised)
  448. describe('Application launch', function () {
  449. this.timeout(10000);
  450. beforeEach(function () {
  451. this.app = new Application({
  452. path: electronPath,
  453. args: [path.join(__dirname, '..')]
  454. })
  455. return this.app.start()
  456. })
  457. beforeEach(function () {
  458. chaiAsPromised.transferPromiseness = this.app.transferPromiseness
  459. })
  460. afterEach(function () {
  461. if (this.app && this.app.isRunning()) {
  462. return this.app.stop()
  463. }
  464. })
  465. it('opens a window', function () {
  466. return this.app.client.waitUntilWindowLoaded()
  467. .getWindowCount().should.eventually.have.at.least(1)
  468. .browserWindow.isMinimized().should.eventually.be.false
  469. .browserWindow.isVisible().should.eventually.be.true
  470. .browserWindow.isFocused().should.eventually.be.true
  471. .browserWindow.getBounds().should.eventually.have.property('width').and.be.above(0)
  472. .browserWindow.getBounds().should.eventually.have.property('height').and.be.above(0)
  473. })
  474. })
  475. ```
  476. ### With AVA
  477. Spectron works with [AVA](https://github.com/avajs/ava), which allows you
  478. to write your tests in ES2015+ without doing any extra work.
  479. ```js
  480. import test from 'ava';
  481. import {Application} from 'spectron';
  482. test.beforeEach(t => {
  483. t.context.app = new Application({
  484. path: '/Applications/MyApp.app/Contents/MacOS/MyApp'
  485. });
  486. return t.context.app.start();
  487. });
  488. test.afterEach(t => {
  489. return t.context.app.stop();
  490. });
  491. test(t => {
  492. return t.context.app.client.waitUntilWindowLoaded()
  493. .getWindowCount().then(count => {
  494. t.is(count, 1);
  495. }).browserWindow.isMinimized().then(min => {
  496. t.false(min);
  497. }).browserWindow.isDevToolsOpened().then(opened => {
  498. t.false(opened);
  499. }).browserWindow.isVisible().then(visible => {
  500. t.true(visible);
  501. }).browserWindow.isFocused().then(focused => {
  502. t.true(focused);
  503. }).browserWindow.getBounds().then(bounds => {
  504. t.true(bounds.width > 0);
  505. t.true(bounds.height > 0);
  506. });
  507. });
  508. ```
  509. AVA has built-in support for [async functions](https://github.com/avajs/ava#async-function-support), which simplifies async operations:
  510. ```js
  511. import test from 'ava';
  512. import {Application} from 'spectron';
  513. test.beforeEach(async t => {
  514. t.context.app = new Application({
  515. path: '/Applications/MyApp.app/Contents/MacOS/MyApp'
  516. });
  517. await t.context.app.start();
  518. });
  519. test.afterEach.always(async t => {
  520. await t.context.app.stop();
  521. });
  522. test(async t => {
  523. const app = t.context.app;
  524. await app.client.waitUntilWindowLoaded();
  525. const win = app.browserWindow;
  526. t.is(await app.client.getWindowCount(), 1);
  527. t.false(await win.isMinimized());
  528. t.false(await win.isDevToolsOpened());
  529. t.true(await win.isVisible());
  530. t.true(await win.isFocused());
  531. const {width, height} = await win.getBounds();
  532. t.true(width > 0);
  533. t.true(height > 0);
  534. });
  535. ```
  536. [preload]: http://electron.atom.io/docs/api/browser-window/#new-browserwindowoptions