+
There was an error attempting to read from the file system.
@@ -44,16 +44,17 @@ export default {
},
methods: {
getCurrentDirectory: function () {
- const fs = window.nw.require('fs');
- try {
- this.contents = fs.readdirSync('.');
- this.error = false;
- } catch (err) {
- this.error = true;
+ if (this.isDesktop) {
+ const fs = this.nw.require('fs');
+ try {
+ this.contents = fs.readdirSync('.');
+ this.error = false;
+ } catch (err) {
+ this.error = true;
+ }
}
}
- },
- computed: {}
+ }
};
diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue
index 8a72ad6..66bde42 100644
--- a/src/components/HelloWorld.vue
+++ b/src/components/HelloWorld.vue
@@ -3,7 +3,8 @@
{{ msg }}
-
+
+
You are using
Vue.js (v{{ vueVersion }}),
NW.js (v{{ versions.nw }}-{{ versions['nw-flavor'] }}),
@@ -11,9 +12,21 @@
and
Chromium (v{{ versions.chromium }}).
+
+ You are using Vue.js (v{{ vueVersion }}).
+
+
+
+
+
@@ -38,9 +51,11 @@
Ecosystem
-
+
+
-
+
+
@@ -154,19 +169,19 @@ export default {
methods: {
toggleDevTools: function () {
if (this.showDevTools) {
- window.nw.Window.get().showDevTools();
+ this.nw.Window.get().showDevTools();
} else {
- window.nw.Window.get().closeDevTools();
+ this.nw.Window.get().closeDevTools();
}
this.showDevTools = !this.showDevTools;
}
},
computed: {
devMode: function () {
- return window.process.versions['nw-flavor'] === 'sdk';
+ return this.isDesktop && this.process.versions['nw-flavor'] === 'sdk';
},
versions: function () {
- return window.process.versions;
+ return this.isDesktop && this.process.versions;
},
vueVersion: function () {
return Vue.version;
diff --git a/src/components/LinkList.vue b/src/components/LinkList.vue
index c1ec52d..d6f61a6 100644
--- a/src/components/LinkList.vue
+++ b/src/components/LinkList.vue
@@ -27,14 +27,9 @@ export default {
validator: function (links) {
let valid = true;
links.forEach(function (link) {
- if (
- !link.name ||
- !link.url ||
- !link.name.length ||
- !link.url.length ||
- typeof(link.name) !== 'string' ||
- typeof(link.url) !== 'string'
- ) {
+ const hasName = link.name && typeof(link.name) === 'string';
+ const hasUrl = link.url && typeof(link.url) === 'string';
+ if (!hasName || !hasUrl) {
valid = false;
}
});
@@ -44,7 +39,11 @@ export default {
},
methods: {
open: function (url) {
- window.nw.Shell.openExternal(url);
+ if (this.isDesktop) {
+ this.nw.Shell.openExternal(url);
+ } else {
+ window.open(url, '_blank');
+ }
}
}
};
diff --git a/src/helpers/applyPrototypes.js b/src/helpers/applyPrototypes.js
new file mode 100644
index 0000000..a0d175c
--- /dev/null
+++ b/src/helpers/applyPrototypes.js
@@ -0,0 +1,11 @@
+// Make NW.js and Node globals available in Vue
+export default function applyPrototypes (Vue) {
+ Vue.prototype.isDesktop = !!window.nw;
+
+ if (window.nw) {
+ Vue.prototype.nw = window.nw;
+ Vue.prototype.process = window.nw.process;
+ Vue.prototype.require = window.nw.require;
+ Vue.prototype.global = global;
+ }
+}
diff --git a/src/main.js b/src/main.js
index 2426431..2dcb210 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,7 +1,10 @@
import Vue from 'vue';
-import App from './App.vue';
+
+import App from '@/App.vue';
+import applyPrototypes from '@/helpers/applyPrototypes.js';
Vue.config.productionTip = false;
+applyPrototypes(Vue);
// eslint-disable-next-line no-unused-vars
const app = new Vue({
diff --git a/tests/unit/App.test.js b/tests/unit/App.test.js
index eeb36ea..90c1d6b 100644
--- a/tests/unit/App.test.js
+++ b/tests/unit/App.test.js
@@ -1,11 +1,27 @@
import { shallowMount } from '@vue/test-utils';
+
import App from '@/App.vue';
describe('App.vue', () => {
- test('Render default contents', () => {
- const wrapper = shallowMount(App);
+ describe('Desktop', () => {
+ test('Render default contents', () => {
+ const wrapper = shallowMount(App);
+
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
+ });
+
+ describe('Web', () => {
+ beforeEach(() => {
+ window.webSetup();
+ });
+
+ test('Render default contents', () => {
+ const wrapper = shallowMount(App);
- expect(wrapper)
- .toMatchSnapshot();
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
});
});
diff --git a/tests/unit/__snapshots__/App.test.js.snap b/tests/unit/__snapshots__/App.test.js.snap
index c7f6232..b973ca7 100644
--- a/tests/unit/__snapshots__/App.test.js.snap
+++ b/tests/unit/__snapshots__/App.test.js.snap
@@ -1,9 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`App.vue Render default contents 1`] = `
+exports[`App.vue Desktop Render default contents 1`] = `
`;
+
+exports[`App.vue Web Render default contents 1`] = `
+
+
+
+
+
+`;
diff --git a/tests/unit/components/FsExample.test.js b/tests/unit/components/FsExample.test.js
index 2183f6f..1cf4a04 100644
--- a/tests/unit/components/FsExample.test.js
+++ b/tests/unit/components/FsExample.test.js
@@ -1,45 +1,80 @@
import { shallowMount } from '@vue/test-utils';
+
import FsExample from '@/components/FsExample.vue';
describe('FsExample.vue', () => {
- test('Render default contents', () => {
- const wrapper = shallowMount(FsExample);
+ const shared = {
+ renderDefaultContents: function () {
+ const wrapper = shallowMount(FsExample);
+ return wrapper;
+ }
+ };
- expect(wrapper)
- .toMatchSnapshot();
- });
+ describe('Desktop', () => {
+ test('Render default contents', () => {
+ const wrapper = shared.renderDefaultContents();
+
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
- test('Click button', async () => {
- const wrapper = shallowMount(FsExample);
- let domButton = wrapper.find('[data-test="fs-example-button"]');
- domButton.trigger('click');
+ test('Click button', async () => {
+ const wrapper = shallowMount(FsExample);
+ let domButton = wrapper.find('[data-test="fs-example-button"]');
+ domButton.trigger('click');
+
+ await wrapper.vm.$nextTick();
+
+ expect(window.nw.require)
+ .toHaveBeenCalledWith('fs');
+
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
- await wrapper.vm.$nextTick();
+ test('Error state', async () => {
+ window.nw.require.mockImplementation((module) => {
+ if (module === 'fs') {
+ return new Error();
+ }
+ });
- expect(window.nw.require)
- .toHaveBeenCalledWith('fs');
+ const wrapper = shallowMount(FsExample);
+ let domButton = wrapper.find('[data-test="fs-example-button"]');
+ domButton.trigger('click');
- expect(wrapper)
- .toMatchSnapshot();
+ await wrapper.vm.$nextTick();
+
+ expect(window.nw.require)
+ .toHaveBeenCalledWith('fs');
+
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
});
- test('Error state', async () => {
- window.nw.require.mockImplementation((module) => {
- if (module === 'fs') {
- return new Error();
- }
+ describe('Web', () => {
+ beforeEach(() => {
+ window.webSetup();
});
- const wrapper = shallowMount(FsExample);
- let domButton = wrapper.find('[data-test="fs-example-button"]');
- domButton.trigger('click');
+ test('Render default contents', () => {
+ const wrapper = shared.renderDefaultContents();
- await wrapper.vm.$nextTick();
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
- expect(window.nw.require)
- .toHaveBeenCalledWith('fs');
+ test('getCurrentDirectory', () => {
+ const wrapper = shallowMount(FsExample);
- expect(wrapper)
- .toMatchSnapshot();
+ wrapper.vm.getCurrentDirectory();
+
+ expect(wrapper.vm.contents)
+ .toEqual(null);
+
+ expect(wrapper.vm.error)
+ .toEqual(false);
+ });
});
});
diff --git a/tests/unit/components/HelloWorld.test.js b/tests/unit/components/HelloWorld.test.js
index 3dafd23..52cf325 100644
--- a/tests/unit/components/HelloWorld.test.js
+++ b/tests/unit/components/HelloWorld.test.js
@@ -1,39 +1,76 @@
import { shallowMount, mount } from '@vue/test-utils';
+
import HelloWorld from '@/components/HelloWorld.vue';
describe('HelloWorld.vue', () => {
- test('Render props.msg', () => {
- const msg = 'new message';
- const wrapper = shallowMount(HelloWorld, {
- propsData: { msg }
+ const shared = {
+ msg: 'new message',
+ renderPropsMsg: function () {
+ const wrapper = shallowMount(HelloWorld, {
+ propsData: {
+ msg: this.msg
+ }
+ });
+
+ return wrapper;
+ },
+ renderDefaultContents: function () {
+ const wrapper = mount(HelloWorld);
+ return wrapper;
+ }
+ };
+
+ describe('Desktop', () => {
+ test('Render props.msg', () => {
+ const wrapper = shared.renderPropsMsg();
+
+ expect(wrapper.find('[data-test="message"]').text())
+ .toEqual(shared.msg);
});
- expect(wrapper.find('[data-test="message"]').text())
- .toEqual(msg);
- });
+ test('Render default contents', () => {
+ const wrapper = shared.renderDefaultContents();
+
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
- test('Render default contents', () => {
- const wrapper = mount(HelloWorld);
+ test('Activate dev tools', async () => {
+ const wrapper = shallowMount(HelloWorld);
- expect(wrapper)
- .toMatchSnapshot();
- });
+ const button = wrapper.find('[data-test="toggleDevTools"]');
- test('Activate dev tools', async () => {
- const wrapper = shallowMount(HelloWorld);
+ button.trigger('click');
+ await wrapper.vm.$nextTick();
- const button = wrapper.find('[data-test="toggleDevTools"]');
+ expect(wrapper.find('[data-test="toggleDevTools').html())
+ .toMatchSnapshot('hide');
- button.trigger('click');
- await wrapper.vm.$nextTick();
+ button.trigger('click');
+ await wrapper.vm.$nextTick();
- expect(wrapper.find('[data-test="toggleDevTools').html())
- .toMatchSnapshot('hide');
+ expect(wrapper.find('[data-test="toggleDevTools').html())
+ .toMatchSnapshot('show');
+ });
+ });
+
+ describe('Web', () => {
+ beforeEach(() => {
+ window.webSetup();
+ });
- button.trigger('click');
- await wrapper.vm.$nextTick();
+ test('Render props.msg', () => {
+ const wrapper = shared.renderPropsMsg();
- expect(wrapper.find('[data-test="toggleDevTools').html())
- .toMatchSnapshot('show');
+ expect(wrapper.find('[data-test="message"]').text())
+ .toEqual(shared.msg);
+ });
+
+ test('Render default contents', () => {
+ const wrapper = shared.renderDefaultContents();
+
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
});
});
diff --git a/tests/unit/components/LinkList.test.js b/tests/unit/components/LinkList.test.js
index fcc754b..958d5b1 100644
--- a/tests/unit/components/LinkList.test.js
+++ b/tests/unit/components/LinkList.test.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+
import LinkList from '@/components/LinkList.vue';
describe('LinkList.vue', () => {
@@ -7,44 +8,99 @@ describe('LinkList.vue', () => {
url: 'https://nwjs.io'
};
- test('Validate props', () => {
- const wrapper = shallowMount(LinkList);
- const links = wrapper.vm.$options.props.links;
+ const shared = {
+ validateProps: function () {
+ const wrapper = shallowMount(LinkList);
+ const links = wrapper.vm.$options.props.links;
+ return links;
+ },
+ renderDefaultContents: function () {
+ const wrapper = shallowMount(LinkList, {
+ propsData: { links: [link] }
+ });
+ return wrapper;
+ },
+ clickLink: function () {
+ const wrapper = shallowMount(LinkList, {
+ propsData: { links: [link] }
+ });
- expect(links.required)
- .toBeFalsy();
+ let domLink = wrapper.findAll('[data-test="link"]').at(0);
+ domLink.trigger('click');
+ }
+ };
- expect(links.type)
- .toBe(Array);
+ describe('Desktop', () => {
+ test('Validate props', () => {
+ const links = shared.validateProps(expect);
- expect(links.default)
- .toBeNull();
+ expect(links.required)
+ .toBeFalsy();
- expect(links.validator && links.validator([{ name: '', url: '' }]))
- .toBeFalsy();
+ expect(links.type)
+ .toBe(Array);
- expect(links.validator && links.validator([link]))
- .toBeTruthy();
- });
+ expect(links.default)
+ .toBeNull();
+
+ expect(links.validator && links.validator([{ name: '', url: '' }]))
+ .toBeFalsy();
+
+ expect(links.validator && links.validator([link]))
+ .toBeTruthy();
+ });
+
+ test('Render default contents', () => {
+ const wrapper = shared.renderDefaultContents();
- test('Render default contents', () => {
- const wrapper = shallowMount(LinkList, {
- propsData: { links: [link] }
+ expect(wrapper)
+ .toMatchSnapshot();
});
- expect(wrapper)
- .toMatchSnapshot();
+ test('Click link', () => {
+ shared.clickLink();
+
+ expect(window.nw.Shell.openExternal)
+ .toHaveBeenCalledWith('https://nwjs.io');
+ });
});
- test('Click link', () => {
- const wrapper = shallowMount(LinkList, {
- propsData: { links: [link] }
+ describe('Web', () => {
+ beforeEach(() => {
+ window.webSetup();
+ });
+
+ test('Validate props', () => {
+ const links = shared.validateProps();
+
+ expect(links.required)
+ .toBeFalsy();
+
+ expect(links.type)
+ .toBe(Array);
+
+ expect(links.default)
+ .toBeNull();
+
+ expect(links.validator && links.validator([{ name: '', url: '' }]))
+ .toBeFalsy();
+
+ expect(links.validator && links.validator([link]))
+ .toBeTruthy();
});
- let domLink = wrapper.findAll('[data-test="link"]').at(0);
- domLink.trigger('click');
+ test('Render default contents', () => {
+ const wrapper = shared.renderDefaultContents();
+
+ expect(wrapper)
+ .toMatchSnapshot();
+ });
- expect(window.nw.Shell.openExternal)
- .toHaveBeenCalledWith('https://nwjs.io');
+ test('Click link', () => {
+ shared.clickLink();
+
+ expect(window.open)
+ .toHaveBeenCalledWith('https://nwjs.io', '_blank');
+ });
});
});
diff --git a/tests/unit/components/__snapshots__/FsExample.test.js.snap b/tests/unit/components/__snapshots__/FsExample.test.js.snap
index 25effa6..6046f23 100644
--- a/tests/unit/components/__snapshots__/FsExample.test.js.snap
+++ b/tests/unit/components/__snapshots__/FsExample.test.js.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`FsExample.vue Click button 1`] = `
+exports[`FsExample.vue Desktop Click button 1`] = `
@@ -20,7 +20,7 @@ exports[`FsExample.vue Click button 1`] = `
`;
-exports[`FsExample.vue Error state 1`] = `
+exports[`FsExample.vue Desktop Error state 1`] = `
There was an error attempting to read from the file system.
@@ -32,7 +32,7 @@ exports[`FsExample.vue Error state 1`] = `
`;
-exports[`FsExample.vue Render default contents 1`] = `
+exports[`FsExample.vue Desktop Render default contents 1`] = `
@@ -41,3 +41,5 @@ exports[`FsExample.vue Render default contents 1`] = `
`;
+
+exports[`FsExample.vue Web Render default contents 1`] = ``;
diff --git a/tests/unit/components/__snapshots__/HelloWorld.test.js.snap b/tests/unit/components/__snapshots__/HelloWorld.test.js.snap
index 2e97202..7d704ab 100644
--- a/tests/unit/components/__snapshots__/HelloWorld.test.js.snap
+++ b/tests/unit/components/__snapshots__/HelloWorld.test.js.snap
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`HelloWorld.vue Activate dev tools: hide 1`] = `
+exports[`HelloWorld.vue Desktop Activate dev tools: hide 1`] = `
Hide
@@ -8,7 +8,7 @@ exports[`HelloWorld.vue Activate dev tools: hide 1`] = `
`;
-exports[`HelloWorld.vue Activate dev tools: show 1`] = `
+exports[`HelloWorld.vue Desktop Activate dev tools: show 1`] = `
Show
@@ -16,19 +16,28 @@ exports[`HelloWorld.vue Activate dev tools: show 1`] = `
`;
-exports[`HelloWorld.vue Render default contents 1`] = `
+exports[`HelloWorld.vue Desktop Render default contents 1`] = `
Welcome to your Vue Desktop App in NW.js!
You are using
- Vue.js (v2.6.12),
- NW.js (v0.48.2-sdk),
- Node.js (v14.10.1),
+ Vue.js (v2.6.14),
+ NW.js (v0.54.0-sdk),
+ Node.js (v16.1.0),
and
- Chromium (v85.0.4183.83).
+ Chromium (v91.0.4472.77).
+
Show
@@ -151,3 +160,124 @@ exports[`HelloWorld.vue Render default contents 1`] = `
`;
+
+exports[`HelloWorld.vue Web Render default contents 1`] = `
+
+
+ Welcome to your Vue Desktop App in NW.js!
+
+
+ You are using Vue.js (v2.6.14).
+
+
+
+
You can use the resources below to find more information around building your Vue App.
+
+
Installed CLI Plugins
+
+
Essential Links
+
+
Ecosystem
+
+
+
+`;
diff --git a/tests/unit/components/__snapshots__/LinkList.test.js.snap b/tests/unit/components/__snapshots__/LinkList.test.js.snap
index 86472df..d4f0d24 100644
--- a/tests/unit/components/__snapshots__/LinkList.test.js.snap
+++ b/tests/unit/components/__snapshots__/LinkList.test.js.snap
@@ -1,6 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`LinkList.vue Render default contents 1`] = `
+exports[`LinkList.vue Desktop Render default contents 1`] = `
+
+`;
+
+exports[`LinkList.vue Web Render default contents 1`] = `
diff --git a/tests/unit/setup.js b/tests/unit/setup.js
index 5cab749..831319e 100644
--- a/tests/unit/setup.js
+++ b/tests/unit/setup.js
@@ -1,5 +1,7 @@
import Vue from 'vue';
+import applyPrototypes from '@/helpers/applyPrototypes.js';
+
const { getComputedStyle } = window;
Vue.config.productionTip = false;
@@ -20,20 +22,27 @@ window.getComputedStyle = function getComputedStyleStub (el) {
};
};
+window.webSetup = function () {
+ delete window.nw;
+ applyPrototypes(Vue);
+
+ window.open = jest.fn();
+};
+
global.beforeEach(() => {
- window.process = {
- cwd: process.cwd,
- env: {
- NODE_ENV: 'development'
- },
- versions: {
- chromium: '85.0.4183.83',
- nw: '0.48.2',
- 'nw-flavor': 'sdk',
- node: '14.10.1'
- }
- };
window.nw = {
+ process: {
+ cwd: process.cwd,
+ env: {
+ NODE_ENV: 'development'
+ },
+ versions: {
+ chromium: '91.0.4472.77',
+ nw: '0.54.0',
+ 'nw-flavor': 'sdk',
+ node: '16.1.0'
+ }
+ },
require: jest.fn((module) => {
if (module === 'fs') {
return {
@@ -55,10 +64,14 @@ global.beforeEach(() => {
}
}
};
+
+ applyPrototypes(Vue);
});
global.afterEach(() => {
- window.nw.Window.get().showDevTools.mockClear();
+ if (window.nw) {
+ window.nw.Window.get().showDevTools.mockClear();
+ }
});