diff --git a/src/jsxTransform.js b/src/jsxTransform.js index bbd762d..6b4ef87 100644 --- a/src/jsxTransform.js +++ b/src/jsxTransform.js @@ -55,17 +55,35 @@ function install (options) { require.extensions[options.extension] = function loadJsx (module, filename) { var content = require('fs').readFileSync(filename, 'utf8'); - try { - var instrumented = transform(filename, content, options); - module._compile(instrumented, filename); - } catch (e) { - if (e.originalError) { - throw e.originalError; - } - e.message = 'Error compiling ' + filename + ': ' + e.message; - e.originalError = e; - throw e; - } + var instrumented = tryInstrumenting(filename, content, options); + tryCompiling(module, instrumented, filename); }; installed = true; } + +function tryInstrumenting (filename, content, options) { + try { + var instrumented = transform(filename, content, options); + } catch (e) { + // When instrumenting nested components, we want to see only + // the first, happening in the innermost component + if (e.originalError) { + throw e.originalError; + } + e.message = 'Error compiling ' + filename + ': ' + e.message; + e.originalError = e; + throw e; + } + return instrumented; +} + +function tryCompiling (module, instrumented, filename) { + try { + module._compile(instrumented, filename); + } catch (e) { + // Chrome does not always show the stack trace + // Better show it twice than never + console.error(e.stack); + throw e; + } +} diff --git a/test-integration/hot-reload.spec.js b/test-integration/hot-reload.spec.js index 35d7818..aa4d872 100644 --- a/test-integration/hot-reload.spec.js +++ b/test-integration/hot-reload.spec.js @@ -12,7 +12,7 @@ let rootDir; let cleanup; describe('loadJsx', function () { - this.timeout(10000); + this.timeout(5000); before(() => { cleanup = jsdom(); diff --git a/test/spec/error.spec.js b/test/spec/error.spec.js index 0e9f199..dbbd56b 100644 --- a/test/spec/error.spec.js +++ b/test/spec/error.spec.js @@ -1,14 +1,29 @@ -/* global it,describe,before,after */ +/* global it,describe,before,beforeEach,after,afterEach */ 'use strict'; const expect = require('expect'); +let errors = []; +let savedConsoleError; -describe('loadJsx', () => { +describe('Error handling', () => { before(() => { const electronHot = require('../../src/index'); electronHot.install(); }); + beforeEach(() => { + errors = []; + savedConsoleError = console.error; + console.error = (arg) => errors.push(arg); + }); + + it('should show helpful information', () => { + const exceptionMessage = getExceptionMessage(() => require('./../views/AppUsingErrorScript.jsx')); + expect(exceptionMessage) + .toMatch(/^unknownFunction is not defined$/); + expect(errors[0]).toMatch(/[\w\/\-\\:]+?error\.js:2:1/); + }); + it('should throw when a component contains an error', () => { const exceptionMessage = getExceptionMessage(() => require('./../views/ErrorComponent.jsx')); expect(exceptionMessage) @@ -21,6 +36,11 @@ describe('loadJsx', () => { .toMatch(/^Error compiling [\w\/\-\\:]+?ErrorComponent\.jsx: Parse Error: Line 10: Unexpected token }/); }); + afterEach(() => { + errors = []; + console.error = savedConsoleError; + }); + after(() => { delete require.extensions['.jsx']; }); diff --git a/test/views/AppUsingErrorScript.jsx b/test/views/AppUsingErrorScript.jsx new file mode 100644 index 0000000..ebc1571 --- /dev/null +++ b/test/views/AppUsingErrorScript.jsx @@ -0,0 +1,11 @@ +"use strict"; + +const React = require('react'); +require('./error'); + +module.exports = class App extends React.Component { + + render() { + return
+ } +}; diff --git a/test/views/error.js b/test/views/error.js new file mode 100644 index 0000000..882d22e --- /dev/null +++ b/test/views/error.js @@ -0,0 +1,2 @@ + +unknownFunction('hello');