Skip to content

Commit

Permalink
♻️ help uses bundled preload script
Browse files Browse the repository at this point in the history
Signed-off-by: Marc Nuri <marc@marcnuri.com>
  • Loading branch information
manusa committed Sep 15, 2022
1 parent 5aec57b commit 78f1a60
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 106 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Expand Up @@ -14,7 +14,8 @@
"experimentalObjectRestSpread": true,
"destructuring": true,
"spread": true
}
},
"sourceType": "module"
},
"rules": {
// Possible Errors
Expand Down
Expand Up @@ -25,31 +25,25 @@ const mockDOM = () => {
describe('Help in Browser test suite', () => {
let mockIpcRenderer;
beforeEach(() => {
require('../../../bundles/help.preload');
mockIpcRenderer = {
send: jest.fn()
};
window.preact = require('preact');
window.html = require('htm').bind(window.preact.h);
window.TopBar = require('../../components').topBar(window.html);
window.APP_EVENTS = {closeDialog: 'close the dialog'};
window.ELECTRONIM_VERSION = '1.33.7';
window.docs = {
'Setup.md': '<span>Setup guide</span>',
'Keyboard-shortcuts.md': '<span>Keyboard shortcuts</span>',
'Troubleshooting.md': '<span>Troubleshooting</span>'
};
window.ipcRenderer = mockIpcRenderer;
mockDOM();
window.ipcRenderer = mockIpcRenderer;
window.ELECTRONIM_VERSION = '1.33.7';
jest.isolateModules(() => {
require('../browser-help');
require('../help.browser');
});
});
test('render, should render all documents', () => {
// Then
expect(document.querySelector('.toc-container').innerHTML)
.toMatch(/Table of Contents/);
expect(document.querySelector('.documents-container').innerHTML)
.toMatch(/Setup guide.+<span>Keyboard shortcuts.+Troubleshooting/);
const documentsContent = document.querySelector('.documents-container').innerHTML;
expect(documentsContent).toContain('<h1>Setup</h1>');
expect(documentsContent).toContain('<h1>Keyboard Shortcuts</h1>');
expect(documentsContent).toContain('<h1>Troubleshooting</h1>');
});
test('render, should show version in footer', () => {
// Then
Expand All @@ -62,7 +56,7 @@ describe('Help in Browser test suite', () => {
fireEvent.click(document.querySelector('.button.is-link.is-light'));
// Then
expect(mockIpcRenderer.send).toHaveBeenCalledTimes(1);
expect(mockIpcRenderer.send).toHaveBeenCalledWith('close the dialog');
expect(mockIpcRenderer.send).toHaveBeenCalledWith('closeDialog');
});
});
});
27 changes: 0 additions & 27 deletions src/help/__tests/index.test.js
Expand Up @@ -13,8 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
const path = require('path');
const DOCS_DIR = path.resolve(__dirname, '../../../docs');
describe('Help module test suite', () => {
let mockBrowserView;
let help;
Expand All @@ -28,31 +26,6 @@ describe('Help module test suite', () => {
}));
help = require('../');
});
describe('fixRelativeUrls', () => {
test('Combination of absolute and relative paths', () => {
// Given
const input = `
<img src\t = 'relativePath'/>
<img src="https://absolute.com" /><a href="./relativeDir" />
<a href="http://test/some-path" />
`;
// When
const result = help.fixRelativeUrls(input);
// Then
expect(result).toBe(`
<img src = '${DOCS_DIR}/relativePath'/>
<img src="https://absolute.com" /><a href="${DOCS_DIR}/./relativeDir" />
<a href="http://test/some-path" />
`);
});
});
test('loadDocs, should load object with documentation', () => {
// When
const docs = help.loadDocs();
// Then
expect(Object.keys(docs)).toContain('Setup.md');
expect(docs['Setup.md']).toMatch(/There are several options available/i);
});
test('openHelpDialog, should open dialog and add event listeners', () => {
// Given
mockBrowserView.setBounds = jest.fn();
Expand Down
74 changes: 42 additions & 32 deletions src/help/__tests/preload.test.js
Expand Up @@ -16,41 +16,51 @@
const {waitFor} = require('@testing-library/dom');

describe('Help Module preload test suite', () => {
let mockHelp;
beforeEach(() => {
mockHelp = {loadDocs: jest.fn()};
jest.resetModules();
jest.mock('../../main/preload', () => {
global.mainPreloadLoaded = true;
});
jest.mock('../', () => mockHelp);
});
test('preload', () => {
// When
require('../preload');
// Then
expect(global.mainPreloadLoaded).toBe(true);
expect(mockHelp.loadDocs).toHaveBeenCalledTimes(1);
});
test('bulma is loaded', async () => {
// When
require('../preload');
window.document.body.innerHTML = '<div />';
// Then
await waitFor(() => expect(document.querySelector('link[href*="bulma"]')).not.toBeNull());
});
test('fontawesome is loaded', async () => {
// When
require('../preload');
window.document.body.innerHTML = '<div />';
// Then
await waitFor(() => expect(document.querySelector('link[href*="fontawesome"]')).not.toBeNull());
describe('preload (just for coverage and sanity, see bundle tests)', () => {
beforeEach(() => {
jest.mock('../help.browser.css', () => {});
jest.mock('!val-loader!./docs.browser.val-loader', () => ({
docs: {}
}), {virtual: true});
window.APP_EVENTS = {};
window.ELECTRONIM_VERSION = '1.33.7';
require('../preload');
});
test('adds required libraries', () => {
expect(window.ELECTRONIM_VERSION).toEqual('1.33.7');
});
});
test('browser-help is loaded', async () => {
// When
require('../preload');
window.document.body.innerHTML = '<div />';
// Then
await waitFor(() => expect(document.querySelector('link[href*="browser-help"]')).not.toBeNull());
describe('preload.bundle', () => {
beforeEach(() => {
require('../../../bundles/help.preload');
});
test('loads styles in order', async () => {
// When
document.body.append(document.createElement('div'));
// Then
await waitFor(() => expect(document.head.children.length).toBeGreaterThan(0));
const styles = Array.from(document.querySelectorAll('style'));
expect(styles).toHaveLength(1);
expect(styles[0].innerHTML).toContain('.help-root {');
});
test('adds required libraries', () => {
expect(window.ELECTRONIM_VERSION).toEqual('0.0.0');
expect(window.preact).not.toBeUndefined();
expect(window.preactHooks).not.toBeUndefined();
expect(window.html).not.toBeUndefined();
expect(window.TopBar).not.toBeUndefined();
});
test('loads document contents with valid asset URLs', () => {
expect(window.docs).toEqual(expect.objectContaining({
'Keyboard-shortcuts.md': expect.stringMatching(/<h1>Keyboard Shortcuts/i),
'Roadmap.md': expect.any(String),
'Screenshots.md': expect.stringContaining('<img src="../../docs/screenshots/main.png" alt="Main" />'),
'Setup.md': expect.stringMatching(/There are several options available/i),
'Troubleshooting.md': expect.any(String)
}));
});
});
});
39 changes: 39 additions & 0 deletions src/help/docs.browser.val-loader.js
@@ -0,0 +1,39 @@
/*
Copyright 2019 Marc Nuri San Felix
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const fs = require('fs');
const path = require('path');
const md = require('markdown-it')({html: true, xhtmlOut: true}); // NOSONAR

const DOCS_DIR = path.resolve(__dirname, '..', '..', 'docs');
// Should be a relative path from the src/help directory (or wherever index.html is located)
const DOCS_DIR_RELATIVE = '../../docs';

const fixRelativeUrls = s => s.replace(
/((src|href)\s*?=\s*?['"](?!http))([^'"]+)(['"])/gi,
`$1${DOCS_DIR_RELATIVE}/$3$4`
);

const loadDocs = () => fs.readdirSync(DOCS_DIR)
.filter(fileName => fileName.endsWith('.md'))
.reduce((acc, fileName) => {
acc[fileName] = fixRelativeUrls(md.render(fs.readFileSync(path.resolve(DOCS_DIR, fileName), 'utf8')));
return acc;
}, {});

module.exports = () => ({
cacheable: true,
code: `module.exports = {docs: ${JSON.stringify(loadDocs())}};`
});
File renamed without changes.
File renamed without changes.
4 changes: 3 additions & 1 deletion src/help/index.html
Expand Up @@ -23,6 +23,8 @@
</head>
<body>
<div class="help-root"></div>
<script src="./browser-help.js"></script>
<script src="../../bundles/lib/bulma/css/bulma.css.js"></script>
<script src="../../bundles/lib/@fortawesome/fontawesome-free/css/all.css.js"></script>
<script src="./help.browser.js"></script>
</body>
</html>
24 changes: 3 additions & 21 deletions src/help/index.js
Expand Up @@ -14,36 +14,18 @@
limitations under the License.
*/
const {BrowserView} = require('electron');
const fs = require('fs');
const path = require('path');
const md = require('markdown-it')({html: true, xhtmlOut: true});
const {handleRedirect} = require('../tab-manager/redirect');
const {showDialog} = require('../browser-window');

const DOCS_DIR = path.resolve(__dirname, '../../docs');

const webPreferences = {
contextIsolation: false,
nativeWindowOpen: true,
nodeIntegration: false,
sandbox: false,
preload: path.resolve(__dirname, 'preload.js')
sandbox: true,
preload: path.resolve(__dirname, '..', '..', 'bundles', 'help.preload.js')
};

// Visible for testing
const fixRelativeUrls = s => s.replace(
/((src|href)\s*?=\s*?['"](?!http))([^'"]+)(['"])/gi,
`$1${DOCS_DIR}/$3$4`
);

const loadDocs = () => fs.readdirSync(DOCS_DIR)
.filter(fileName => fileName.endsWith('.md'))
.reduce((acc, fileName) => {
acc[fileName] = fixRelativeUrls(md.render(fs.readFileSync(path.resolve(DOCS_DIR, fileName), 'utf8')));
return acc;
}, {});


const openHelpDialog = mainWindow => () => {
const helpView = new BrowserView({webPreferences});
helpView.webContents.loadURL(`file://${__dirname}/index.html`);
Expand All @@ -53,4 +35,4 @@ const openHelpDialog = mainWindow => () => {
showDialog(mainWindow, helpView);
};

module.exports = {fixRelativeUrls, openHelpDialog, loadDocs};
module.exports = {openHelpDialog};
17 changes: 10 additions & 7 deletions src/help/preload.js
Expand Up @@ -13,16 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
require('../main/preload');
const components = require('../components');
/* eslint-disable no-undef */
const {ipcRenderer} = require('electron');
const {docs} = require('!val-loader!./docs.browser.val-loader');
const {topBar} = require('../components/top-bar');

components.bulma();
components.fontAwesome();
components.addStylesheet('./browser-help.css');
require('./help.browser.css');

window.ipcRenderer = ipcRenderer;
window.APP_EVENTS = APP_EVENTS;
window.ELECTRONIM_VERSION = ELECTRONIM_VERSION;
window.preact = require('preact');
window.preactHooks = require('preact/hooks');
window.html = require('htm').bind(window.preact.h);
window.TopBar = components.topBar(window.html);
window.TopBar = topBar(window.html);

window.docs = require('./').loadDocs();
window.docs = docs;
4 changes: 2 additions & 2 deletions webpack.js
Expand Up @@ -25,7 +25,7 @@ const {APP_EVENTS, ELECTRONIM_VERSION} = require('./src/constants');
const BUNDLES_DIR = 'bundles';
const ENTRIES = [
// 'chrome-tabs',
// 'help',
'help'
// 'main',
// 'settings',
// 'tab-manager'
Expand Down Expand Up @@ -72,7 +72,7 @@ const bundle = webpack({
// eslint-disable-next-line prefer-const
let observer;
const callback = () => {
if (document.head) {
if (document && document.head) {
document.head.append(element);
observer.disconnect();
}
Expand Down

0 comments on commit 78f1a60

Please sign in to comment.