Skip to content

Commit

Permalink
feat(client/editor-tab): display error tab when editor fails
Browse files Browse the repository at this point in the history
Closes #1214
  • Loading branch information
barmac authored and nikku committed Mar 5, 2019
1 parent dac7300 commit e3815ce
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 60 deletions.
27 changes: 20 additions & 7 deletions client/src/app/tabs/EditorTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,27 @@

import React, { PureComponent } from 'react';

import ErrorTab from './ErrorTab';
import MultiSheetTab from './MultiSheetTab';


export function createTab(tabName, providers) {

class EditorTab extends PureComponent {

static getDerivedStateFromError(error) {
return {
hasError: true
};
}

constructor(props) {
super(props);

this.state = {
hasError: false
};

this.tabRef = React.createRef();
}

Expand All @@ -39,13 +50,15 @@ export function createTab(tabName, providers) {
} = this.props;

return (
<MultiSheetTab
id={ tab.id }
tab={ tab }
{ ...otherProps }
xml={ tab.file.contents }
ref={ this.tabRef }
providers={ providers } />
this.state.hasError ?
<ErrorTab ref={ this.tabRef } /> :
<MultiSheetTab
id={ tab.id }
tab={ tab }
{ ...otherProps }
xml={ tab.file.contents }
ref={ this.tabRef }
providers={ providers } />
);
}

Expand Down
41 changes: 41 additions & 0 deletions client/src/app/tabs/ErrorTab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright (c) Camunda Services GmbH.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import React, { PureComponent } from 'react';

import css from './ErrorTab.less';

import {
TabContainer
} from '../primitives';


export default class ErrorTab extends PureComponent {

triggerAction() {}

render() {
return (
<TabContainer className="content tab">
<div className={ css.ErrorTab }>
<h1>
Unexpected Error
</h1>
<p>
An unexpected error occurred in this tab. Please click the link below to report
an issue on GitHub. You can also save the latest known state of the tab.
</p>
<p>
<a href="https://github.com/camunda/camunda-modeler/issues/new/choose">
Report an issue.
</a>
</p>
</div>
</TabContainer>
);
}
}
18 changes: 18 additions & 0 deletions client/src/app/tabs/ErrorTab.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
:local(.ErrorTab) {

display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
flex: 1;

h1 {
font-size: 26px;
}

p {
font-size: 16px;
max-width: 60%;
text-align: justify;
}
}
58 changes: 48 additions & 10 deletions client/src/app/tabs/__tests__/EditorTabSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,55 @@

import React from 'react';

import { createTab } from './../EditorTab';
import TestRenderer from 'react-test-renderer';

import { mount } from 'enzyme';
import { createTab } from './../EditorTab';
import ErrorTab from './../ErrorTab';

import {
Editor as MockEditor,
providers as defaultProviders,
tab as defaultTab
} from './mocks';

/* global sinon */


describe('<EditorTab>', function() {

describe('render', function() {

it('should render', function() {

// when
const {
instance
} = renderEditorTab();

expect(instance).to.exist;
// then
expect(instance, 'did not render').to.exist;
});

});


describe('error handling', function() {

afterEach(sinon.restore);


it('should display ErrorTab when editor fails', function() {

// given
sinon.stub(MockEditor.prototype, 'render').throwsException();

// when
const {
wrapper
} = renderEditorTab();

// then
verifyChildIsPresent(wrapper, ErrorTab);
});

});
Expand All @@ -39,25 +68,34 @@ describe('<EditorTab>', function() {
function noop() {}

function renderEditorTab({
tab = defaultTab,
onError = noop,
onShown = noop
onShown = noop,
providers = defaultProviders,
tab = defaultTab
} = {}) {

const EditorTab = createTab(defaultTab.name, defaultProviders);
const EditorTab = createTab(tab.name, providers);

const wrapper = mount(
const testRenderer = TestRenderer.create(
<EditorTab
tab={ tab }
onError={ onError }
onShown={ onShown }
/>
);

const instance = wrapper.instance();
const instance = testRenderer.getInstance();

return {
instance,
wrapper
wrapper: testRenderer.root
};
}
}

function verifyChildIsPresent(wrapper, childType) {
function isChildPresent() {
return wrapper.findByType(childType);
}

expect(isChildPresent, `did not display ${childType.name}`).to.not.throw();
}
86 changes: 43 additions & 43 deletions client/src/app/tabs/__tests__/mocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,49 @@
* LICENSE file in the root directory of this source tree.
*/

import React, { Component } from 'react';

export class Editor extends Component {
import React, { Component } from 'react';

export class Editor extends Component {
constructor(props) {
super(props);

this.xml = null;
}

triggerAction() {}

setXML(xml) {
this.xml = xml;
}

getXML() {
return this.xml;
}

render() {
return <div></div>;
}
}

export const providers = [{
type: 'editor',
editor: Editor,
defaultName: 'Editor'
}, {
type: 'fallback',
editor: Editor,
defaultName: 'Fallback',
isFallback: true
}];

export const tab = {
id: 42,
name: 'foo.bar',
type: 'bar',
title: 'unsaved',
file: {
name: 'foo.bar',
contents: '',
path: null
}

this.xml = null;
}

triggerAction() {}

setXML(xml) {
this.xml = xml;
}

getXML() {
return this.xml;
}

render() {
return <div></div>;
}
}

export const providers = [{
type: 'editor',
editor: Editor,
defaultName: 'Editor'
}, {
type: 'fallback',
editor: Editor,
defaultName: 'Fallback',
isFallback: true
}];

export const tab = {
id: 42,
name: 'foo.bar',
type: 'bar',
title: 'unsaved',
file: {
name: 'foo.bar',
contents: '',
path: null
}
};

0 comments on commit e3815ce

Please sign in to comment.