$30 off During Our Annual Pro Sale. View Details »

Mock Native API in your E2E test

November 06, 2017

Mock Native API in your E2E test

ElectronMeetup in Tokyo LT (https://connpass.com/event/69473/)

How to run spectron E2E test in case of using Native API in your specs.


November 06, 2017

More Decks by joe_re

Other Decks in Technology


  1. Mock Native API in your E2E test 2017/11/06 ElectronMeetup in

    Tokyo LT @joe_re
  2. Who am I? twitter: @joe_re github: @joe­re community: Nishinippori.rb, GraphQL

    Tokyo Organizer
  3. Book

  4. Applications CafePitch Markdown Driven PresentationTool Tubutler Simple and usefull Youtube

  5. Today, I talk about spectron E2E test in case of

    using 'Native API' in your spec.
  6. Spectron

  7. What is Spectron? E2E Testing tool for Electron appplication. You

    can call ElectronAPI in your spec via ChromeDriver and WebDriver.io.
  8. Example const app = new spectron.Application({ path: 'path/to/your/app' }); describe('application

    launch', function () { this.timeout(10000); beforeEach(function () { return app.start(); }); afterEach(function () { return app.stop(); }); it('shows an initial window', function () { return app.client.getWindowCount().then(function (count) { assert.equal(count, 1); }); }); });
  9. Strong Points You can access any DOM via Webdriver.io. You

    can call any Electron API in your spec. No need setup script.(use Chromium inside Electron) Support CI services.(Travis, AppVeyor, etc)
  10. DEMO

  11. Spectron is nice. But it can't access Native API. (latest

    v3.7.2) So it can't mock Menu, Dialog, etc modules... https://github.com/electron/spectron/issues/94
  12. This is simple solution, but ugly... if (process.env.NODE_ENV === "production")

    { // production code here } else { // test code here }
  13. I want to write a spec which doesn't affect production

  14. I created two modules to resolve it. spectron­fake­menu https://github.com/joe­re/spectron­fake­menu spectron­fake­dialog

  15. Usage spectron­fake­menu const Application = require('spectron').Application; const fakeMenu = require('spectron-fake-menu');

    const app = new Application({ path: electron, args: [ path.join(__dirname, '.') ] }); fakeMenu.apply(app); // apply fake menu await app.start(); fakeMenu.clickMenu('Config'); // 'Config' Menu click fakeMenu.clickMenu('File', 'CloseTab'); // File->CloseTab Menu click spectron­fake­dialog const Application = require('spectron').Application; const fakeDialog = require('spectron-fake-dialog'); const app = new Application({ path: electron, args: [ path.join(__dirname, '.') ] }); fakeDialog.apply(app); await app.start(); fakeDialog.mock([ { method: 'showOpenDialog', value: ['faked.txt'] } ])); // write your specs
  16. How do they work? Electron provides '­­require' option same as

    Node.js. It can preload a module before run main script. These modules inject extra IPC and provide API which call or mock Native API inside your specs.
  17. Rough image

  18. Implementation(spectron­fake­dialog) const path = require('path'); let _app = null; function

    apply(app) { _app = app; _app.args.unshift(path.join(__dirname, 'preload.js')); _app.args.unshift('--require'); return _app; } function mock(options) { return _app.electron.ipcRenderer.sendSync('SPECTRON_FAKE_DIALOG/SEND', options); } module.exports = { apply, mock };
  19. Implementation(spectron­fake­dialog) preload script const { dialog, ipcMain, BrowserWindow } =

    require('electron'); //... some logics for creating mocked function ... function fake(options) { options.forEach(v => { if (dialog[v.method]) { dialog[v.method] = mockFunction.bind(null, v.value); } else { throw new Error(`can't find ${v.method} on dialog module.`); } }); } ipcMain.on('SPECTRON_FAKE_DIALOG/SEND', (e, options) => { fake(options); e.returnValue = true; });
  20. Please use they if you'd like.

  21. Thank you for your attention!