api-debugger-spec.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { expect } from 'chai';
  2. import * as http from 'http';
  3. import * as path from 'path';
  4. import { AddressInfo } from 'net';
  5. import { BrowserWindow } from 'electron/main';
  6. import { closeAllWindows } from './window-helpers';
  7. import { emittedOnce, emittedUntil } from './events-helpers';
  8. describe('debugger module', () => {
  9. const fixtures = path.resolve(__dirname, '..', 'spec', 'fixtures');
  10. let w: BrowserWindow;
  11. beforeEach(() => {
  12. w = new BrowserWindow({
  13. show: false,
  14. width: 400,
  15. height: 400
  16. });
  17. });
  18. afterEach(closeAllWindows);
  19. describe('debugger.attach', () => {
  20. it('succeeds when devtools is already open', async () => {
  21. await w.webContents.loadURL('about:blank');
  22. w.webContents.openDevTools();
  23. w.webContents.debugger.attach();
  24. expect(w.webContents.debugger.isAttached()).to.be.true();
  25. });
  26. it('fails when protocol version is not supported', done => {
  27. try {
  28. w.webContents.debugger.attach('2.0');
  29. } catch (err) {
  30. expect(w.webContents.debugger.isAttached()).to.be.false();
  31. done();
  32. }
  33. });
  34. it('attaches when no protocol version is specified', async () => {
  35. w.webContents.debugger.attach();
  36. expect(w.webContents.debugger.isAttached()).to.be.true();
  37. });
  38. });
  39. describe('debugger.detach', () => {
  40. it('fires detach event', async () => {
  41. const detach = emittedOnce(w.webContents.debugger, 'detach');
  42. w.webContents.debugger.attach();
  43. w.webContents.debugger.detach();
  44. const [, reason] = await detach;
  45. expect(reason).to.equal('target closed');
  46. expect(w.webContents.debugger.isAttached()).to.be.false();
  47. });
  48. it('doesn\'t disconnect an active devtools session', async () => {
  49. w.webContents.loadURL('about:blank');
  50. const detach = emittedOnce(w.webContents.debugger, 'detach');
  51. w.webContents.debugger.attach();
  52. w.webContents.openDevTools();
  53. w.webContents.once('devtools-opened', () => {
  54. w.webContents.debugger.detach();
  55. });
  56. await detach;
  57. expect(w.webContents.debugger.isAttached()).to.be.false();
  58. expect((w as any).devToolsWebContents.isDestroyed()).to.be.false();
  59. });
  60. });
  61. describe('debugger.sendCommand', () => {
  62. let server: http.Server;
  63. afterEach(() => {
  64. if (server != null) {
  65. server.close();
  66. server = null as any;
  67. }
  68. });
  69. it('returns response', async () => {
  70. w.webContents.loadURL('about:blank');
  71. w.webContents.debugger.attach();
  72. const params = { expression: '4+2' };
  73. const res = await w.webContents.debugger.sendCommand('Runtime.evaluate', params);
  74. expect(res.wasThrown).to.be.undefined();
  75. expect(res.result.value).to.equal(6);
  76. w.webContents.debugger.detach();
  77. });
  78. it('returns response when devtools is opened', async () => {
  79. w.webContents.loadURL('about:blank');
  80. w.webContents.debugger.attach();
  81. const opened = emittedOnce(w.webContents, 'devtools-opened');
  82. w.webContents.openDevTools();
  83. await opened;
  84. const params = { expression: '4+2' };
  85. const res = await w.webContents.debugger.sendCommand('Runtime.evaluate', params);
  86. expect(res.wasThrown).to.be.undefined();
  87. expect(res.result.value).to.equal(6);
  88. w.webContents.debugger.detach();
  89. });
  90. it('fires message event', async () => {
  91. const url = process.platform !== 'win32'
  92. ? `file://${path.join(fixtures, 'pages', 'a.html')}`
  93. : `file:///${path.join(fixtures, 'pages', 'a.html').replace(/\\/g, '/')}`;
  94. w.webContents.loadURL(url);
  95. w.webContents.debugger.attach();
  96. const message = emittedUntil(w.webContents.debugger, 'message',
  97. (event: Electron.Event, method: string) => method === 'Console.messageAdded');
  98. w.webContents.debugger.sendCommand('Console.enable');
  99. const [,, params] = await message;
  100. w.webContents.debugger.detach();
  101. expect((params as any).message.level).to.equal('log');
  102. expect((params as any).message.url).to.equal(url);
  103. expect((params as any).message.text).to.equal('a');
  104. });
  105. it('returns error message when command fails', async () => {
  106. w.webContents.loadURL('about:blank');
  107. w.webContents.debugger.attach();
  108. const promise = w.webContents.debugger.sendCommand('Test');
  109. await expect(promise).to.be.eventually.rejectedWith(Error, "'Test' wasn't found");
  110. w.webContents.debugger.detach();
  111. });
  112. // TODO(deepak1556): Fix and enable with upgrade
  113. it.skip('handles valid unicode characters in message', (done) => {
  114. try {
  115. w.webContents.debugger.attach();
  116. } catch (err) {
  117. done(`unexpected error : ${err}`);
  118. }
  119. let requestId : number;
  120. w.webContents.debugger.on('message', (event, method, params) => {
  121. if (method === 'Network.responseReceived' &&
  122. params.response.url.startsWith('http://127.0.0.1')) {
  123. requestId = params.requestId;
  124. } else if (method === 'Network.loadingFinished' &&
  125. params.requestId === requestId) {
  126. w.webContents.debugger.sendCommand('Network.getResponseBody', {
  127. requestId: params.requestId
  128. }).then(data => {
  129. expect(data.body).to.equal('\u0024');
  130. done();
  131. }).catch(result => done(result));
  132. }
  133. });
  134. server = http.createServer((req, res) => {
  135. res.setHeader('Content-Type', 'text/plain; charset=utf-8');
  136. res.end('\u0024');
  137. });
  138. server.listen(0, '127.0.0.1', () => {
  139. w.webContents.debugger.sendCommand('Network.enable');
  140. w.loadURL(`http://127.0.0.1:${(server.address() as AddressInfo).port}`);
  141. });
  142. });
  143. it('does not crash for invalid unicode characters in message', (done) => {
  144. try {
  145. w.webContents.debugger.attach();
  146. } catch (err) {
  147. done(`unexpected error : ${err}`);
  148. }
  149. w.webContents.debugger.on('message', (event, method) => {
  150. // loadingFinished indicates that page has been loaded and it did not
  151. // crash because of invalid UTF-8 data
  152. if (method === 'Network.loadingFinished') {
  153. done();
  154. }
  155. });
  156. server = http.createServer((req, res) => {
  157. res.setHeader('Content-Type', 'text/plain; charset=utf-8');
  158. res.end('\uFFFF');
  159. });
  160. server.listen(0, '127.0.0.1', () => {
  161. w.webContents.debugger.sendCommand('Network.enable');
  162. w.loadURL(`http://127.0.0.1:${(server.address() as AddressInfo).port}`);
  163. });
  164. });
  165. it('uses empty sessionId by default', async () => {
  166. w.webContents.loadURL('about:blank');
  167. w.webContents.debugger.attach();
  168. const onMessage = emittedOnce(w.webContents.debugger, 'message');
  169. await w.webContents.debugger.sendCommand('Target.setDiscoverTargets', { discover: true });
  170. const [, method, params, sessionId] = await onMessage;
  171. expect(method).to.equal('Target.targetCreated');
  172. expect(params.targetInfo.targetId).to.not.be.empty();
  173. expect(sessionId).to.be.empty();
  174. w.webContents.debugger.detach();
  175. });
  176. it('creates unique session id for each target', (done) => {
  177. w.webContents.loadFile(path.join(__dirname, 'fixtures', 'sub-frames', 'debug-frames.html'));
  178. w.webContents.debugger.attach();
  179. let session: String;
  180. w.webContents.debugger.on('message', (event, ...args) => {
  181. const [method, params, sessionId] = args;
  182. if (method === 'Target.targetCreated') {
  183. w.webContents.debugger.sendCommand('Target.attachToTarget', { targetId: params.targetInfo.targetId, flatten: true }).then(result => {
  184. session = result.sessionId;
  185. w.webContents.debugger.sendCommand('Debugger.enable', {}, result.sessionId);
  186. });
  187. }
  188. if (method === 'Debugger.scriptParsed') {
  189. expect(sessionId).to.equal(session);
  190. w.webContents.debugger.detach();
  191. done();
  192. }
  193. });
  194. w.webContents.debugger.sendCommand('Target.setDiscoverTargets', { discover: true });
  195. });
  196. });
  197. });