From ab737a17b606d3986992077f3d10049afb52d52e Mon Sep 17 00:00:00 2001 From: HyunmoAhn Date: Wed, 23 Jan 2019 19:56:29 +0900 Subject: [PATCH] Config of End-to-End & Search window e2e test code (#164) * Refactor about constant of path * Config default setting information * Edit unit test config and repair unit test code * Fix title about page html * E2E configure using spectron with jest * Attach ipc handler to use e2e test Spectron doesn't support controll of electron window. So To use end to end test, Attach ipc handler on test environment. * Add E2E support module * Add window manager to control electron window on e2e environment * Add test manager to use convenience * Initial e2e code for search window * E2E test main feature of list on search window * E2E test feature of menu on search window * Fix unit-test snapshot code --- .babelrc | 1 + .eslintrc | 2 + app/config.js | 101 +++++ app/constants/path/index.js | 39 +- app/e2e-ipc-handler.js | 14 + app/main/controllers/search.js | 4 +- app/main/utils/__tests__/disk/getData.spec.js | 4 +- .../update/openUpdateProgress.spec.js | 11 +- .../__tests__/update/openUpdateWindow.spec.js | 11 +- .../utils/__tests__/widget/makeWidget.spec.js | 9 +- .../__tests__/window/openPreference.spec.js | 11 +- app/main/utils/disk/getData.js | 13 +- app/main/utils/disk/saveData.js | 4 +- app/main/utils/init.js | 5 + app/main/utils/menu/trayMenuBar.js | 14 +- app/main/utils/update/openUpdateProgress.js | 9 +- app/main/utils/update/openUpdateWindow.js | 9 +- app/main/utils/widget/makeWidget.js | 11 +- app/main/utils/window/openPreference.js | 9 +- .../__snapshots__/SearchMenu.spec.jsx.snap | 10 + .../search/components/SearchMenu/index.jsx | 5 + app/renderer/pages/search/search.html | 2 +- app/renderer/pages/widget/widget.html | 2 +- jest.config.js | 28 ++ jest.config.json | 28 -- jest.e2e.config.js | 22 ++ package.json | 13 +- test/__snapshots__/search.e2e.js.snap | 19 + test/config.js | 25 ++ test/search.e2e.js | 274 ++++++++++++++ test/testManager.js | 38 ++ test/windowManager.js | 20 + webpack.basic.config.js | 1 + yarn.lock | 348 +++++++++++++++++- 34 files changed, 950 insertions(+), 166 deletions(-) create mode 100644 app/config.js create mode 100644 app/e2e-ipc-handler.js create mode 100644 jest.config.js delete mode 100644 jest.config.json create mode 100644 jest.e2e.config.js create mode 100644 test/__snapshots__/search.e2e.js.snap create mode 100644 test/config.js create mode 100644 test/search.e2e.js create mode 100644 test/testManager.js create mode 100644 test/windowManager.js diff --git a/.babelrc b/.babelrc index ba98459a..437d120d 100644 --- a/.babelrc +++ b/.babelrc @@ -8,6 +8,7 @@ "alias": { "actions": "./app/actions", "assets": "./app/assets", + "config": "./app/config.js", "constants": "./app/constants", "components": "./app/components", "main": "./app/main", diff --git a/.eslintrc b/.eslintrc index 20bca57a..577df5b5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -21,6 +21,8 @@ "jsx-a11y/heading-has-content": 0, "react/jsx-one-expression-per-line": 0, "lines-between-class-members": 0, + "no-continue": 0, + "no-bitwise": 0 }, "parser": "babel-eslint", "globals": { diff --git a/app/config.js b/app/config.js new file mode 100644 index 00000000..1da4a421 --- /dev/null +++ b/app/config.js @@ -0,0 +1,101 @@ +import { app, remote } from 'electron'; +import path from 'path'; + +const BASIC_PATH = (app || remote.app).getPath('appData'); +const TEMP_DIR = process.platform === 'win32' ? 'C:\\Windows\\Temp' : '/tmp'; +const IS_TEST = process.env.NODE_ENV === 'test'; +const SETTING_FILE = 'store.json'; + +export const SETTING_FILE_PATH = !IS_TEST ? + path.join(BASIC_PATH, 'oh-my-desk', SETTING_FILE) : + path.join(TEMP_DIR, SETTING_FILE); + +const ROOT_PATH = path.resolve(__dirname, '..'); + +function getPagePath(target) { + const ENV = process.env.NODE_ENV; + const MIDDLE_PATH = ENV === 'development' ? + path.join('app', 'renderer', 'pages', target) : + path.join('build'); + + return `file://${path.join(ROOT_PATH, MIDDLE_PATH, `${target}.html`)}`; +} +export const WIDGET_PATH = getPagePath('widget'); +export const PREFERENCE_PATH = getPagePath('preference'); +export const SEARCH_PATH = getPagePath('search'); +export const UPDATE_WINDOW_PATH = getPagePath('UpdateWindow'); +export const UPDATE_PROGRESS_PATH = getPagePath('UpdateProgress'); + +export const TRAY_ICON_PATH = path.join(ROOT_PATH, 'app', 'assets', 'iconTemplate.png'); +export const LOGO_ICON_PATH = path.join(ROOT_PATH, 'app', 'assets', 'oh-my-desk-icon.png'); + +export const DEFAULT_SETTING = { + identification: { + widgetInfoById: { + 'fb07e56a-2ef3-4c3f-b7d4-3680a7173dd2': { + size: { + height: 787, + width: 750, + }, + isEditProgress: false, + isMakeProgress: false, + position: { + x: 360, + y: 83, + }, + createTime: '2018-11-13T04:10:58.640Z', + name: 'google', + isOnTop: false, + url: 'https://www.google.com/', + isOpen: true, + favorites: true, + userAgent: 'DESKTOP', + resentFocusTime: '2018-11-26T11:32:48.186Z', + id: 'fb07e56a-2ef3-4c3f-b7d4-3680a7173dd2', + reloadInterval: 5, + }, + 'e8581480-cd58-458a-a268-f9869fa5fcfc': { + size: { + height: 777, + width: 821, + }, + isEditProgress: false, + isMakeProgress: false, + position: { + x: 575, + y: 115, + }, + createTime: '2018-11-13T11:32:08.049Z', + name: 'trello', + isOnTop: false, + url: 'https://trello.com', + isOpen: false, + favorites: false, + userAgent: 'DESKTOP', + resentFocusTime: '2018-11-25T16:33:47.625Z', + id: 'e8581480-cd58-458a-a268-f9869fa5fcfc', + }, + 'd5db9663-4879-47ca-ab63-10cf74de2967': { + size: { + height: 600, + width: 500, + }, + isEditProgress: false, + isMakeProgress: false, + position: { + x: 600, + y: 99, + }, + createTime: '2018-11-25T16:34:16.673Z', + name: 'translator', + isOnTop: false, + url: 'https://translate.google.com/', + isOpen: false, + favorites: false, + userAgent: 'DESKTOP', + resentFocusTime: '2018-11-25T16:34:17.266Z', + id: 'd5db9663-4879-47ca-ab63-10cf74de2967', + }, + }, + }, +}; diff --git a/app/constants/path/index.js b/app/constants/path/index.js index c63570ac..8b967e20 100644 --- a/app/constants/path/index.js +++ b/app/constants/path/index.js @@ -1,45 +1,8 @@ -import { app, remote } from 'electron'; import path from 'path'; -/** - * Path for globally. - */ -export const CONFIG_PATH = (app || remote.app).getPath('appData'); -export const SETTING_FILE_NAME = '/oh-my-desk/store.json'; - -/** - * Path for main process. - */ - -function getPagePath(target) { - const rootPath = process.env.NODE_ENV === 'development' ? - path.resolve(__dirname, '../../..') : path.resolve(__dirname, '..'); - const projectPath = process.env.NODE_ENV === 'development' ? `app/renderer/pages/${target}` : 'build'; - const htmlPath = `${target}.html`; - - return path.join(rootPath, projectPath, htmlPath); -} - -export const WIDGET_PATH = getPagePath('widget'); -export const PREFERENCE_PATH = getPagePath('preference'); -export const SEARCH_PATH = getPagePath('search'); -export const UPDATE_WINDOW_PATH = getPagePath('UpdateWindow'); -export const UPDATE_PROGRESS_PATH = getPagePath('UpdateProgress'); - -function getAssetPath(image) { - const rootPath = process.env.NODE_ENV === 'development' ? - path.resolve(__dirname, '../../..') : path.resolve(__dirname, '..'); - const assetPath = 'app/assets'; - - return path.join(rootPath, assetPath, `${image}.png`); -} - -export const TRAY_ICON_PATH = getAssetPath('iconTemplate'); -export const LOGO_ICON_PATH = getAssetPath('oh-my-desk-icon'); - /** * Path for renderer process. */ const ROOT_PATH = process.env.NODE_ENV === 'development' ? // TODO find better method to get root path. path.resolve(__dirname, '../../../..') : path.resolve(__dirname, '..'); -export const PRELOAD_SCRIPT_PATH = path.join(ROOT_PATH, 'build/preloadScript.js'); +export const PRELOAD_SCRIPT_PATH = path.join(ROOT_PATH, 'build/preloadScript.js'); // eslint-disable-line diff --git a/app/e2e-ipc-handler.js b/app/e2e-ipc-handler.js new file mode 100644 index 00000000..651ae222 --- /dev/null +++ b/app/e2e-ipc-handler.js @@ -0,0 +1,14 @@ +import { ipcMain } from 'electron'; +import TrayMenuBar from 'main/utils/menu/trayMenuBar'; + +function e2eIpcHandler() { + ipcMain.on('search.window.open', () => { + TrayMenuBar.showWindow(); + }); + + ipcMain.on('search.window.close', () => { + TrayMenuBar.hideWindow(); + }); +} + +export default e2eIpcHandler; diff --git a/app/main/controllers/search.js b/app/main/controllers/search.js index 14888fb7..a584e9b6 100644 --- a/app/main/controllers/search.js +++ b/app/main/controllers/search.js @@ -1,7 +1,7 @@ import { app, dialog } from 'electron'; import * as TYPES from 'actions/constant/actionTypes'; import TrayBar from 'main/utils/menu/trayMenuBar'; -import * as PATH from 'constants/path'; +import { LOGO_ICON_PATH } from 'config'; import i18n from 'constants/i18n'; const searchController = (action) => { @@ -18,7 +18,7 @@ const searchController = (action) => { title: text.quit, message: text.quitMessage, buttons: [text.ok, text.cancel], - icon: PATH.LOGO_ICON_PATH, + icon: LOGO_ICON_PATH, }; dialog.showMessageBox(options, (index) => { const isYesBtn = index === 0; diff --git a/app/main/utils/__tests__/disk/getData.spec.js b/app/main/utils/__tests__/disk/getData.spec.js index 13415e3d..6f8b4e71 100644 --- a/app/main/utils/__tests__/disk/getData.spec.js +++ b/app/main/utils/__tests__/disk/getData.spec.js @@ -1,5 +1,5 @@ import fs from 'fs'; -import * as SETTING from 'constants/setting'; +import { DEFAULT_SETTING } from 'config'; import getData from 'main/utils/disk/getData'; jest.mock('fs'); @@ -22,6 +22,6 @@ describe('test getStoredDataInDisk', () => { const result = getData(); expect(fs.readFileSync).toHaveBeenCalledTimes(0); - expect(result).toEqual(JSON.parse(SETTING.defaultWidgets)); + expect(result).toEqual(DEFAULT_SETTING); }); }); diff --git a/app/main/utils/__tests__/update/openUpdateProgress.spec.js b/app/main/utils/__tests__/update/openUpdateProgress.spec.js index e8e3191e..293d479b 100644 --- a/app/main/utils/__tests__/update/openUpdateProgress.spec.js +++ b/app/main/utils/__tests__/update/openUpdateProgress.spec.js @@ -1,7 +1,6 @@ import { BrowserWindow } from 'electron'; import uuid from 'uuid'; -import url from 'url'; -import * as PATH from 'constants/path'; +import { UPDATE_PROGRESS_PATH } from 'config'; import store from 'store/storeMain'; import openUpdateProgress from 'main/utils/update/openUpdateProgress'; import { updateProgressWindowOpen, updateProgressWindowClose } from 'actions/update'; @@ -45,12 +44,6 @@ describe('test openUpdateProgress', () => { openUpdateProgress(); expect(mockWindow.loadURL).toHaveBeenCalledTimes(1); - expect(mockWindow.loadURL).toHaveBeenCalledWith( - url.format({ - pathname: PATH.UPDATE_PROGRESS_PATH, - protocol: 'file:', - slashes: true, - }), - ); + expect(mockWindow.loadURL).toHaveBeenCalledWith(UPDATE_PROGRESS_PATH); }); }); diff --git a/app/main/utils/__tests__/update/openUpdateWindow.spec.js b/app/main/utils/__tests__/update/openUpdateWindow.spec.js index 22e63818..82243c6c 100644 --- a/app/main/utils/__tests__/update/openUpdateWindow.spec.js +++ b/app/main/utils/__tests__/update/openUpdateWindow.spec.js @@ -1,6 +1,5 @@ import { BrowserWindow } from 'electron'; -import url from 'url'; -import * as PATH from 'constants/path'; +import { UPDATE_WINDOW_PATH } from 'config'; import openUpdateWindow from 'main/utils/update/openUpdateWindow'; describe('test openUpdateWindow', () => { @@ -15,12 +14,6 @@ describe('test openUpdateWindow', () => { openUpdateWindow(); expect(mockWindow.loadURL).toHaveBeenCalledTimes(1); - expect(mockWindow.loadURL).toHaveBeenCalledWith( - url.format({ - pathname: PATH.UPDATE_WINDOW_PATH, - protocol: 'file:', - slashes: true, - }), - ); + expect(mockWindow.loadURL).toHaveBeenCalledWith(UPDATE_WINDOW_PATH); }); }); diff --git a/app/main/utils/__tests__/widget/makeWidget.spec.js b/app/main/utils/__tests__/widget/makeWidget.spec.js index c7cf9d05..87839dec 100644 --- a/app/main/utils/__tests__/widget/makeWidget.spec.js +++ b/app/main/utils/__tests__/widget/makeWidget.spec.js @@ -3,7 +3,7 @@ import Immutable from 'immutable'; import * as actions from 'actions/widget'; import { BrowserWindow as MockBrowserWindow } from 'app/__mocks__/electron'; import storeMock from 'store/storeMain'; -import * as PATH from 'constants/path'; +import { WIDGET_PATH, LOGO_ICON_PATH } from 'config'; import * as updateWidgetContentBounds from 'main/utils/widget/updateWidgetContentBounds'; import makeWidget from 'main/utils/widget/makeWidget'; @@ -106,7 +106,7 @@ describe('test makeWidgetWindow', () => { title: 'Close Widget', message: 'Content of progress will be disappear. \nDo close making window?', buttons: ['Ok', 'Cancel'], - icon: PATH.LOGO_ICON_PATH, + icon: LOGO_ICON_PATH, }, expect.any(Function)); }); @@ -131,7 +131,7 @@ describe('test makeWidgetWindow', () => { title: 'Close Widget', message: 'Content of progress will be disappear. \nDo close making window?', buttons: ['Ok', 'Cancel'], - icon: PATH.LOGO_ICON_PATH, + icon: LOGO_ICON_PATH, }, expect.any(Function)); }); @@ -216,8 +216,7 @@ describe('test makeWidgetWindow', () => { it('when process.env.NODE_ENV === development', () => { makeWidget('mock-id', mockInfo); expect(mock.loadURL).toHaveBeenCalledTimes(1); - expect(mock.loadURL) - .toHaveBeenCalledWith(`file://${PATH.WIDGET_PATH}`); + expect(mock.loadURL).toHaveBeenCalledWith(WIDGET_PATH); }); // TODO test about process.env.NODE_ENV === 'production' diff --git a/app/main/utils/__tests__/window/openPreference.spec.js b/app/main/utils/__tests__/window/openPreference.spec.js index 28ab654b..77c4003f 100644 --- a/app/main/utils/__tests__/window/openPreference.spec.js +++ b/app/main/utils/__tests__/window/openPreference.spec.js @@ -1,9 +1,8 @@ import { BrowserWindow } from 'electron'; import Immutable from 'immutable'; import uuid from 'uuid'; -import url from 'url'; import store from 'store/storeMain'; -import * as PATH from 'constants/path'; +import { PREFERENCE_PATH } from 'config'; import openPreference from 'main/utils/window/openPreference'; import { openBrowserWindow } from 'actions/window'; import * as preferenceActions from 'actions/preference'; @@ -64,13 +63,7 @@ describe('test openPreference', () => { openPreference(); expect(mockWindow.loadURL).toHaveBeenCalledTimes(1); - expect(mockWindow.loadURL).toHaveBeenCalledWith( - url.format({ - pathname: PATH.PREFERENCE_PATH, - protocol: 'file:', - slashed: true, - }), - ); + expect(mockWindow.loadURL).toHaveBeenCalledWith(PREFERENCE_PATH); }); it('should call BrowserWindow.on', () => { diff --git a/app/main/utils/disk/getData.js b/app/main/utils/disk/getData.js index d7918a9d..163cd2e3 100644 --- a/app/main/utils/disk/getData.js +++ b/app/main/utils/disk/getData.js @@ -1,14 +1,15 @@ import fs from 'fs'; -import * as PATH from 'constants/path'; -import * as SETTING from 'constants/setting'; +import { + DEFAULT_SETTING, + SETTING_FILE_PATH, +} from 'config'; const getData = () => { - const STORED_PATH = `${PATH.CONFIG_PATH}/${PATH.SETTING_FILE_NAME}`; - if (!fs.existsSync(STORED_PATH)) { - return JSON.parse(SETTING.defaultWidgets); + if (!fs.existsSync(SETTING_FILE_PATH)) { + return DEFAULT_SETTING; } - const storedData = fs.readFileSync(STORED_PATH, { encoding: 'utf-8' }); + const storedData = fs.readFileSync(SETTING_FILE_PATH, { encoding: 'utf-8' }); return JSON.parse(storedData); }; diff --git a/app/main/utils/disk/saveData.js b/app/main/utils/disk/saveData.js index 04040b1a..8f67c507 100644 --- a/app/main/utils/disk/saveData.js +++ b/app/main/utils/disk/saveData.js @@ -1,11 +1,11 @@ import fs from 'fs'; -import * as PATH from 'constants/path'; +import { SETTING_FILE_PATH } from 'config'; import store from 'store/storeMain'; const saveData = () => { const data = store.getState().get('share'); - fs.writeFileSync(`${PATH.CONFIG_PATH}/${PATH.SETTING_FILE_NAME}`, JSON.stringify(data.toJS())); + fs.writeFileSync(SETTING_FILE_PATH, JSON.stringify(data.toJS())); }; export default saveData; diff --git a/app/main/utils/init.js b/app/main/utils/init.js index 4c18dd27..31b5d3a7 100644 --- a/app/main/utils/init.js +++ b/app/main/utils/init.js @@ -14,6 +14,7 @@ import { hotKeySearchWindowSelector } from 'store/reducers/share/config/selector import saveData from 'main/utils/disk/saveData'; import TrayMenuBar from 'main/utils/menu/trayMenuBar'; import { setInitialStore } from 'actions/setting'; +import e2eIpcHandler from '../../e2e-ipc-handler'; // save data about setting every 5 minutes. const SAVE_SETTING_INTERVAL = 300000; @@ -50,6 +51,10 @@ function init() { } store.dispatch(setInitialStore()); + + if (process.env.NODE_ENV === 'test') { + e2eIpcHandler(); + } } export default init; diff --git a/app/main/utils/menu/trayMenuBar.js b/app/main/utils/menu/trayMenuBar.js index 81da7121..dec57f39 100644 --- a/app/main/utils/menu/trayMenuBar.js +++ b/app/main/utils/menu/trayMenuBar.js @@ -1,22 +1,20 @@ import { app, globalShortcut, Menu } from 'electron'; import menuBar from 'menubar'; -import url from 'url'; import store from 'store/storeMain'; import { searchTrayClose, searchTrayOpen, } from 'actions/search'; -import * as PATH from 'constants/path'; +import { + SEARCH_PATH, + TRAY_ICON_PATH, +} from 'config'; import i18n from 'constants/i18n'; import openPreference from 'main/utils/window/openPreference'; const trayMenuBar = menuBar({ - icon: PATH.TRAY_ICON_PATH, - index: url.format({ - pathname: PATH.SEARCH_PATH, - protocol: 'file:', - slashes: true, - }), + icon: TRAY_ICON_PATH, + index: SEARCH_PATH, showDockIcon: true, tooltip: `oh-my-desk ${app.getVersion()}`, fullscreenable: false, diff --git a/app/main/utils/update/openUpdateProgress.js b/app/main/utils/update/openUpdateProgress.js index e7bcb7af..c56edd78 100644 --- a/app/main/utils/update/openUpdateProgress.js +++ b/app/main/utils/update/openUpdateProgress.js @@ -1,8 +1,7 @@ import { BrowserWindow } from 'electron'; -import url from 'url'; import { v4 } from 'uuid'; import store from 'store/storeMain'; -import * as PATH from 'constants/path'; +import { UPDATE_PROGRESS_PATH } from 'config'; import { updateProgressWindowOpen, updateProgressWindowClose, @@ -26,11 +25,7 @@ const openUpdateWindow = () => { store.dispatch(updateProgressWindowOpen(id, updateWindow)); - updateWindow.loadURL(url.format({ - pathname: PATH.UPDATE_PROGRESS_PATH, - protocol: 'file:', - slashes: true, - })); + updateWindow.loadURL(UPDATE_PROGRESS_PATH); }; export default openUpdateWindow; diff --git a/app/main/utils/update/openUpdateWindow.js b/app/main/utils/update/openUpdateWindow.js index fd5d1693..aaeb11a2 100644 --- a/app/main/utils/update/openUpdateWindow.js +++ b/app/main/utils/update/openUpdateWindow.js @@ -1,6 +1,5 @@ import { BrowserWindow } from 'electron'; -import url from 'url'; -import * as PATH from 'constants/path'; +import { UPDATE_WINDOW_PATH } from 'config'; const openUpdateWindow = () => { const updateWindow = new BrowserWindow({ @@ -13,11 +12,7 @@ const openUpdateWindow = () => { }, }); - updateWindow.loadURL(url.format({ - pathname: PATH.UPDATE_WINDOW_PATH, - protocol: 'file:', - slashes: true, - })); + updateWindow.loadURL(UPDATE_WINDOW_PATH); }; export default openUpdateWindow; diff --git a/app/main/utils/widget/makeWidget.js b/app/main/utils/widget/makeWidget.js index d0cd5c5b..a5d0f5f2 100644 --- a/app/main/utils/widget/makeWidget.js +++ b/app/main/utils/widget/makeWidget.js @@ -1,11 +1,10 @@ import { BrowserWindow, dialog } from 'electron'; -import url from 'url'; import * as actions from 'actions/widget'; import { widgetInfoByIdSelector } from 'store/reducers/share/identification/selectors'; import store from 'store/storeMain'; import createWidget from 'main/utils/widget/createWidget'; import updateWidgetContentBounds from 'main/utils/widget/updateWidgetContentBounds'; -import * as PATH from 'constants/path'; +import { WIDGET_PATH, LOGO_ICON_PATH } from 'config'; import i18n from 'constants/i18n'; const makeWidget = (id, info, isFocus) => { @@ -26,11 +25,7 @@ const makeWidget = (id, info, isFocus) => { minHeight: 300, }); - widget.loadURL(url.format({ - pathname: PATH.WIDGET_PATH, - protocol: 'file:', - slashes: true, - })); + widget.loadURL(WIDGET_PATH); widget.once('ready-to-show', () => { if (isFocus) { @@ -67,7 +62,7 @@ const makeWidget = (id, info, isFocus) => { title: text.closeWidget, message: text.closeMessage(targetInfo.get('name')), buttons: [text.ok, text.cancel], - icon: PATH.LOGO_ICON_PATH, + icon: LOGO_ICON_PATH, }; dialog.showMessageBox(options, (index) => { if (index === 0) { // when click Yes button diff --git a/app/main/utils/window/openPreference.js b/app/main/utils/window/openPreference.js index 3499f916..e7e44f16 100644 --- a/app/main/utils/window/openPreference.js +++ b/app/main/utils/window/openPreference.js @@ -1,12 +1,11 @@ import { BrowserWindow } from 'electron'; import { v4 } from 'uuid'; -import url from 'url'; import store from 'store/storeMain'; import * as identificationSelector from 'store/reducers/share/identification/selectors'; import * as identification from 'store/reducers/personal/identification/selectors'; import { openBrowserWindow } from 'actions/window'; import * as preferenceAction from 'actions/preference'; -import * as PATH from 'constants/path'; +import { PREFERENCE_PATH } from 'config'; const openPreference = () => { const winId = identificationSelector.preferenceSelector(store.getState()); @@ -29,11 +28,7 @@ const openPreference = () => { }, }); - winPreference.loadURL(url.format({ - pathname: PATH.PREFERENCE_PATH, - protocol: 'file:', - slashes: true, - })); + winPreference.loadURL(PREFERENCE_PATH); if (process.env.NODE_ENV === 'development') { winPreference.webContents.openDevTools(); diff --git a/app/renderer/pages/search/components/SearchMenu/__snapshots__/SearchMenu.spec.jsx.snap b/app/renderer/pages/search/components/SearchMenu/__snapshots__/SearchMenu.spec.jsx.snap index bf60e920..a8a08a3b 100644 --- a/app/renderer/pages/search/components/SearchMenu/__snapshots__/SearchMenu.spec.jsx.snap +++ b/app/renderer/pages/search/components/SearchMenu/__snapshots__/SearchMenu.spec.jsx.snap @@ -17,6 +17,7 @@ exports[`Test SearchMenu Component should match to snapshot 1`] = ` > + +`; diff --git a/test/config.js b/test/config.js new file mode 100644 index 00000000..0534e775 --- /dev/null +++ b/test/config.js @@ -0,0 +1,25 @@ +/* eslint-disable no-console */ +import path from 'path'; +import { Application } from 'spectron'; +import { sync as rimraf } from 'rimraf'; + +const TEMP_DIR = process.platform === 'win32' ? 'C:\\Windows\\Temp' : '/tmp'; +const SETTING_FILE = 'store.json'; + +export const TEST_SETTING_PATH = path.join(TEMP_DIR, SETTING_FILE); + +export function createApp() { + return new Application({ + path: path.join(__dirname, '..', 'node_modules', '.bin', + `electron${process.platform === 'win32' ? '.cmd' : ''}`), + args: ['-r', '@babel/register', path.join(__dirname, '..', 'app', 'main.js')], + env: { + NODE_ENV: 'test', + }, + waitTimeout: 10e3, + }); +} + +export function resetConfigFile() { + rimraf(TEST_SETTING_PATH); +} diff --git a/test/search.e2e.js b/test/search.e2e.js new file mode 100644 index 00000000..3a5f6388 --- /dev/null +++ b/test/search.e2e.js @@ -0,0 +1,274 @@ +import testManager from './testManager'; +import windowManager from './windowManager'; +import * as config from './config'; + +jest.setTimeout(30000); +describe('test search window feature of list', async () => { + const app = config.createApp(); + const browser = windowManager(app); + const test = testManager(app); + + beforeAll(async () => { + config.resetConfigFile(); + await app.start(); + }); + afterAll(async () => { + await app.stop(); + config.resetConfigFile(); + }); + + beforeEach(async () => { + await app.client.waitUntilWindowLoaded(); + }); + + it('start initial app', async () => { + await test.matchWindowCount(2); + await test.matchWindowTitle('oh-my-desk widget'); + }); + + it('open search window and focus', async () => { + await browser.searchWindowOpen(); + await test.matchWindowCount(3); + await app.client.windowByIndex(2); + await test.matchWindowTitle('oh-my-desk search'); + await test.matchValue('.SearchInput__input', ''); + }); + + it('assert default widget list', async () => { + const container = await test.getElement('.SearchList'); + const list = container.querySelectorAll('.SearchItem'); + const expectText = ['google', 'translator', 'trello']; + + list.forEach((item, index) => { + expect(item.querySelector('strong').textContent) + .toBe(expectText[index]); + }); + }); + + it('type search input', async () => { + await test.matchValue('.SearchInput__input', ''); + await app.client.keys('trans'); + await test.matchValue('.SearchInput__input', 'trans'); + }); + + it('assert searched widget list', async () => { + const container = await test.getElement('.SearchList'); + const list = container.querySelectorAll('.SearchItem'); + expect(list.length).toBe(1); + expect(list[0].querySelector('strong').textContent) + .toBe('translator'); + }); + + it('open widget using enter key', async () => { + await app.client.keys('Enter'); + expect(await app.browserWindow.isVisible()).toBe(false); + await app.client.pause(1000); + await app.client.windowByIndex(4); + await test.matchWindowCount(5); + await test.matchWindowTitle('oh-my-desk widget'); + await test.matchText('.TitleBar__title', 'translator'); + }); + + it('close widget using toggle btn', async () => { + await browser.searchWindowOpen(); + await app.client.windowByIndex(2); + await test.matchWindowTitle('oh-my-desk search'); + await test.matchValue('.SearchInput__input', ''); + expect(await app.browserWindow.isVisible()).toBe(true); + + let btn = await test.getElement('.ToggleButton__wrapper', 0); + expect(btn.classList.contains('ToggleButton__wrapper-active')) + .toBe(true); + + await app.client.click('.SearchItem__toggle-btn'); + await test.matchWindowCount(3); + + btn = await test.getElement('.ToggleButton__wrapper', 0); + expect(btn.classList.contains('ToggleButton__wrapper-active')) + .toBe(false); + }); + + it('open widget using toggle btn', async () => { + await app.client.click('.SearchItem__toggle-btn'); + await app.client.pause(1000); + await test.matchWindowCount(5); + + const btn = await test.getElement('.ToggleButton__wrapper', 0); + expect(btn.classList.contains('ToggleButton__wrapper-active')) + .toBe(true); + }); + + describe('change selected list of widget', async () => { + describe('test of arrow down', () => { + it('test first to second list', async () => { + await app.client.keys('ArrowDown'); + + const container = await test.getElement('.SearchList'); + const btn = container.querySelectorAll('.SearchItem'); + expect(btn[0].classList.contains('SearchItem__select')) + .toBe(false); + expect(btn[1].classList.contains('SearchItem__select')) + .toBe(true); + }); + + it('test second to third list', async () => { + await app.client.keys('ArrowDown'); + + const container = await test.getElement('.SearchList'); + const btn = container.querySelectorAll('.SearchItem'); + expect(btn[1].classList.contains('SearchItem__select')) + .toBe(false); + expect(btn[2].classList.contains('SearchItem__select')) + .toBe(true); + }); + + it('test third to first list', async () => { + await app.client.keys('ArrowDown'); + + const container = await test.getElement('.SearchList'); + const btn = container.querySelectorAll('.SearchItem'); + expect(btn[2].classList.contains('SearchItem__select')) + .toBe(false); + expect(btn[0].classList.contains('SearchItem__select')) + .toBe(true); + }); + }); + + describe('test of arrow up', () => { + it('test first to third list', async () => { + await app.client.keys('ArrowUp'); + + const container = await test.getElement('.SearchList'); + const btn = container.querySelectorAll('.SearchItem'); + expect(btn[0].classList.contains('SearchItem__select')) + .toBe(false); + expect(btn[2].classList.contains('SearchItem__select')) + .toBe(true); + }); + + it('test third to second list', async () => { + await app.client.keys('ArrowUp'); + + const container = await test.getElement('.SearchList'); + const btn = container.querySelectorAll('.SearchItem'); + expect(btn[2].classList.contains('SearchItem__select')) + .toBe(false); + expect(btn[1].classList.contains('SearchItem__select')) + .toBe(true); + }); + + it('test second to first list', async () => { + await app.client.keys('ArrowUp'); + + const container = await test.getElement('.SearchList'); + const btn = container.querySelectorAll('.SearchItem'); + expect(btn[1].classList.contains('SearchItem__select')) + .toBe(false); + expect(btn[0].classList.contains('SearchItem__select')) + .toBe(true); + }); + }); + + describe('open widget to type enter except first list', () => { + it('focus second widget of list', async () => { + await app.client.keys('ArrowDown'); + await app.client.keys('Enter'); + expect(await app.browserWindow.isVisible()).toBe(false); + await app.client.windowByIndex(0); + expect(await app.browserWindow.isFocused()).toBe(true); + }); + + it('open third widget of list', async () => { + await browser.searchWindowOpen(); + await app.client.windowByIndex(2); + await app.client.keys('ArrowDown'); + await app.client.keys('Enter'); + await app.client.pause(1000); + expect(await app.browserWindow.isVisible()).toBe(false); + await test.matchWindowCount(7); + await app.client.windowByIndex(6); + await test.matchWindowTitle('oh-my-desk widget'); + expect(await app.browserWindow.isFocused()).toBe(true); + await test.matchText('.TitleBar__title', 'trello'); + }); + }); + }); +}); + +describe('test search window feature of menu', () => { + const app = config.createApp(); + const browser = windowManager(app); + const test = testManager(app); + + beforeAll(async () => { + config.resetConfigFile(); + await app.start(); + }); + afterAll(async () => { + await app.stop(); + config.resetConfigFile(); + }); + + beforeEach(async () => { + await app.client.waitUntilWindowLoaded(); + }); + + it('open new widget window', async () => { + await browser.searchWindowOpen(); + await app.client.windowByIndex(1); + await test.matchWindowTitle('oh-my-desk search'); + await app.client.click('[data-test-id="menu-new-widget"]'); + await app.client.pause(1000); + + await test.matchWindowCount(5); + + await app.client.windowByIndex(4); + await test.matchWindowTitle('oh-my-desk widget'); + await test.matchText('.TitleBar__title', 'Empty Widget'); + const notice = await test.getElement('.MakeNotice__bar'); + + expect(notice).toMatchSnapshot(); + }); + + it('open preference window', async () => { + await browser.searchWindowOpen(); + await app.client.windowByIndex(1); + await test.matchWindowTitle('oh-my-desk search'); + await app.client.click('[data-test-id="menu-setting"]'); + await test.matchWindowCount(6); + + await app.client.windowByIndex(5); + await test.matchWindowTitle('oh-my-desk preference'); + }); + + describe('toggle visibility type of widget list', () => { + it('should set default to favorites', async () => { + await browser.searchWindowOpen(); + await app.client.windowByIndex(1); + await test.matchWindowTitle('oh-my-desk search'); + await app.client.click('[data-test-id="menu-favorites"]'); + + const container = await test.getElement('.SearchList'); + const list = container.querySelectorAll('.SearchItem'); + const expectText = ['google']; + + list.forEach((item, index) => { + expect(item.querySelector('strong').textContent) + .toBe(expectText[index]); + }); + }); + + it('should set favorites to default', async () => { + await app.client.click('[data-test-id="menu-all"]'); + + const container = await test.getElement('.SearchList'); + const list = container.querySelectorAll('.SearchItem'); + const expectText = ['google', 'translator', 'trello']; + + list.forEach((item, index) => { + expect(item.querySelector('strong').textContent) + .toBe(expectText[index]); + }); + }); + }); +}); diff --git a/test/testManager.js b/test/testManager.js new file mode 100644 index 00000000..397c9c60 --- /dev/null +++ b/test/testManager.js @@ -0,0 +1,38 @@ +const testManager = app => ({ + matchWindowCount: async (expectNumber) => { + const count = await app.client.getWindowCount(); + + expect(count).toBe(expectNumber); + }, + matchWindowTitle: async (expectTitle) => { + const windowTitle = await app.client.getTitle(); + + expect(windowTitle).toBe(expectTitle); + }, + matchValue: async (selector, expectValue) => { + const value = await app.client.getValue(selector); + + expect(value).toBe(expectValue); + }, + matchText: async (selector, expectText) => { + const value = await app.client.getText(selector); + + expect(value).toBe(expectText); + }, + getElement: async (selector, index) => { + const container = document.createElement('div'); + let html = await app.client.getHTML(selector); + + if (typeof html !== 'string') { + html = html[index]; + } + + container.innerHTML = html; + + const selected = container.querySelector(selector); + + return selected; + }, +}); + +export default testManager; diff --git a/test/windowManager.js b/test/windowManager.js new file mode 100644 index 00000000..cd433ab2 --- /dev/null +++ b/test/windowManager.js @@ -0,0 +1,20 @@ +const windowManager = app => ({ + searchWindowOpen: async () => { + await app.webContents.executeJavaScript(` + const { ipcRenderer } = require('electron'); + `); + await app.webContents.executeJavaScript(` + ipcRenderer.send('search.window.open'); + `); + }, + searchWindowClose: async () => { + await app.webContents.executeJavaScript(` + const { ipcRenderer } = require('electron'); + `); + await app.webContents.executeJavaScript(` + ipcRenderer.send('search.window.close'); + `); + }, +}); + +export default windowManager; diff --git a/webpack.basic.config.js b/webpack.basic.config.js index 9dbe3c92..30b75fe5 100644 --- a/webpack.basic.config.js +++ b/webpack.basic.config.js @@ -101,6 +101,7 @@ module.exports = { alias: { actions: path.resolve(__dirname, 'app/actions'), assets: path.resolve(__dirname, 'app/assets'), + config: path.resolve(__dirname, 'app/config.js'), constants: path.resolve(__dirname, 'app/constants'), components: path.resolve(__dirname, 'app/components'), main: path.resolve(__dirname, 'app/main'), diff --git a/yarn.lock b/yarn.lock index 854baced..92cd41a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1027,6 +1027,32 @@ aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" +archiver-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174" + integrity sha1-5QtMCccL89aA4y/xt5lOn52JUXQ= + dependencies: + glob "^7.0.0" + graceful-fs "^4.1.0" + lazystream "^1.0.0" + lodash "^4.8.0" + normalize-path "^2.0.0" + readable-stream "^2.0.0" + +archiver@~2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-2.1.1.tgz#ff662b4a78201494a3ee544d3a33fe7496509ebc" + integrity sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw= + dependencies: + archiver-utils "^1.3.0" + async "^2.0.0" + buffer-crc32 "^0.2.1" + glob "^7.0.0" + lodash "^4.8.0" + readable-stream "^2.0.0" + tar-stream "^1.5.0" + zip-stream "^1.2.0" + are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" @@ -1178,7 +1204,7 @@ async@^1.4.0, async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.1.4: +async@^2.0.0, async@^2.1.4: version "2.6.1" resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" dependencies: @@ -1467,6 +1493,14 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -1659,6 +1693,11 @@ buffer-alloc@^1.2.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" +buffer-crc32@^0.2.1: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + buffer-fill@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" @@ -1683,6 +1722,14 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" + integrity sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + builder-util-runtime@4.4.1, builder-util-runtime@^4.4.1, builder-util-runtime@~4.4.1: version "4.4.1" resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-4.4.1.tgz#2770d03241e51fde46acacc7ed3ed8a9f45f02cb" @@ -2119,6 +2166,16 @@ component-emitter@1.2.1, component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" +compress-commons@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f" + integrity sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8= + dependencies: + buffer-crc32 "^0.2.1" + crc32-stream "^2.0.0" + normalize-path "^2.0.0" + readable-stream "^2.0.0" + compressible@~2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.14.tgz#326c5f507fbb055f54116782b969a81b67a29da7" @@ -2260,6 +2317,21 @@ coveralls@^3.0.1: minimist "^1.2.0" request "^2.85.0" +crc32-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" + integrity sha1-483TtN8xaN10494/u8t7KX/pCPQ= + dependencies: + crc "^3.4.4" + readable-stream "^2.0.0" + +crc@^3.4.4: + version "3.8.0" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" + integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ== + dependencies: + buffer "^5.1.0" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -2369,6 +2441,13 @@ css-loader@^0.28.11: postcss-value-parser "^3.3.0" source-list-map "^2.0.0" +css-parse@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" + integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q= + dependencies: + css "^2.0.0" + css-select@^1.1.0, css-select@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" @@ -2386,6 +2465,11 @@ css-selector-tokenizer@^0.7.0: fastparse "^1.1.1" regexpu-core "^1.0.0" +css-value@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea" + integrity sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo= + css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" @@ -2505,6 +2589,13 @@ debug@=3.1.0, debug@^3.0.1, debug@^3.1.0: dependencies: ms "2.0.0" +debug@^3.0.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + debug@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" @@ -2542,6 +2633,11 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +deepmerge@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.0.1.tgz#25c1c24f110fb914f80001b925264dd77f3f4312" + integrity sha512-VIPwiMJqJ13ZQfaCsIFnp5Me9tnjURiaIFxfz7EH0Ci0dTSQpZtSLrqOicXqEd/z2r+z+Klk9GzmnRsgpgbOsQ== + default-require-extensions@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7" @@ -2645,6 +2741,11 @@ detect-node@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.3.tgz#a2033c09cc8e158d37748fbde7507832bd6ce127" +dev-null@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dev-null/-/dev-null-0.1.1.tgz#5a205ce3c2b2ef77b6238d6ba179eb74c6a0e818" + integrity sha1-WiBc48Ky73e2I41roXnrdMag6Bg= + diff@^3.2.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -2813,6 +2914,11 @@ ejs@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" +ejs@~2.5.6: + version "2.5.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" + integrity sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ== + electron-builder-http@^19.27.5: version "19.27.5" resolved "https://registry.yarnpkg.com/electron-builder-http/-/electron-builder-http-19.27.5.tgz#800865df2e618ffab9e5b3b895c15b4ce7fd7f17" @@ -2839,6 +2945,14 @@ electron-builder@^20.17.0: update-notifier "^2.5.0" yargs "^12.0.1" +electron-chromedriver@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-3.0.0.tgz#ec0a17badb6c3529813c660bf91a43fb91407674" + integrity sha512-xWivZRiPTtDFJt+qXv7Ax/Dmhxj0iqESOxoLZ2szu3fv6k1vYDUDJUMHfdfVAke9D2gBRIgChuGb5j3YEt6hxQ== + dependencies: + electron-download "^4.1.0" + extract-zip "^1.6.5" + electron-download@^3.0.1: version "3.3.0" resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-3.3.0.tgz#2cfd54d6966c019c4d49ad65fbe65cc9cdef68c8" @@ -2853,6 +2967,21 @@ electron-download@^3.0.1: semver "^5.3.0" sumchecker "^1.2.0" +electron-download@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.1.tgz#02e69556705cc456e520f9e035556ed5a015ebe8" + integrity sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg== + dependencies: + debug "^3.0.0" + env-paths "^1.0.0" + fs-extra "^4.0.1" + minimist "^1.2.0" + nugget "^2.0.1" + path-exists "^3.0.0" + rc "^1.2.1" + semver "^5.4.1" + sumchecker "^2.0.2" + electron-is-dev@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/electron-is-dev/-/electron-is-dev-0.3.0.tgz#14e6fda5c68e9e4ecbeff9ccf037cbd7c05c5afe" @@ -2976,6 +3105,11 @@ entities@^1.1.1, entities@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" +env-paths@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0" + integrity sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA= + enzyme-adapter-react-16@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.3.0.tgz#4cfba44f8c27256d28e171bdf7a5b5aebce6041b" @@ -3436,7 +3570,7 @@ extend@~3.0.1, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" -external-editor@^2.1.0: +external-editor@^2.0.4, external-editor@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" dependencies: @@ -3471,7 +3605,7 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-zip@^1.0.3: +extract-zip@^1.0.3, extract-zip@^1.6.5: version "1.6.7" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" dependencies: @@ -3754,6 +3888,11 @@ from@~0: version "0.1.7" resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-extra-p@^4.4.0, fs-extra-p@^4.6.1: version "4.6.1" resolved "https://registry.yarnpkg.com/fs-extra-p/-/fs-extra-p-4.6.1.tgz#6156e0cc98097f415fcd17029578fc41c78b5092" @@ -3771,6 +3910,15 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-extra@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" @@ -3843,7 +3991,7 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gaze@^1.0.0: +gaze@^1.0.0, gaze@~1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" dependencies: @@ -3899,7 +4047,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" dependencies: @@ -3978,10 +4126,20 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" +graceful-fs@^4.1.0: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" +grapheme-splitter@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + "growl@~> 1.10.0": version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" @@ -4032,6 +4190,11 @@ has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -4411,6 +4574,26 @@ inquirer@^6.0.0: strip-ansi "^4.0.0" through "^2.3.6" +inquirer@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + internal-ip@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c" @@ -5355,6 +5538,13 @@ lazy-val@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.3.tgz#bb97b200ef00801d94c317e29dc6ed39e31c5edc" +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= + dependencies: + readable-stream "^2.0.5" + lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" @@ -5653,6 +5843,11 @@ lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.3, version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" +lodash@^4.8.0: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + log-driver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" @@ -6250,7 +6445,7 @@ normalize-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" -normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: @@ -6277,6 +6472,11 @@ npm-bundled@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.5.tgz#3c1732b7ba936b3a10325aef616467c0ccbcc979" +npm-install-package@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/npm-install-package/-/npm-install-package-2.1.0.tgz#d7efe3cfcd7ab00614b896ea53119dc9ab259125" + integrity sha1-1+/jz816sAYUuJbqUxGdyaslkSU= + npm-packlist@^1.1.6: version "1.1.11" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.11.tgz#84e8c683cbe7867d34b1d357d893ce29e28a02de" @@ -6324,7 +6524,7 @@ nth-check@~1.0.1: dependencies: boolbase "~1.0.0" -nugget@^2.0.0: +nugget@^2.0.0, nugget@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" dependencies: @@ -6481,7 +6681,7 @@ opn@^5.1.0: dependencies: is-wsl "^1.1.0" -optimist@^0.6.1: +optimist@^0.6.1, optimist@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: @@ -7238,7 +7438,7 @@ punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" -q@^1.1.2: +q@^1.1.2, q@~1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" @@ -7320,7 +7520,7 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" -rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.2.7: +rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.2.1, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" dependencies: @@ -7452,7 +7652,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3, readable-stream@^2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -7761,7 +7961,7 @@ request@2.87.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@^2.45.0, request@^2.85.0, request@^2.87.0: +request@^2.45.0, request@^2.83.0, request@^2.85.0, request@^2.87.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" dependencies: @@ -7884,6 +8084,11 @@ rework@^1.0.1: convert-source-map "^0.3.3" css "^2.0.0" +rgb2hex@^0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.1.9.tgz#5d3e0e14b0177b568e6f0d5b43e34fbfdb670346" + integrity sha512-32iuQzhOjyT+cv9aAFRBJ19JgHwzQwbjUhH3Fj2sWW2EEGAW8fpFrDFP5ndoKDxJaLO06x1hE3kyuIFrUQtybQ== + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -7896,6 +8101,13 @@ rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: dependencies: glob "^7.0.5" +rimraf@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -7930,6 +8142,18 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= + rxjs@^5.5.2: version "5.5.11" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.11.tgz#f733027ca43e3bec6b994473be4ab98ad43ced87" @@ -8384,6 +8608,17 @@ spdy@^3.4.1: select-hose "^2.0.0" spdy-transport "^2.0.18" +spectron@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/spectron/-/spectron-5.0.0.tgz#602440da0c892f8d73471652ae68000b98d7769c" + integrity sha512-wJrFe8EZ7xvarYawBPd1pDegmSz81U1jG0rSCx+yXqD1TISUH9ASB21KysLXkPylAnc2vhbpGiWQxrqVFtsiJg== + dependencies: + dev-null "^0.1.1" + electron-chromedriver "~3.0.0" + request "^2.87.0" + split "^1.0.0" + webdriverio "^4.13.0" + speedometer@~0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" @@ -8400,6 +8635,13 @@ split@0.3: dependencies: through "2" +split@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -8598,6 +8840,13 @@ sumchecker@^1.2.0: debug "^2.2.0" es6-promise "^4.0.5" +sumchecker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e" + integrity sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4= + dependencies: + debug "^2.2.0" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -8614,6 +8863,13 @@ supports-color@^5.1.0, supports-color@^5.2.0, supports-color@^5.3.0, supports-co dependencies: has-flag "^3.0.0" +supports-color@~5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.0.1.tgz#1c5331f22250c84202805b2f17adf16699f3a39a" + integrity sha512-7FQGOlSQ+AQxBNXJpVDj8efTA/FtyB5wcNE1omXXJ0cq6jm1jjDwuROlYDbnzHqdNPqliWFhcioCWSyav+xBnA== + dependencies: + has-flag "^2.0.0" + svgo@^0.7.0: version "0.7.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" @@ -8653,6 +8909,19 @@ tapable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" +tar-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + tar@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" @@ -8756,6 +9025,11 @@ to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" @@ -9056,7 +9330,7 @@ url-parse@^1.1.8, url-parse@^1.4.3: querystringify "^2.0.0" requires-port "^1.0.0" -url@^0.11.0: +url@^0.11.0, url@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" dependencies: @@ -9200,6 +9474,39 @@ wbuf@^1.1.0, wbuf@^1.7.2: dependencies: minimalistic-assert "^1.0.0" +wdio-dot-reporter@~0.0.8: + version "0.0.10" + resolved "https://registry.yarnpkg.com/wdio-dot-reporter/-/wdio-dot-reporter-0.0.10.tgz#facfb7c9c5984149951f59cbc3cd0752101cf0e0" + integrity sha512-A0TCk2JdZEn3M1DSG9YYbNRcGdx/YRw19lTiRpgwzH4qqWkO/oRDZRmi3Snn4L2j54KKTfPalBhlOtc8fojVgg== + +webdriverio@^4.13.0: + version "4.14.2" + resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.14.2.tgz#335038214272675b409bdfc8276a9345a88bc83e" + integrity sha512-eZXiu0ST6KBi6Pz8tDArw5bNgGu6aohrkA8GFADk1HzClSyf+3arcS16Q7n7SaUPz/ZemsLIw5nQO8eb6v8L3g== + dependencies: + archiver "~2.1.0" + babel-runtime "^6.26.0" + css-parse "^2.0.0" + css-value "~0.0.1" + deepmerge "~2.0.1" + ejs "~2.5.6" + gaze "~1.1.2" + glob "~7.1.1" + grapheme-splitter "^1.0.2" + inquirer "~3.3.0" + json-stringify-safe "~5.0.1" + mkdirp "~0.5.1" + npm-install-package "~2.1.0" + optimist "~0.6.1" + q "~1.5.0" + request "^2.83.0" + rgb2hex "^0.1.9" + safe-buffer "~5.1.1" + supports-color "~5.0.0" + url "~0.11.0" + wdio-dot-reporter "~0.0.8" + wgxpath "~1.0.0" + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -9325,6 +9632,11 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" +wgxpath@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wgxpath/-/wgxpath-1.0.0.tgz#eef8a4b9d558cc495ad3a9a2b751597ecd9af690" + integrity sha1-7vikudVYzEla06mit1FZfs2a9pA= + whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.4.tgz#63fb016b7435b795d9025632c086a5209dbd2621" @@ -9582,3 +9894,13 @@ yauzl@2.4.1: resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" dependencies: fd-slicer "~1.0.1" + +zip-stream@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04" + integrity sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ= + dependencies: + archiver-utils "^1.3.0" + compress-commons "^1.2.0" + lodash "^4.8.0" + readable-stream "^2.0.0"