feat: install devtool extensions for debug builds (#160)

* feat: install devtool extensions for debug builds
* refactor: unify fetching package.json
* test: add new feature test & update pkgJson fetch
* chore: bump electron-devtools-installer@3.1.1
* docs: dev tool extension
diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md
index 49fd08b..f1e20d6 100644
--- a/DOCUMENTATION.md
+++ b/DOCUMENTATION.md
@@ -36,11 +36,16 @@
     - [How to Disable the Window From Being Resizable](#how-to-disable-the-window-from-being-resizable)
     - [How to Make the Window Fullscreen](#how-to-make-the-window-fullscreen)
     - [How to Support Node.js and Electron APIs](#how-to-support-nodejs-and-electron-apis)
+    - [Customizing BrowserWindow Instance Method](#customizing-browserwindow-instance-method)
+      - [Load a local HTML file using relative path from the `{project_dir}/www` directory](#load-a-local-html-file-using-relative-path-from-the-project_dirwww-directory)
+      - [Load a local HTML using full path](#load-a-local-html-using-full-path)
+      - [Load a remote URL](#load-a-remote-url)
   - [Customizing the Electron's Main Process](#customizing-the-electrons-main-process)
   - [Bundling Node Modules](#bundling-node-modules)
     - [Cordova Package Handling](#cordova-package-handling)
   - [DevTools](#devtools)
   - [Debugging the Application's Main Process](#debugging-the-applications-main-process)
+  - [Enable Developer Tool Exrtensions (Chrome Extensions)](#enable-developer-tool-exrtensions-chrome-extensions)
   - [Build Configurations](#build-configurations)
     - [Default Build Configurations](#default-build-configurations)
     - [Customizing Build Configurations](#customizing-build-configurations)
@@ -366,6 +371,49 @@
 cordova run electron --nobuild --debug -- --inspect-brk=5858
 ```
 
+## Enable Developer Tool Exrtensions (Chrome Extensions)
+
+To enable a devtool extension, for a debug build, add the `devToolsExtension` collection to the Cordova Electron Settings file (`ElectronSettingsFilePath`).
+
+For example:
+
+```json
+{
+  "devToolsExtension": [
+    "VUEJS_DEVTOOLS"
+  ]
+}
+```
+
+Below is a list of pre-provided devtools that can be added.
+
+- `EMBER_INSPECTOR`
+- `REACT_DEVELOPER_TOOLS`
+- `BACKBONE_DEBUGGER`
+- `JQUERY_DEBUGGER`
+- `ANGULARJS_BATARANG`
+- `VUEJS_DEVTOOLS`
+- `REDUX_DEVTOOLS`
+- `REACT_PERF`
+- `CYCLEJS_DEVTOOL`
+- `APOLLO_DEVELOPER_TOOLS`
+- `MOBX_DEVTOOLS`
+
+If there are any devtools or extensions you wish to use that are avaiable in the Chrome App Store, you can add them by provided the extension's app ID.
+
+**Note:** The developer tools & extensions are not installed on a release build.
+
+**Example:**
+
+```json
+{
+    "browserWindow": {
+        "width": 1024,
+        "height": 768
+    }
+}
+```
+
 ## Build Configurations
 
 ### Default Build Configurations
diff --git a/bin/templates/platform_www/cdv-electron-main.js b/bin/templates/platform_www/cdv-electron-main.js
index 155dbc2..c8d4968 100644
--- a/bin/templates/platform_www/cdv-electron-main.js
+++ b/bin/templates/platform_www/cdv-electron-main.js
@@ -29,6 +29,10 @@
 const cdvElectronSettings = require('./cdv-electron-settings.json');
 const reservedScheme = require('./cdv-reserved-scheme.json');
 
+const devTools = cdvElectronSettings.browserWindow.webPreferences.devTools
+    ? require('electron-devtools-installer')
+    : false;
+
 const scheme = cdvElectronSettings.scheme;
 const hostname = cdvElectronSettings.hostname;
 const isFileProtocol = scheme === 'file';
@@ -106,6 +110,13 @@
         configureProtocol();
     }
 
+    if (devTools && cdvElectronSettings.devToolsExtension) {
+        const extensions = cdvElectronSettings.devToolsExtension.map(id => devTools[id] || id);
+        devTools.default(extensions) // default = install extension
+            .then((name) => console.log(`Added Extension:  ${name}`))
+            .catch((err) => console.log('An error occurred: ', err));
+    }
+
     createWindow();
 });
 
diff --git a/lib/Api.js b/lib/Api.js
index 6eed49c..0751a64 100644
--- a/lib/Api.js
+++ b/lib/Api.js
@@ -33,6 +33,7 @@
     PlatformJson,
     PluginInfoProvider
 } = require('cordova-common');
+const { getPackageJson } = require('./util');
 const Parser = require('./parser');
 
 function setupEvents (externalEventEmitter) {
@@ -353,17 +354,8 @@
     }
 
     static version () {
-        let platformPkg = null;
-
-        try {
-            // coming from user project
-            platformPkg = require(require.resolve('cordova-electron/package.json'));
-        } catch (e) {
-            // coming from repo test & coho
-            platformPkg = require('../package.json');
-        }
-
-        return platformPkg.version;
+        const packageJson = getPackageJson();
+        return packageJson.version;
     }
 }
 // @todo create projectInstance and fulfill promise with it.
diff --git a/lib/PackageJsonParser.js b/lib/PackageJsonParser.js
index 2944029..9bebeff 100644
--- a/lib/PackageJsonParser.js
+++ b/lib/PackageJsonParser.js
@@ -20,6 +20,7 @@
 const fs = require('fs-extra');
 const path = require('path');
 const { events } = require('cordova-common');
+const { getPackageJson } = require('./util');
 
 class PackageJsonParser {
     constructor (wwwDir, projectRootDir) {
@@ -95,6 +96,21 @@
         return this;
     }
 
+    enableDevTools (enable = false) {
+        if (enable) {
+            const pkgJson = getPackageJson();
+            const devToolsDependency = 'electron-devtools-installer';
+
+            if (!this.package.dependencies) {
+                this.package.dependencies = {};
+            }
+
+            this.package.dependencies[devToolsDependency] = pkgJson.dependencies[devToolsDependency];
+        }
+
+        return this;
+    }
+
     configureHomepage (config) {
         this.package.homepage = (config.doc.find('author') && config.doc.find('author').attrib.href) || 'https://cordova.io';
     }
diff --git a/lib/prepare.js b/lib/prepare.js
index a304ee2..db46af0 100644
--- a/lib/prepare.js
+++ b/lib/prepare.js
@@ -76,6 +76,7 @@
 
     (new PackageJsonParser(this.locations.www, cordovaProject.root))
         .configure(this.config, projectPackageJson)
+        .enableDevTools(options && options.options && !options.options.release)
         .write();
 
     const userElectronSettings = cordovaProject.projectConfig.getPlatformPreference('ElectronSettingsFilePath', 'electron');
diff --git a/lib/util.js b/lib/util.js
index e8362b7..df84976 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -17,6 +17,8 @@
     under the License.
 */
 
+let _packageJson = null;
+
 module.exports.deepMerge = (mergeTo, mergeWith) => {
     for (const property in mergeWith) {
         if (Object.prototype.toString.call(mergeWith[property]) === '[object Object]') {
@@ -30,3 +32,23 @@
 
     return mergeTo;
 };
+
+/**
+ * Gets the `cordova-electron` package.json file.
+ * The path to the file depends on if called from a unit testing or an actual Cordova project.
+ *
+ * @return {Object} package.json content
+ */
+module.exports.getPackageJson = () => {
+    if (_packageJson) return _packageJson;
+
+    try {
+        // coming from user project
+        _packageJson = require(require.resolve('cordova-electron/package.json'));
+    } catch (e) {
+        // coming from repo test & coho
+        _packageJson = require('../package.json');
+    }
+
+    return _packageJson;
+};
diff --git a/package-lock.json b/package-lock.json
index eaf3d51..e0e1c21 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1279,6 +1279,26 @@
         "yargs": "^15.3.1"
       }
     },
+    "electron-devtools-installer": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-3.1.1.tgz",
+      "integrity": "sha512-g2D4J6APbpsiIcnLkFMyKZ6bOpEJ0Ltcc2m66F7oKUymyGAt628OWeU9nRZoh1cNmUs/a6Cls2UfOmsZtE496Q==",
+      "requires": {
+        "rimraf": "^3.0.2",
+        "semver": "^7.2.1",
+        "unzip-crx-3": "^0.2.0"
+      },
+      "dependencies": {
+        "rimraf": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        }
+      }
+    },
     "electron-publish": {
       "version": "22.7.0",
       "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.7.0.tgz",
@@ -2271,6 +2291,11 @@
       "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
       "dev": true
     },
+    "immediate": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+      "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
+    },
     "import-fresh": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
@@ -2728,6 +2753,17 @@
         "universalify": "^1.0.0"
       }
     },
+    "jszip": {
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz",
+      "integrity": "sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==",
+      "requires": {
+        "lie": "~3.3.0",
+        "pako": "~1.0.2",
+        "readable-stream": "~2.3.6",
+        "set-immediate-shim": "~1.0.1"
+      }
+    },
     "keyv": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
@@ -2759,6 +2795,14 @@
         "type-check": "~0.3.2"
       }
     },
+    "lie": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+      "requires": {
+        "immediate": "~3.0.5"
+      }
+    },
     "load-json-file": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
@@ -3179,6 +3223,11 @@
         }
       }
     },
+    "pako": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+    },
     "parent-module": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -3693,6 +3742,11 @@
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
       "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
     },
+    "set-immediate-shim": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+      "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
+    },
     "shebang-command": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -4130,6 +4184,16 @@
       "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
       "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
     },
+    "unzip-crx-3": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz",
+      "integrity": "sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==",
+      "requires": {
+        "jszip": "^3.1.0",
+        "mkdirp": "^0.5.1",
+        "yaku": "^0.16.6"
+      }
+    },
     "update-notifier": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz",
@@ -4315,6 +4379,11 @@
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
       "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
     },
+    "yaku": {
+      "version": "0.16.7",
+      "resolved": "https://registry.npmjs.org/yaku/-/yaku-0.16.7.tgz",
+      "integrity": "sha1-HRlceKqbW/hHnIlblQT9TwhHmE4="
+    },
     "yallist": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
diff --git a/package.json b/package.json
index 6c99282..60833bb 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
     "cordova-common": "^4.0.1",
     "electron": "^9.0.0",
     "electron-builder": "^22.7.0",
+    "electron-devtools-installer": "^3.1.1",
     "execa": "^4.0.0",
     "fs-extra": "^9.0.0"
   },
diff --git a/tests/spec/unit/lib/Api.spec.js b/tests/spec/unit/lib/Api.spec.js
index d32e61b..6d5b438 100644
--- a/tests/spec/unit/lib/Api.spec.js
+++ b/tests/spec/unit/lib/Api.spec.js
@@ -488,31 +488,9 @@
 
     describe('version method', () => {
         it('should get version from cordova-electron package.', () => {
-            const dummyRequire = path => {
-                expect(path).toEqual('cordova-elecrtron-resolved-package-path');
+            Api.__set__('getPackageJson', () => {
                 return { version: '1.0.0' };
-            };
-
-            dummyRequire.resolve = path => {
-                return 'cordova-elecrtron-resolved-package-path';
-            };
-
-            Api.__set__('require', dummyRequire);
-
-            expect(Api.version()).toEqual('1.0.0');
-        });
-
-        it('should get version from package.json.', () => {
-            const dummyRequire = path => {
-                expect(path).toEqual('../package.json');
-                return { version: '1.0.0' };
-            };
-
-            dummyRequire.resolve = path => {
-                throw Error('random error');
-            };
-
-            Api.__set__('require', dummyRequire);
+            });
 
             expect(Api.version()).toEqual('1.0.0');
         });
diff --git a/tests/spec/unit/lib/PackageJsonParser.spec.js b/tests/spec/unit/lib/PackageJsonParser.spec.js
index c555052..fb21b8f 100644
--- a/tests/spec/unit/lib/PackageJsonParser.spec.js
+++ b/tests/spec/unit/lib/PackageJsonParser.spec.js
@@ -79,6 +79,39 @@
         expect(packageJsonParser.package).toEqual(defaultInitPackageObj);
     });
 
+    it('should not modify the package object when config is not provided.', () => {
+        packageJsonParser.configure();
+        // the package object should be the same as it was initialized
+        expect(packageJsonParser.package).toEqual(defaultInitPackageObj);
+    });
+
+    it('should not add dev tools extension when enable argument = false.', () => {
+        packageJsonParser.enableDevTools(false);
+        // the package object should be the same as it was initialized
+        expect(packageJsonParser.package.dependencies).not.toBeDefined();
+    });
+
+    it('should not add dev tools extension when enable argument = undefined.', () => {
+        packageJsonParser.enableDevTools();
+        // the package object should be the same as it was initialized
+        expect(packageJsonParser.package.dependencies).not.toBeDefined();
+    });
+
+    it('should add dev tools extension when enable argument = true.', () => {
+        packageJsonParser.enableDevTools(true);
+        // the package object should be the same as it was initialized
+        expect(packageJsonParser.package.dependencies).toBeDefined();
+        expect(packageJsonParser.package.dependencies['electron-devtools-installer']).toBeDefined();
+    });
+
+    it('should not create dependencies object if it exists an enable argument = true.', () => {
+        packageJsonParser.package.dependencies = {}; // mocking that the object already exists
+        packageJsonParser.enableDevTools(true);
+        // the package object should be the same as it was initialized
+        expect(packageJsonParser.package.dependencies).toBeDefined();
+        expect(packageJsonParser.package.dependencies['electron-devtools-installer']).toBeDefined();
+    });
+
     it('should update the package object with default values, when config.xml is empty.', () => {
         packageJsonParser.configure(cfgEmpty, defaultMockProjectPackageJson);
 
diff --git a/tests/spec/unit/lib/prepare.spec.js b/tests/spec/unit/lib/prepare.spec.js
index f26c127..26e5e77 100644
--- a/tests/spec/unit/lib/prepare.spec.js
+++ b/tests/spec/unit/lib/prepare.spec.js
@@ -107,6 +107,7 @@
 let fakeParserConstructorSpy;
 let fakeManifestJsonParserConfigureSpy;
 let fakePackageJsonParserConfigureSpy;
+let fakePackageJsonParserEnableDevToolsSpy;
 let fakeSettingJsonParserConfigureSpy;
 let fakeParserWriteSpy;
 let fakeConfigParserConstructorSpy;
@@ -124,6 +125,7 @@
 
     fakeManifestJsonParserConfigureSpy = jasmine.createSpy('fakeManifestJsonParserConfigureSpy');
     fakePackageJsonParserConfigureSpy = jasmine.createSpy('fakePackageJsonParserConfigureSpy');
+    fakePackageJsonParserEnableDevToolsSpy = jasmine.createSpy('fakePackageJsonParserEnableDevToolsSpy');
     fakeSettingJsonParserConfigureSpy = jasmine.createSpy('fakeSettingJsonParserConfigureSpy');
 
     fakeParserWriteSpy = jasmine.createSpy('fakeParserWriteSpy');
@@ -183,6 +185,11 @@
         fakePackageJsonParserConfigureSpy(configXmlParser, projectPackageJson);
         return this;
     }
+
+    enableDevTools (enable) {
+        fakePackageJsonParserEnableDevToolsSpy(enable);
+        return this;
+    }
 }
 
 class FakeSettingJsonParser extends FakeParser {
@@ -280,6 +287,7 @@
                 expect(fakeConfigParserConstructorSpy).toHaveBeenCalled();
                 expect(fakeManifestJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakePackageJsonParserConfigureSpy).toHaveBeenCalled();
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalled();
                 expect(fakeSettingJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakeParserWriteSpy).toHaveBeenCalled();
                 expect(fakeConfigParserWriteSpy).toHaveBeenCalled();
@@ -290,6 +298,104 @@
             });
         });
 
+        it('should enable devtools.', () => {
+            // Mocking the scope with dummy API;
+            return Promise.resolve().then(function () {
+                // Create API instance and mock for test case.
+                api.events = { emit: emitSpy };
+                api.parser.update_www = () => this;
+                api.parser.update_project = () => this;
+
+                const defaultConfigPathMock = path.join(api.locations.platformRootDir, 'cordova', 'defaults.xml');
+
+                const copySyncSpy = jasmine.createSpy('copySync');
+                prepare.__set__('fs', {
+                    existsSync: function (configPath) {
+                        return configPath === defaultConfigPathMock;
+                    },
+                    copySync: copySyncSpy,
+                    readFileSync: function (filePath) {
+                        if (filePath === path.join('MOCK_PROJECT_ROOT', 'package.json')) {
+                            return defaultMockProjectPackageJson;
+                        }
+                    }
+                });
+
+                // override classes and methods called in modules.export.prepare
+                prepare.__set__('ConfigParser', FakeConfigParser);
+                prepare.__set__('xmlHelpers', xmlHelpersMock);
+                prepare.__set__('updateIcons', updateIconsFake);
+                prepare.__set__('updateSplashScreens', updateSplashScreensFake);
+                prepare.__set__('ManifestJsonParser', FakeManifestJsonParser);
+                prepare.__set__('PackageJsonParser', FakePackageJsonParser);
+                prepare.__set__('SettingJsonParser', FakeSettingJsonParser);
+
+                cordovaProject.projectConfig.getPlatformPreference = () => undefined;
+
+                prepare.prepare.call(
+                    api,
+                    cordovaProject,
+                    {
+                        options: {
+                            release: false
+                        }
+                    },
+                    api
+                );
+
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalledWith(true);
+            });
+        });
+
+        it('should not enable devtools.', () => {
+            // Mocking the scope with dummy API;
+            return Promise.resolve().then(function () {
+                // Create API instance and mock for test case.
+                api.events = { emit: emitSpy };
+                api.parser.update_www = () => this;
+                api.parser.update_project = () => this;
+
+                const defaultConfigPathMock = path.join(api.locations.platformRootDir, 'cordova', 'defaults.xml');
+
+                const copySyncSpy = jasmine.createSpy('copySync');
+                prepare.__set__('fs', {
+                    existsSync: function (configPath) {
+                        return configPath === defaultConfigPathMock;
+                    },
+                    copySync: copySyncSpy,
+                    readFileSync: function (filePath) {
+                        if (filePath === path.join('MOCK_PROJECT_ROOT', 'package.json')) {
+                            return defaultMockProjectPackageJson;
+                        }
+                    }
+                });
+
+                // override classes and methods called in modules.export.prepare
+                prepare.__set__('ConfigParser', FakeConfigParser);
+                prepare.__set__('xmlHelpers', xmlHelpersMock);
+                prepare.__set__('updateIcons', updateIconsFake);
+                prepare.__set__('updateSplashScreens', updateSplashScreensFake);
+                prepare.__set__('ManifestJsonParser', FakeManifestJsonParser);
+                prepare.__set__('PackageJsonParser', FakePackageJsonParser);
+                prepare.__set__('SettingJsonParser', FakeSettingJsonParser);
+
+                cordovaProject.projectConfig.getPlatformPreference = () => undefined;
+
+                prepare.prepare.call(
+                    api,
+                    cordovaProject,
+                    {
+                        options: {
+                            release: true
+                        }
+                    },
+                    api
+                );
+
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalledWith(false);
+            });
+        });
+
         it('should get user supplied Electron settings overide path from config.xml but ignore for incorrect path.', () => {
             // Mocking the scope with dummy API;
             return Promise.resolve().then(function () {
@@ -329,6 +435,7 @@
 
                 expect(fakeManifestJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakePackageJsonParserConfigureSpy).toHaveBeenCalled();
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalled();
                 expect(fakeSettingJsonParserConfigureSpy).toHaveBeenCalled();
                 const actual = fakeSettingJsonParserConfigureSpy.calls.argsFor(0)[1];
                 expect(actual).toEqual(undefined);
@@ -373,6 +480,7 @@
 
                 expect(fakeManifestJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakePackageJsonParserConfigureSpy).toHaveBeenCalled();
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalled();
                 expect(fakeSettingJsonParserConfigureSpy).toHaveBeenCalled();
                 const actual = fakeSettingJsonParserConfigureSpy.calls.argsFor(0)[2];
                 expect(actual).toContain('pass_test_path');
@@ -424,6 +532,7 @@
                 expect(fakeConfigParserConstructorSpy).toHaveBeenCalled();
                 expect(fakeManifestJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakePackageJsonParserConfigureSpy).toHaveBeenCalled();
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalled();
                 expect(fakeSettingJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakeParserWriteSpy).toHaveBeenCalled();
                 expect(fakeConfigParserWriteSpy).toHaveBeenCalled();
@@ -480,6 +589,7 @@
                 expect(fakeConfigParserConstructorSpy).toHaveBeenCalled();
                 expect(fakeManifestJsonParserConfigureSpy).not.toHaveBeenCalled();
                 expect(fakePackageJsonParserConfigureSpy).toHaveBeenCalled();
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalled();
                 expect(fakeSettingJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakeParserWriteSpy).toHaveBeenCalled();
                 expect(fakeConfigParserWriteSpy).toHaveBeenCalled();
@@ -535,6 +645,7 @@
                 expect(fakeConfigParserConstructorSpy).toHaveBeenCalled();
                 expect(fakeManifestJsonParserConfigureSpy).not.toHaveBeenCalled();
                 expect(fakePackageJsonParserConfigureSpy).toHaveBeenCalled();
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalled();
                 expect(fakeSettingJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakeParserWriteSpy).toHaveBeenCalled();
                 expect(fakeConfigParserWriteSpy).toHaveBeenCalled();
@@ -588,6 +699,7 @@
                 expect(fakeConfigParserConstructorSpy).toHaveBeenCalled();
                 expect(fakeManifestJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakePackageJsonParserConfigureSpy).toHaveBeenCalled();
+                expect(fakePackageJsonParserEnableDevToolsSpy).toHaveBeenCalled();
                 expect(fakeSettingJsonParserConfigureSpy).toHaveBeenCalled();
                 expect(fakeParserWriteSpy).toHaveBeenCalled();
                 expect(fakeConfigParserWriteSpy).toHaveBeenCalled();