chromium-spec.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. const assert = require('assert')
  2. const http = require('http')
  3. const path = require('path')
  4. const ws = require('ws')
  5. const url = require('url')
  6. const {ipcRenderer, remote} = require('electron')
  7. const {closeWindow} = require('./window-helpers')
  8. const {app, BrowserWindow, ipcMain, protocol, session, webContents} = remote
  9. const isCI = remote.getGlobal('isCi')
  10. describe('chromium feature', function () {
  11. var fixtures = path.resolve(__dirname, 'fixtures')
  12. var listener = null
  13. afterEach(function () {
  14. if (listener != null) {
  15. window.removeEventListener('message', listener)
  16. }
  17. listener = null
  18. })
  19. xdescribe('heap snapshot', function () {
  20. it('does not crash', function () {
  21. process.atomBinding('v8_util').takeHeapSnapshot()
  22. })
  23. })
  24. describe('sending request of http protocol urls', function () {
  25. it('does not crash', function (done) {
  26. var server = http.createServer(function (req, res) {
  27. res.end()
  28. server.close()
  29. done()
  30. })
  31. server.listen(0, '127.0.0.1', function () {
  32. var port = server.address().port
  33. $.get('http://127.0.0.1:' + port)
  34. })
  35. })
  36. })
  37. describe('document.hidden', function () {
  38. var url = 'file://' + fixtures + '/pages/document-hidden.html'
  39. var w = null
  40. afterEach(function () {
  41. return closeWindow(w).then(function () { w = null })
  42. })
  43. it('is set correctly when window is not shown', function (done) {
  44. w = new BrowserWindow({
  45. show: false
  46. })
  47. w.webContents.once('ipc-message', function (event, args) {
  48. assert.deepEqual(args, ['hidden', true])
  49. done()
  50. })
  51. w.loadURL(url)
  52. })
  53. it('is set correctly when window is inactive', function (done) {
  54. if (isCI && process.platform === 'win32') return done()
  55. w = new BrowserWindow({
  56. show: false
  57. })
  58. w.webContents.once('ipc-message', function (event, args) {
  59. assert.deepEqual(args, ['hidden', false])
  60. done()
  61. })
  62. w.showInactive()
  63. w.loadURL(url)
  64. })
  65. })
  66. xdescribe('navigator.webkitGetUserMedia', function () {
  67. it('calls its callbacks', function (done) {
  68. navigator.webkitGetUserMedia({
  69. audio: true,
  70. video: false
  71. }, function () {
  72. done()
  73. }, function () {
  74. done()
  75. })
  76. })
  77. })
  78. describe('navigator.mediaDevices', function () {
  79. if (process.env.TRAVIS === 'true') {
  80. return
  81. }
  82. if (isCI && process.platform === 'linux') {
  83. return
  84. }
  85. if (isCI && process.platform === 'win32') {
  86. return
  87. }
  88. it('can return labels of enumerated devices', function (done) {
  89. navigator.mediaDevices.enumerateDevices().then((devices) => {
  90. const labels = devices.map((device) => device.label)
  91. const labelFound = labels.some((label) => !!label)
  92. if (labelFound) {
  93. done()
  94. } else {
  95. done('No device labels found: ' + JSON.stringify(labels))
  96. }
  97. }).catch(done)
  98. })
  99. it('can return new device id when cookie storage is cleared', function (done) {
  100. const options = {
  101. origin: null,
  102. storages: ['cookies']
  103. }
  104. const deviceIds = []
  105. const ses = session.fromPartition('persist:media-device-id')
  106. let w = new BrowserWindow({
  107. show: false,
  108. webPreferences: {
  109. session: ses
  110. }
  111. })
  112. w.webContents.on('ipc-message', function (event, args) {
  113. if (args[0] === 'deviceIds') {
  114. deviceIds.push(args[1])
  115. }
  116. if (deviceIds.length === 2) {
  117. assert.notDeepEqual(deviceIds[0], deviceIds[1])
  118. closeWindow(w).then(function () {
  119. w = null
  120. done()
  121. }).catch(function (error) {
  122. done(error)
  123. })
  124. } else {
  125. ses.clearStorageData(options, function () {
  126. w.webContents.reload()
  127. })
  128. }
  129. })
  130. w.loadURL('file://' + fixtures + '/pages/media-id-reset.html')
  131. })
  132. })
  133. describe('navigator.language', function () {
  134. it('should not be empty', function () {
  135. assert.notEqual(navigator.language, '')
  136. })
  137. })
  138. describe('navigator.serviceWorker', function () {
  139. var url = 'file://' + fixtures + '/pages/service-worker/index.html'
  140. var w = null
  141. afterEach(function () {
  142. return closeWindow(w).then(function () { w = null })
  143. })
  144. it('should register for file scheme', function (done) {
  145. w = new BrowserWindow({
  146. show: false
  147. })
  148. w.webContents.on('ipc-message', function (event, args) {
  149. if (args[0] === 'reload') {
  150. w.webContents.reload()
  151. } else if (args[0] === 'error') {
  152. done('unexpected error : ' + args[1])
  153. } else if (args[0] === 'response') {
  154. assert.equal(args[1], 'Hello from serviceWorker!')
  155. session.defaultSession.clearStorageData({
  156. storages: ['serviceworkers']
  157. }, function () {
  158. done()
  159. })
  160. }
  161. })
  162. w.loadURL(url)
  163. })
  164. })
  165. describe('window.open', function () {
  166. if (process.env.TRAVIS === 'true' && process.platform === 'darwin') {
  167. return
  168. }
  169. let w = null
  170. afterEach(() => {
  171. return closeWindow(w).then(function () { w = null })
  172. })
  173. it('returns a BrowserWindowProxy object', function () {
  174. var b = window.open('about:blank', '', 'show=no')
  175. assert.equal(b.closed, false)
  176. assert.equal(b.constructor.name, 'BrowserWindowProxy')
  177. b.close()
  178. })
  179. it('accepts "nodeIntegration" as feature', function (done) {
  180. var b
  181. listener = function (event) {
  182. assert.equal(event.data.isProcessGlobalUndefined, true)
  183. b.close()
  184. done()
  185. }
  186. window.addEventListener('message', listener)
  187. b = window.open('file://' + fixtures + '/pages/window-opener-node.html', '', 'nodeIntegration=no,show=no')
  188. })
  189. it('inherit options of parent window', function (done) {
  190. var b
  191. listener = function (event) {
  192. var ref1 = remote.getCurrentWindow().getSize()
  193. var width = ref1[0]
  194. var height = ref1[1]
  195. assert.equal(event.data, 'size: ' + width + ' ' + height)
  196. b.close()
  197. done()
  198. }
  199. window.addEventListener('message', listener)
  200. b = window.open('file://' + fixtures + '/pages/window-open-size.html', '', 'show=no')
  201. })
  202. it('disables node integration when it is disabled on the parent window', function (done) {
  203. var b
  204. listener = function (event) {
  205. assert.equal(event.data.isProcessGlobalUndefined, true)
  206. b.close()
  207. done()
  208. }
  209. window.addEventListener('message', listener)
  210. var windowUrl = require('url').format({
  211. pathname: `${fixtures}/pages/window-opener-no-node-integration.html`,
  212. protocol: 'file',
  213. query: {
  214. p: `${fixtures}/pages/window-opener-node.html`
  215. },
  216. slashes: true
  217. })
  218. b = window.open(windowUrl, '', 'nodeIntegration=no,show=no')
  219. })
  220. it('does not override child options', function (done) {
  221. var b, size
  222. size = {
  223. width: 350,
  224. height: 450
  225. }
  226. listener = function (event) {
  227. assert.equal(event.data, 'size: ' + size.width + ' ' + size.height)
  228. b.close()
  229. done()
  230. }
  231. window.addEventListener('message', listener)
  232. b = window.open('file://' + fixtures + '/pages/window-open-size.html', '', 'show=no,width=' + size.width + ',height=' + size.height)
  233. })
  234. it('handles cycles when merging the parent options into the child options', (done) => {
  235. w = BrowserWindow.fromId(ipcRenderer.sendSync('create-window-with-options-cycle'))
  236. w.loadURL('file://' + fixtures + '/pages/window-open.html')
  237. w.webContents.once('new-window', (event, url, frameName, disposition, options) => {
  238. assert.equal(options.show, false)
  239. assert.deepEqual(options.foo, {
  240. bar: null,
  241. baz: {
  242. hello: {
  243. world: true
  244. }
  245. },
  246. baz2: {
  247. hello: {
  248. world: true
  249. }
  250. }
  251. })
  252. done()
  253. })
  254. })
  255. it('defines a window.location getter', function (done) {
  256. var b, targetURL
  257. if (process.platform === 'win32') {
  258. targetURL = 'file:///' + fixtures.replace(/\\/g, '/') + '/pages/base-page.html'
  259. } else {
  260. targetURL = 'file://' + fixtures + '/pages/base-page.html'
  261. }
  262. app.once('browser-window-created', (event, window) => {
  263. window.webContents.once('did-finish-load', () => {
  264. assert.equal(b.location, targetURL)
  265. b.close()
  266. done()
  267. })
  268. })
  269. b = window.open(targetURL)
  270. })
  271. it('defines a window.location setter', function (done) {
  272. let b
  273. app.once('browser-window-created', (event, {webContents}) => {
  274. webContents.once('did-finish-load', function () {
  275. // When it loads, redirect
  276. b.location = 'file://' + fixtures + '/pages/base-page.html'
  277. webContents.once('did-finish-load', function () {
  278. // After our second redirect, cleanup and callback
  279. b.close()
  280. done()
  281. })
  282. })
  283. })
  284. // Load a page that definitely won't redirect
  285. b = window.open('about:blank')
  286. })
  287. it('open a blank page when no URL is specified', function (done) {
  288. let b
  289. app.once('browser-window-created', (event, {webContents}) => {
  290. webContents.once('did-finish-load', function () {
  291. const {location} = b
  292. b.close()
  293. assert.equal(location, 'about:blank')
  294. let c
  295. app.once('browser-window-created', (event, {webContents}) => {
  296. webContents.once('did-finish-load', function () {
  297. const {location} = c
  298. c.close()
  299. assert.equal(location, 'about:blank')
  300. done()
  301. })
  302. })
  303. c = window.open('')
  304. })
  305. })
  306. b = window.open()
  307. })
  308. })
  309. describe('window.opener', function () {
  310. let url = 'file://' + fixtures + '/pages/window-opener.html'
  311. let w = null
  312. afterEach(function () {
  313. return closeWindow(w).then(function () { w = null })
  314. })
  315. it('is null for main window', function (done) {
  316. w = new BrowserWindow({
  317. show: false
  318. })
  319. w.webContents.once('ipc-message', function (event, args) {
  320. assert.deepEqual(args, ['opener', null])
  321. done()
  322. })
  323. w.loadURL(url)
  324. })
  325. it('is not null for window opened by window.open', function (done) {
  326. let b
  327. listener = function (event) {
  328. assert.equal(event.data, 'object')
  329. b.close()
  330. done()
  331. }
  332. window.addEventListener('message', listener)
  333. b = window.open(url, '', 'show=no')
  334. })
  335. })
  336. describe('window.opener access from BrowserWindow', function () {
  337. const scheme = 'other'
  338. let url = `${scheme}://${fixtures}/pages/window-opener-location.html`
  339. let w = null
  340. before(function (done) {
  341. protocol.registerFileProtocol(scheme, function (request, callback) {
  342. callback(`${fixtures}/pages/window-opener-location.html`)
  343. }, function (error) {
  344. done(error)
  345. })
  346. })
  347. after(function () {
  348. protocol.unregisterProtocol(scheme)
  349. })
  350. afterEach(function () {
  351. w.close()
  352. })
  353. it('does nothing when origin of current window does not match opener', function (done) {
  354. listener = function (event) {
  355. assert.equal(event.data, undefined)
  356. done()
  357. }
  358. window.addEventListener('message', listener)
  359. w = window.open(url, '', 'show=no')
  360. })
  361. it('works when origin matches', function (done) {
  362. listener = function (event) {
  363. assert.equal(event.data, location.href)
  364. done()
  365. }
  366. window.addEventListener('message', listener)
  367. w = window.open(`file://${fixtures}/pages/window-opener-location.html`, '', 'show=no')
  368. })
  369. it('works when origin does not match opener but has node integration', function (done) {
  370. listener = function (event) {
  371. assert.equal(event.data, location.href)
  372. done()
  373. }
  374. window.addEventListener('message', listener)
  375. w = window.open(url, '', 'show=no,nodeIntegration=yes')
  376. })
  377. })
  378. describe('window.opener access from <webview>', function () {
  379. const scheme = 'other'
  380. const srcPath = `${fixtures}/pages/webview-opener-postMessage.html`
  381. const pageURL = `file://${fixtures}/pages/window-opener-location.html`
  382. let webview = null
  383. before(function (done) {
  384. protocol.registerFileProtocol(scheme, function (request, callback) {
  385. callback(srcPath)
  386. }, function (error) {
  387. done(error)
  388. })
  389. })
  390. after(function () {
  391. protocol.unregisterProtocol(scheme)
  392. })
  393. afterEach(function () {
  394. if (webview != null) webview.remove()
  395. })
  396. it('does nothing when origin of webview src URL does not match opener', function (done) {
  397. webview = new WebView()
  398. webview.addEventListener('console-message', function (e) {
  399. assert.equal(e.message, 'null')
  400. done()
  401. })
  402. webview.setAttribute('allowpopups', 'on')
  403. webview.src = url.format({
  404. pathname: srcPath,
  405. protocol: scheme,
  406. query: {
  407. p: pageURL
  408. },
  409. slashes: true
  410. })
  411. document.body.appendChild(webview)
  412. })
  413. it('works when origin matches', function (done) {
  414. webview = new WebView()
  415. webview.addEventListener('console-message', function (e) {
  416. assert.equal(e.message, webview.src)
  417. done()
  418. })
  419. webview.setAttribute('allowpopups', 'on')
  420. webview.src = url.format({
  421. pathname: srcPath,
  422. protocol: 'file',
  423. query: {
  424. p: pageURL
  425. },
  426. slashes: true
  427. })
  428. document.body.appendChild(webview)
  429. })
  430. it('works when origin does not match opener but has node integration', function (done) {
  431. webview = new WebView()
  432. webview.addEventListener('console-message', function (e) {
  433. webview.remove()
  434. assert.equal(e.message, webview.src)
  435. done()
  436. })
  437. webview.setAttribute('allowpopups', 'on')
  438. webview.setAttribute('nodeintegration', 'on')
  439. webview.src = url.format({
  440. pathname: srcPath,
  441. protocol: scheme,
  442. query: {
  443. p: pageURL
  444. },
  445. slashes: true
  446. })
  447. document.body.appendChild(webview)
  448. })
  449. })
  450. describe('window.postMessage', function () {
  451. it('sets the source and origin correctly', function (done) {
  452. var b
  453. listener = function (event) {
  454. window.removeEventListener('message', listener)
  455. b.close()
  456. var message = JSON.parse(event.data)
  457. assert.equal(message.data, 'testing')
  458. assert.equal(message.origin, 'file://')
  459. assert.equal(message.sourceEqualsOpener, true)
  460. assert.equal(event.origin, 'file://')
  461. done()
  462. }
  463. window.addEventListener('message', listener)
  464. app.once('browser-window-created', (event, {webContents}) => {
  465. webContents.once('did-finish-load', function () {
  466. b.postMessage('testing', '*')
  467. })
  468. })
  469. b = window.open('file://' + fixtures + '/pages/window-open-postMessage.html', '', 'show=no')
  470. })
  471. })
  472. describe('window.opener.postMessage', function () {
  473. it('sets source and origin correctly', function (done) {
  474. var b
  475. listener = function (event) {
  476. window.removeEventListener('message', listener)
  477. b.close()
  478. assert.equal(event.source, b)
  479. assert.equal(event.origin, 'file://')
  480. done()
  481. }
  482. window.addEventListener('message', listener)
  483. b = window.open('file://' + fixtures + '/pages/window-opener-postMessage.html', '', 'show=no')
  484. })
  485. it('supports windows opened from a <webview>', function (done) {
  486. const webview = new WebView()
  487. webview.addEventListener('console-message', function (e) {
  488. webview.remove()
  489. assert.equal(e.message, 'message')
  490. done()
  491. })
  492. webview.allowpopups = true
  493. webview.src = url.format({
  494. pathname: `${fixtures}/pages/webview-opener-postMessage.html`,
  495. protocol: 'file',
  496. query: {
  497. p: `${fixtures}/pages/window-opener-postMessage.html`
  498. },
  499. slashes: true
  500. })
  501. document.body.appendChild(webview)
  502. })
  503. })
  504. describe('creating a Uint8Array under browser side', function () {
  505. it('does not crash', function () {
  506. var RUint8Array = remote.getGlobal('Uint8Array')
  507. var arr = new RUint8Array()
  508. assert(arr)
  509. })
  510. })
  511. describe('webgl', function () {
  512. if (isCI && process.platform === 'win32') {
  513. return
  514. }
  515. it('can be get as context in canvas', function () {
  516. if (process.platform === 'linux') return
  517. var webgl = document.createElement('canvas').getContext('webgl')
  518. assert.notEqual(webgl, null)
  519. })
  520. })
  521. describe('web workers', function () {
  522. it('Worker can work', function (done) {
  523. var worker = new Worker('../fixtures/workers/worker.js')
  524. var message = 'ping'
  525. worker.onmessage = function (event) {
  526. assert.equal(event.data, message)
  527. worker.terminate()
  528. done()
  529. }
  530. worker.postMessage(message)
  531. })
  532. it('SharedWorker can work', function (done) {
  533. var worker = new SharedWorker('../fixtures/workers/shared_worker.js')
  534. var message = 'ping'
  535. worker.port.onmessage = function (event) {
  536. assert.equal(event.data, message)
  537. done()
  538. }
  539. worker.port.postMessage(message)
  540. })
  541. })
  542. describe('iframe', function () {
  543. var iframe = null
  544. beforeEach(function () {
  545. iframe = document.createElement('iframe')
  546. })
  547. afterEach(function () {
  548. document.body.removeChild(iframe)
  549. })
  550. it('does not have node integration', function (done) {
  551. iframe.src = 'file://' + fixtures + '/pages/set-global.html'
  552. document.body.appendChild(iframe)
  553. iframe.onload = function () {
  554. assert.equal(iframe.contentWindow.test, 'undefined undefined undefined')
  555. done()
  556. }
  557. })
  558. })
  559. describe('storage', function () {
  560. it('requesting persitent quota works', function (done) {
  561. navigator.webkitPersistentStorage.requestQuota(1024 * 1024, function (grantedBytes) {
  562. assert.equal(grantedBytes, 1048576)
  563. done()
  564. })
  565. })
  566. describe('custom non standard schemes', function () {
  567. const protocolName = 'storage'
  568. let contents = null
  569. before(function (done) {
  570. const handler = function (request, callback) {
  571. let parsedUrl = url.parse(request.url)
  572. let filename
  573. switch (parsedUrl.pathname) {
  574. case '/localStorage' : filename = 'local_storage.html'; break
  575. case '/sessionStorage' : filename = 'session_storage.html'; break
  576. case '/WebSQL' : filename = 'web_sql.html'; break
  577. case '/indexedDB' : filename = 'indexed_db.html'; break
  578. case '/cookie' : filename = 'cookie.html'; break
  579. default : filename = ''
  580. }
  581. callback({path: fixtures + '/pages/storage/' + filename})
  582. }
  583. protocol.registerFileProtocol(protocolName, handler, function (error) {
  584. done(error)
  585. })
  586. })
  587. after(function (done) {
  588. protocol.unregisterProtocol(protocolName, () => done())
  589. })
  590. beforeEach(function () {
  591. contents = webContents.create({})
  592. })
  593. afterEach(function () {
  594. contents.destroy()
  595. contents = null
  596. })
  597. it('cannot access localStorage', function (done) {
  598. ipcMain.once('local-storage-response', function (event, error) {
  599. assert.equal(
  600. error,
  601. 'Failed to read the \'localStorage\' property from \'Window\': Access is denied for this document.')
  602. done()
  603. })
  604. contents.loadURL(protocolName + '://host/localStorage')
  605. })
  606. it('cannot access sessionStorage', function (done) {
  607. ipcMain.once('session-storage-response', function (event, error) {
  608. assert.equal(
  609. error,
  610. 'Failed to read the \'sessionStorage\' property from \'Window\': Access is denied for this document.')
  611. done()
  612. })
  613. contents.loadURL(protocolName + '://host/sessionStorage')
  614. })
  615. it('cannot access WebSQL database', function (done) {
  616. ipcMain.once('web-sql-response', function (event, error) {
  617. assert.equal(
  618. error,
  619. 'An attempt was made to break through the security policy of the user agent.')
  620. done()
  621. })
  622. contents.loadURL(protocolName + '://host/WebSQL')
  623. })
  624. it('cannot access indexedDB', function (done) {
  625. ipcMain.once('indexed-db-response', function (event, error) {
  626. assert.equal(error, 'The user denied permission to access the database.')
  627. done()
  628. })
  629. contents.loadURL(protocolName + '://host/indexedDB')
  630. })
  631. it('cannot access cookie', function (done) {
  632. ipcMain.once('cookie-response', function (event, cookie) {
  633. assert(!cookie)
  634. done()
  635. })
  636. contents.loadURL(protocolName + '://host/cookie')
  637. })
  638. })
  639. })
  640. describe('websockets', function () {
  641. var wss = null
  642. var server = null
  643. var WebSocketServer = ws.Server
  644. afterEach(function () {
  645. wss.close()
  646. server.close()
  647. })
  648. it('has user agent', function (done) {
  649. server = http.createServer()
  650. server.listen(0, '127.0.0.1', function () {
  651. var port = server.address().port
  652. wss = new WebSocketServer({
  653. server: server
  654. })
  655. wss.on('error', done)
  656. wss.on('connection', function (ws) {
  657. if (ws.upgradeReq.headers['user-agent']) {
  658. done()
  659. } else {
  660. done('user agent is empty')
  661. }
  662. })
  663. var socket = new WebSocket(`ws://127.0.0.1:${port}`)
  664. assert(socket)
  665. })
  666. })
  667. })
  668. describe('Promise', function () {
  669. it('resolves correctly in Node.js calls', function (done) {
  670. document.registerElement('x-element', {
  671. prototype: Object.create(HTMLElement.prototype, {
  672. createdCallback: {
  673. value: function () {}
  674. }
  675. })
  676. })
  677. setImmediate(function () {
  678. var called = false
  679. Promise.resolve().then(function () {
  680. done(called ? void 0 : new Error('wrong sequence'))
  681. })
  682. document.createElement('x-element')
  683. called = true
  684. })
  685. })
  686. it('resolves correctly in Electron calls', function (done) {
  687. document.registerElement('y-element', {
  688. prototype: Object.create(HTMLElement.prototype, {
  689. createdCallback: {
  690. value: function () {}
  691. }
  692. })
  693. })
  694. remote.getGlobal('setImmediate')(function () {
  695. var called = false
  696. Promise.resolve().then(function () {
  697. done(called ? void 0 : new Error('wrong sequence'))
  698. })
  699. document.createElement('y-element')
  700. called = true
  701. })
  702. })
  703. })
  704. describe('fetch', function () {
  705. it('does not crash', function (done) {
  706. const server = http.createServer(function (req, res) {
  707. res.end('test')
  708. server.close()
  709. })
  710. server.listen(0, '127.0.0.1', function () {
  711. const port = server.address().port
  712. fetch(`http://127.0.0.1:${port}`).then((res) => {
  713. return res.body.getReader()
  714. }).then((reader) => {
  715. reader.read().then((r) => {
  716. reader.cancel()
  717. done()
  718. })
  719. }).catch(function (e) {
  720. done(e)
  721. })
  722. })
  723. })
  724. })
  725. })