api-web-contents-spec.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. 'use strict'
  2. const assert = require('assert')
  3. const path = require('path')
  4. const {closeWindow} = require('./window-helpers')
  5. const {ipcRenderer, remote} = require('electron')
  6. const {BrowserWindow, webContents, ipcMain} = remote
  7. const isCi = remote.getGlobal('isCi')
  8. describe('webContents module', function () {
  9. const fixtures = path.resolve(__dirname, 'fixtures')
  10. let w
  11. beforeEach(function () {
  12. w = new BrowserWindow({
  13. show: false,
  14. width: 400,
  15. height: 400,
  16. webPreferences: {
  17. backgroundThrottling: false
  18. }
  19. })
  20. })
  21. afterEach(function () {
  22. return closeWindow(w).then(function () { w = null })
  23. })
  24. describe('getAllWebContents() API', function () {
  25. it('returns an array of web contents', function (done) {
  26. w.webContents.on('devtools-opened', function () {
  27. const all = webContents.getAllWebContents().sort(function (a, b) {
  28. return a.getId() - b.getId()
  29. })
  30. assert.ok(all.length >= 4)
  31. assert.equal(all[0].getType(), 'window')
  32. assert.equal(all[all.length - 2].getType(), 'remote')
  33. assert.equal(all[all.length - 1].getType(), 'webview')
  34. done()
  35. })
  36. w.loadURL('file://' + path.join(fixtures, 'pages', 'webview-zoom-factor.html'))
  37. w.webContents.openDevTools()
  38. })
  39. })
  40. describe('getFocusedWebContents() API', function () {
  41. it('returns the focused web contents', function (done) {
  42. if (isCi) return done()
  43. const specWebContents = remote.getCurrentWebContents()
  44. assert.equal(specWebContents.getId(), webContents.getFocusedWebContents().getId())
  45. specWebContents.once('devtools-opened', function () {
  46. assert.equal(specWebContents.devToolsWebContents.getId(), webContents.getFocusedWebContents().getId())
  47. specWebContents.closeDevTools()
  48. })
  49. specWebContents.once('devtools-closed', function () {
  50. assert.equal(specWebContents.getId(), webContents.getFocusedWebContents().getId())
  51. done()
  52. })
  53. specWebContents.openDevTools()
  54. })
  55. it('does not crash when called on a detached dev tools window', function (done) {
  56. const specWebContents = w.webContents
  57. specWebContents.once('devtools-opened', function () {
  58. assert.doesNotThrow(function () {
  59. webContents.getFocusedWebContents()
  60. })
  61. specWebContents.closeDevTools()
  62. })
  63. specWebContents.once('devtools-closed', function () {
  64. assert.doesNotThrow(function () {
  65. webContents.getFocusedWebContents()
  66. })
  67. done()
  68. })
  69. specWebContents.openDevTools({mode: 'detach'})
  70. w.inspectElement(100, 100)
  71. })
  72. })
  73. describe('isFocused() API', function () {
  74. it('returns false when the window is hidden', function () {
  75. BrowserWindow.getAllWindows().forEach(function (window) {
  76. assert.equal(!window.isVisible() && window.webContents.isFocused(), false)
  77. })
  78. })
  79. })
  80. describe('before-input-event event', () => {
  81. it('can prevent document keyboard events', (done) => {
  82. w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'key-events.html'))
  83. w.webContents.once('did-finish-load', () => {
  84. ipcMain.once('keydown', (event, key) => {
  85. assert.equal(key, 'b')
  86. done()
  87. })
  88. ipcRenderer.send('prevent-next-input-event', 'a', w.webContents.id)
  89. w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'a'})
  90. w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'b'})
  91. })
  92. })
  93. it('has the correct properties', (done) => {
  94. w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'base-page.html'))
  95. w.webContents.once('did-finish-load', () => {
  96. const testBeforeInput = (opts) => {
  97. return new Promise((resolve, reject) => {
  98. w.webContents.once('before-input-event', (event, input) => {
  99. assert.equal(input.type, opts.type)
  100. assert.equal(input.key, opts.key)
  101. assert.equal(input.code, opts.code)
  102. assert.equal(input.isAutoRepeat, opts.isAutoRepeat)
  103. assert.equal(input.shift, opts.shift)
  104. assert.equal(input.control, opts.control)
  105. assert.equal(input.alt, opts.alt)
  106. assert.equal(input.meta, opts.meta)
  107. resolve()
  108. })
  109. const modifiers = []
  110. if (opts.shift) modifiers.push('shift')
  111. if (opts.control) modifiers.push('control')
  112. if (opts.alt) modifiers.push('alt')
  113. if (opts.meta) modifiers.push('meta')
  114. if (opts.isAutoRepeat) modifiers.push('isAutoRepeat')
  115. w.webContents.sendInputEvent({
  116. type: opts.type,
  117. keyCode: opts.keyCode,
  118. modifiers: modifiers
  119. })
  120. })
  121. }
  122. Promise.resolve().then(() => {
  123. return testBeforeInput({
  124. type: 'keyDown',
  125. key: 'A',
  126. code: 'KeyA',
  127. keyCode: 'a',
  128. shift: true,
  129. control: true,
  130. alt: true,
  131. meta: true,
  132. isAutoRepeat: true
  133. })
  134. }).then(() => {
  135. return testBeforeInput({
  136. type: 'keyUp',
  137. key: '.',
  138. code: 'Period',
  139. keyCode: '.',
  140. shift: false,
  141. control: true,
  142. alt: true,
  143. meta: false,
  144. isAutoRepeat: false
  145. })
  146. }).then(() => {
  147. return testBeforeInput({
  148. type: 'keyUp',
  149. key: '!',
  150. code: 'Digit1',
  151. keyCode: '1',
  152. shift: true,
  153. control: false,
  154. alt: false,
  155. meta: true,
  156. isAutoRepeat: false
  157. })
  158. }).then(() => {
  159. return testBeforeInput({
  160. type: 'keyUp',
  161. key: 'Tab',
  162. code: 'Tab',
  163. keyCode: 'Tab',
  164. shift: false,
  165. control: true,
  166. alt: false,
  167. meta: false,
  168. isAutoRepeat: true
  169. })
  170. }).then(done).catch(done)
  171. })
  172. })
  173. })
  174. describe('sendInputEvent(event)', function () {
  175. beforeEach(function (done) {
  176. w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'key-events.html'))
  177. w.webContents.once('did-finish-load', function () {
  178. done()
  179. })
  180. })
  181. it('can send keydown events', function (done) {
  182. ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) {
  183. assert.equal(key, 'a')
  184. assert.equal(code, 'KeyA')
  185. assert.equal(keyCode, 65)
  186. assert.equal(shiftKey, false)
  187. assert.equal(ctrlKey, false)
  188. assert.equal(altKey, false)
  189. done()
  190. })
  191. w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'A'})
  192. })
  193. it('can send keydown events with modifiers', function (done) {
  194. ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) {
  195. assert.equal(key, 'Z')
  196. assert.equal(code, 'KeyZ')
  197. assert.equal(keyCode, 90)
  198. assert.equal(shiftKey, true)
  199. assert.equal(ctrlKey, true)
  200. assert.equal(altKey, false)
  201. done()
  202. })
  203. w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'Z', modifiers: ['shift', 'ctrl']})
  204. })
  205. it('can send keydown events with special keys', function (done) {
  206. ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) {
  207. assert.equal(key, 'Tab')
  208. assert.equal(code, 'Tab')
  209. assert.equal(keyCode, 9)
  210. assert.equal(shiftKey, false)
  211. assert.equal(ctrlKey, false)
  212. assert.equal(altKey, true)
  213. done()
  214. })
  215. w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'Tab', modifiers: ['alt']})
  216. })
  217. it('can send char events', function (done) {
  218. ipcMain.once('keypress', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) {
  219. assert.equal(key, 'a')
  220. assert.equal(code, 'KeyA')
  221. assert.equal(keyCode, 65)
  222. assert.equal(shiftKey, false)
  223. assert.equal(ctrlKey, false)
  224. assert.equal(altKey, false)
  225. done()
  226. })
  227. w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'A'})
  228. w.webContents.sendInputEvent({type: 'char', keyCode: 'A'})
  229. })
  230. it('can send char events with modifiers', function (done) {
  231. ipcMain.once('keypress', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) {
  232. assert.equal(key, 'Z')
  233. assert.equal(code, 'KeyZ')
  234. assert.equal(keyCode, 90)
  235. assert.equal(shiftKey, true)
  236. assert.equal(ctrlKey, true)
  237. assert.equal(altKey, false)
  238. done()
  239. })
  240. w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'Z'})
  241. w.webContents.sendInputEvent({type: 'char', keyCode: 'Z', modifiers: ['shift', 'ctrl']})
  242. })
  243. })
  244. it('supports inserting CSS', function (done) {
  245. w.loadURL('about:blank')
  246. w.webContents.insertCSS('body { background-repeat: round; }')
  247. w.webContents.executeJavaScript('window.getComputedStyle(document.body).getPropertyValue("background-repeat")', (result) => {
  248. assert.equal(result, 'round')
  249. done()
  250. })
  251. })
  252. it('supports inspecting an element in the devtools', function (done) {
  253. w.loadURL('about:blank')
  254. w.webContents.once('devtools-opened', function () {
  255. done()
  256. })
  257. w.webContents.inspectElement(10, 10)
  258. })
  259. describe('startDrag({file, icon})', () => {
  260. it('throws errors for a missing file or a missing/empty icon', () => {
  261. assert.throws(() => {
  262. w.webContents.startDrag({icon: path.join(__dirname, 'fixtures', 'assets', 'logo.png')})
  263. }, /Must specify either 'file' or 'files' option/)
  264. assert.throws(() => {
  265. w.webContents.startDrag({file: __filename})
  266. }, /Must specify 'icon' option/)
  267. if (process.platform === 'darwin') {
  268. assert.throws(() => {
  269. w.webContents.startDrag({file: __filename, icon: __filename})
  270. }, /Must specify non-empty 'icon' option/)
  271. }
  272. })
  273. })
  274. })