How to use error method in ava

Best JavaScript code snippet using ava

ReactLegacyErrorBoundaries-test.internal.js

Source:ReactLegacyErrorBoundaries-test.internal.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @emails react-core8 */9'use strict';10let PropTypes;11let React;12let ReactDOM;13let ReactFeatureFlags;14// TODO: Refactor this test once componentDidCatch setState is deprecated.15describe('ReactLegacyErrorBoundaries', () => {16  let log;17  let BrokenConstructor;18  let BrokenComponentWillMount;19  let BrokenComponentDidMount;20  let BrokenComponentWillReceiveProps;21  let BrokenComponentWillUpdate;22  let BrokenComponentDidUpdate;23  let BrokenComponentWillUnmount;24  let BrokenRenderErrorBoundary;25  let BrokenComponentWillMountErrorBoundary;26  let BrokenComponentDidMountErrorBoundary;27  let BrokenRender;28  let ErrorBoundary;29  let ErrorMessage;30  let NoopErrorBoundary;31  let RetryErrorBoundary;32  let Normal;33  beforeEach(() => {34    jest.resetModules();35    PropTypes = require('prop-types');36    ReactFeatureFlags = require('shared/ReactFeatureFlags');37    ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;38    ReactDOM = require('react-dom');39    React = require('react');40    log = [];41    BrokenConstructor = class extends React.Component {42      constructor(props) {43        super(props);44        log.push('BrokenConstructor constructor [!]');45        throw new Error('Hello');46      }47      render() {48        log.push('BrokenConstructor render');49        return <div>{this.props.children}</div>;50      }51      UNSAFE_componentWillMount() {52        log.push('BrokenConstructor componentWillMount');53      }54      componentDidMount() {55        log.push('BrokenConstructor componentDidMount');56      }57      UNSAFE_componentWillReceiveProps() {58        log.push('BrokenConstructor componentWillReceiveProps');59      }60      UNSAFE_componentWillUpdate() {61        log.push('BrokenConstructor componentWillUpdate');62      }63      componentDidUpdate() {64        log.push('BrokenConstructor componentDidUpdate');65      }66      componentWillUnmount() {67        log.push('BrokenConstructor componentWillUnmount');68      }69    };70    BrokenComponentWillMount = class extends React.Component {71      constructor(props) {72        super(props);73        log.push('BrokenComponentWillMount constructor');74      }75      render() {76        log.push('BrokenComponentWillMount render');77        return <div>{this.props.children}</div>;78      }79      UNSAFE_componentWillMount() {80        log.push('BrokenComponentWillMount componentWillMount [!]');81        throw new Error('Hello');82      }83      componentDidMount() {84        log.push('BrokenComponentWillMount componentDidMount');85      }86      UNSAFE_componentWillReceiveProps() {87        log.push('BrokenComponentWillMount componentWillReceiveProps');88      }89      UNSAFE_componentWillUpdate() {90        log.push('BrokenComponentWillMount componentWillUpdate');91      }92      componentDidUpdate() {93        log.push('BrokenComponentWillMount componentDidUpdate');94      }95      componentWillUnmount() {96        log.push('BrokenComponentWillMount componentWillUnmount');97      }98    };99    BrokenComponentDidMount = class extends React.Component {100      constructor(props) {101        super(props);102        log.push('BrokenComponentDidMount constructor');103      }104      render() {105        log.push('BrokenComponentDidMount render');106        return <div>{this.props.children}</div>;107      }108      UNSAFE_componentWillMount() {109        log.push('BrokenComponentDidMount componentWillMount');110      }111      componentDidMount() {112        log.push('BrokenComponentDidMount componentDidMount [!]');113        throw new Error('Hello');114      }115      UNSAFE_componentWillReceiveProps() {116        log.push('BrokenComponentDidMount componentWillReceiveProps');117      }118      UNSAFE_componentWillUpdate() {119        log.push('BrokenComponentDidMount componentWillUpdate');120      }121      componentDidUpdate() {122        log.push('BrokenComponentDidMount componentDidUpdate');123      }124      componentWillUnmount() {125        log.push('BrokenComponentDidMount componentWillUnmount');126      }127    };128    BrokenComponentWillReceiveProps = class extends React.Component {129      constructor(props) {130        super(props);131        log.push('BrokenComponentWillReceiveProps constructor');132      }133      render() {134        log.push('BrokenComponentWillReceiveProps render');135        return <div>{this.props.children}</div>;136      }137      UNSAFE_componentWillMount() {138        log.push('BrokenComponentWillReceiveProps componentWillMount');139      }140      componentDidMount() {141        log.push('BrokenComponentWillReceiveProps componentDidMount');142      }143      UNSAFE_componentWillReceiveProps() {144        log.push(145          'BrokenComponentWillReceiveProps componentWillReceiveProps [!]',146        );147        throw new Error('Hello');148      }149      UNSAFE_componentWillUpdate() {150        log.push('BrokenComponentWillReceiveProps componentWillUpdate');151      }152      componentDidUpdate() {153        log.push('BrokenComponentWillReceiveProps componentDidUpdate');154      }155      componentWillUnmount() {156        log.push('BrokenComponentWillReceiveProps componentWillUnmount');157      }158    };159    BrokenComponentWillUpdate = class extends React.Component {160      constructor(props) {161        super(props);162        log.push('BrokenComponentWillUpdate constructor');163      }164      render() {165        log.push('BrokenComponentWillUpdate render');166        return <div>{this.props.children}</div>;167      }168      UNSAFE_componentWillMount() {169        log.push('BrokenComponentWillUpdate componentWillMount');170      }171      componentDidMount() {172        log.push('BrokenComponentWillUpdate componentDidMount');173      }174      UNSAFE_componentWillReceiveProps() {175        log.push('BrokenComponentWillUpdate componentWillReceiveProps');176      }177      UNSAFE_componentWillUpdate() {178        log.push('BrokenComponentWillUpdate componentWillUpdate [!]');179        throw new Error('Hello');180      }181      componentDidUpdate() {182        log.push('BrokenComponentWillUpdate componentDidUpdate');183      }184      componentWillUnmount() {185        log.push('BrokenComponentWillUpdate componentWillUnmount');186      }187    };188    BrokenComponentDidUpdate = class extends React.Component {189      static defaultProps = {190        errorText: 'Hello',191      };192      constructor(props) {193        super(props);194        log.push('BrokenComponentDidUpdate constructor');195      }196      render() {197        log.push('BrokenComponentDidUpdate render');198        return <div>{this.props.children}</div>;199      }200      UNSAFE_componentWillMount() {201        log.push('BrokenComponentDidUpdate componentWillMount');202      }203      componentDidMount() {204        log.push('BrokenComponentDidUpdate componentDidMount');205      }206      UNSAFE_componentWillReceiveProps() {207        log.push('BrokenComponentDidUpdate componentWillReceiveProps');208      }209      UNSAFE_componentWillUpdate() {210        log.push('BrokenComponentDidUpdate componentWillUpdate');211      }212      componentDidUpdate() {213        log.push('BrokenComponentDidUpdate componentDidUpdate [!]');214        throw new Error(this.props.errorText);215      }216      componentWillUnmount() {217        log.push('BrokenComponentDidUpdate componentWillUnmount');218      }219    };220    BrokenComponentWillUnmount = class extends React.Component {221      static defaultProps = {222        errorText: 'Hello',223      };224      constructor(props) {225        super(props);226        log.push('BrokenComponentWillUnmount constructor');227      }228      render() {229        log.push('BrokenComponentWillUnmount render');230        return <div>{this.props.children}</div>;231      }232      UNSAFE_componentWillMount() {233        log.push('BrokenComponentWillUnmount componentWillMount');234      }235      componentDidMount() {236        log.push('BrokenComponentWillUnmount componentDidMount');237      }238      UNSAFE_componentWillReceiveProps() {239        log.push('BrokenComponentWillUnmount componentWillReceiveProps');240      }241      UNSAFE_componentWillUpdate() {242        log.push('BrokenComponentWillUnmount componentWillUpdate');243      }244      componentDidUpdate() {245        log.push('BrokenComponentWillUnmount componentDidUpdate');246      }247      componentWillUnmount() {248        log.push('BrokenComponentWillUnmount componentWillUnmount [!]');249        throw new Error(this.props.errorText);250      }251    };252    BrokenComponentWillMountErrorBoundary = class extends React.Component {253      constructor(props) {254        super(props);255        this.state = {error: null};256        log.push('BrokenComponentWillMountErrorBoundary constructor');257      }258      render() {259        if (this.state.error) {260          log.push('BrokenComponentWillMountErrorBoundary render error');261          return <div>Caught an error: {this.state.error.message}.</div>;262        }263        log.push('BrokenComponentWillMountErrorBoundary render success');264        return <div>{this.props.children}</div>;265      }266      UNSAFE_componentWillMount() {267        log.push(268          'BrokenComponentWillMountErrorBoundary componentWillMount [!]',269        );270        throw new Error('Hello');271      }272      componentDidMount() {273        log.push('BrokenComponentWillMountErrorBoundary componentDidMount');274      }275      componentWillUnmount() {276        log.push('BrokenComponentWillMountErrorBoundary componentWillUnmount');277      }278      componentDidCatch(error) {279        log.push('BrokenComponentWillMountErrorBoundary componentDidCatch');280        this.setState({error});281      }282    };283    BrokenComponentDidMountErrorBoundary = class extends React.Component {284      constructor(props) {285        super(props);286        this.state = {error: null};287        log.push('BrokenComponentDidMountErrorBoundary constructor');288      }289      render() {290        if (this.state.error) {291          log.push('BrokenComponentDidMountErrorBoundary render error');292          return <div>Caught an error: {this.state.error.message}.</div>;293        }294        log.push('BrokenComponentDidMountErrorBoundary render success');295        return <div>{this.props.children}</div>;296      }297      UNSAFE_componentWillMount() {298        log.push('BrokenComponentDidMountErrorBoundary componentWillMount');299      }300      componentDidMount() {301        log.push('BrokenComponentDidMountErrorBoundary componentDidMount [!]');302        throw new Error('Hello');303      }304      componentWillUnmount() {305        log.push('BrokenComponentDidMountErrorBoundary componentWillUnmount');306      }307      componentDidCatch(error) {308        log.push('BrokenComponentDidMountErrorBoundary componentDidCatch');309        this.setState({error});310      }311    };312    BrokenRenderErrorBoundary = class extends React.Component {313      constructor(props) {314        super(props);315        this.state = {error: null};316        log.push('BrokenRenderErrorBoundary constructor');317      }318      render() {319        if (this.state.error) {320          log.push('BrokenRenderErrorBoundary render error [!]');321          throw new Error('Hello');322        }323        log.push('BrokenRenderErrorBoundary render success');324        return <div>{this.props.children}</div>;325      }326      UNSAFE_componentWillMount() {327        log.push('BrokenRenderErrorBoundary componentWillMount');328      }329      componentDidMount() {330        log.push('BrokenRenderErrorBoundary componentDidMount');331      }332      componentWillUnmount() {333        log.push('BrokenRenderErrorBoundary componentWillUnmount');334      }335      componentDidCatch(error) {336        log.push('BrokenRenderErrorBoundary componentDidCatch');337        this.setState({error});338      }339    };340    BrokenRender = class extends React.Component {341      constructor(props) {342        super(props);343        log.push('BrokenRender constructor');344      }345      render() {346        log.push('BrokenRender render [!]');347        throw new Error('Hello');348      }349      UNSAFE_componentWillMount() {350        log.push('BrokenRender componentWillMount');351      }352      componentDidMount() {353        log.push('BrokenRender componentDidMount');354      }355      UNSAFE_componentWillReceiveProps() {356        log.push('BrokenRender componentWillReceiveProps');357      }358      UNSAFE_componentWillUpdate() {359        log.push('BrokenRender componentWillUpdate');360      }361      componentDidUpdate() {362        log.push('BrokenRender componentDidUpdate');363      }364      componentWillUnmount() {365        log.push('BrokenRender componentWillUnmount');366      }367    };368    NoopErrorBoundary = class extends React.Component {369      constructor(props) {370        super(props);371        log.push('NoopErrorBoundary constructor');372      }373      render() {374        log.push('NoopErrorBoundary render');375        return <BrokenRender />;376      }377      UNSAFE_componentWillMount() {378        log.push('NoopErrorBoundary componentWillMount');379      }380      componentDidMount() {381        log.push('NoopErrorBoundary componentDidMount');382      }383      componentWillUnmount() {384        log.push('NoopErrorBoundary componentWillUnmount');385      }386      componentDidCatch() {387        log.push('NoopErrorBoundary componentDidCatch');388      }389    };390    Normal = class extends React.Component {391      static defaultProps = {392        logName: 'Normal',393      };394      constructor(props) {395        super(props);396        log.push(`${this.props.logName} constructor`);397      }398      render() {399        log.push(`${this.props.logName} render`);400        return <div>{this.props.children}</div>;401      }402      UNSAFE_componentWillMount() {403        log.push(`${this.props.logName} componentWillMount`);404      }405      componentDidMount() {406        log.push(`${this.props.logName} componentDidMount`);407      }408      UNSAFE_componentWillReceiveProps() {409        log.push(`${this.props.logName} componentWillReceiveProps`);410      }411      UNSAFE_componentWillUpdate() {412        log.push(`${this.props.logName} componentWillUpdate`);413      }414      componentDidUpdate() {415        log.push(`${this.props.logName} componentDidUpdate`);416      }417      componentWillUnmount() {418        log.push(`${this.props.logName} componentWillUnmount`);419      }420    };421    ErrorBoundary = class extends React.Component {422      constructor(props) {423        super(props);424        this.state = {error: null};425        log.push(`${this.props.logName} constructor`);426      }427      render() {428        if (this.state.error && !this.props.forceRetry) {429          log.push(`${this.props.logName} render error`);430          return this.props.renderError(this.state.error, this.props);431        }432        log.push(`${this.props.logName} render success`);433        return <div>{this.props.children}</div>;434      }435      componentDidCatch(error) {436        log.push(`${this.props.logName} componentDidCatch`);437        this.setState({error});438      }439      UNSAFE_componentWillMount() {440        log.push(`${this.props.logName} componentWillMount`);441      }442      componentDidMount() {443        log.push(`${this.props.logName} componentDidMount`);444      }445      UNSAFE_componentWillReceiveProps() {446        log.push(`${this.props.logName} componentWillReceiveProps`);447      }448      UNSAFE_componentWillUpdate() {449        log.push(`${this.props.logName} componentWillUpdate`);450      }451      componentDidUpdate() {452        log.push(`${this.props.logName} componentDidUpdate`);453      }454      componentWillUnmount() {455        log.push(`${this.props.logName} componentWillUnmount`);456      }457    };458    ErrorBoundary.defaultProps = {459      logName: 'ErrorBoundary',460      renderError(error, props) {461        return (462          <div ref={props.errorMessageRef}>463            Caught an error: {error.message}.464          </div>465        );466      },467    };468    RetryErrorBoundary = class extends React.Component {469      constructor(props) {470        super(props);471        log.push('RetryErrorBoundary constructor');472      }473      render() {474        log.push('RetryErrorBoundary render');475        return <BrokenRender />;476      }477      UNSAFE_componentWillMount() {478        log.push('RetryErrorBoundary componentWillMount');479      }480      componentDidMount() {481        log.push('RetryErrorBoundary componentDidMount');482      }483      componentWillUnmount() {484        log.push('RetryErrorBoundary componentWillUnmount');485      }486      componentDidCatch(error) {487        log.push('RetryErrorBoundary componentDidCatch [!]');488        // In Fiber, calling setState() (and failing) is treated as a rethrow.489        this.setState({});490      }491    };492    ErrorMessage = class extends React.Component {493      constructor(props) {494        super(props);495        log.push('ErrorMessage constructor');496      }497      UNSAFE_componentWillMount() {498        log.push('ErrorMessage componentWillMount');499      }500      componentDidMount() {501        log.push('ErrorMessage componentDidMount');502      }503      componentWillUnmount() {504        log.push('ErrorMessage componentWillUnmount');505      }506      render() {507        log.push('ErrorMessage render');508        return <div>Caught an error: {this.props.message}.</div>;509      }510    };511  });512  it('does not swallow exceptions on mounting without boundaries', () => {513    let container = document.createElement('div');514    expect(() => {515      ReactDOM.render(<BrokenRender />, container);516    }).toThrow('Hello');517    container = document.createElement('div');518    expect(() => {519      ReactDOM.render(<BrokenComponentWillMount />, container);520    }).toThrow('Hello');521    container = document.createElement('div');522    expect(() => {523      ReactDOM.render(<BrokenComponentDidMount />, container);524    }).toThrow('Hello');525  });526  it('does not swallow exceptions on updating without boundaries', () => {527    let container = document.createElement('div');528    ReactDOM.render(<BrokenComponentWillUpdate />, container);529    expect(() => {530      ReactDOM.render(<BrokenComponentWillUpdate />, container);531    }).toThrow('Hello');532    container = document.createElement('div');533    ReactDOM.render(<BrokenComponentWillReceiveProps />, container);534    expect(() => {535      ReactDOM.render(<BrokenComponentWillReceiveProps />, container);536    }).toThrow('Hello');537    container = document.createElement('div');538    ReactDOM.render(<BrokenComponentDidUpdate />, container);539    expect(() => {540      ReactDOM.render(<BrokenComponentDidUpdate />, container);541    }).toThrow('Hello');542  });543  it('does not swallow exceptions on unmounting without boundaries', () => {544    const container = document.createElement('div');545    ReactDOM.render(<BrokenComponentWillUnmount />, container);546    expect(() => {547      ReactDOM.unmountComponentAtNode(container);548    }).toThrow('Hello');549  });550  it('prevents errors from leaking into other roots', () => {551    const container1 = document.createElement('div');552    const container2 = document.createElement('div');553    const container3 = document.createElement('div');554    ReactDOM.render(<span>Before 1</span>, container1);555    expect(() => {556      ReactDOM.render(<BrokenRender />, container2);557    }).toThrow('Hello');558    ReactDOM.render(559      <ErrorBoundary>560        <BrokenRender />561      </ErrorBoundary>,562      container3,563    );564    expect(container1.firstChild.textContent).toBe('Before 1');565    expect(container2.firstChild).toBe(null);566    expect(container3.firstChild.textContent).toBe('Caught an error: Hello.');567    ReactDOM.render(<span>After 1</span>, container1);568    ReactDOM.render(<span>After 2</span>, container2);569    ReactDOM.render(570      <ErrorBoundary forceRetry={true}>After 3</ErrorBoundary>,571      container3,572    );573    expect(container1.firstChild.textContent).toBe('After 1');574    expect(container2.firstChild.textContent).toBe('After 2');575    expect(container3.firstChild.textContent).toBe('After 3');576    ReactDOM.unmountComponentAtNode(container1);577    ReactDOM.unmountComponentAtNode(container2);578    ReactDOM.unmountComponentAtNode(container3);579    expect(container1.firstChild).toBe(null);580    expect(container2.firstChild).toBe(null);581    expect(container3.firstChild).toBe(null);582  });583  it('renders an error state if child throws in render', () => {584    const container = document.createElement('div');585    ReactDOM.render(586      <ErrorBoundary>587        <BrokenRender />588      </ErrorBoundary>,589      container,590    );591    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');592    expect(log).toEqual([593      'ErrorBoundary constructor',594      'ErrorBoundary componentWillMount',595      'ErrorBoundary render success',596      'BrokenRender constructor',597      'BrokenRender componentWillMount',598      'BrokenRender render [!]',599      // Fiber mounts with null children before capturing error600      'ErrorBoundary componentDidMount',601      // Catch and render an error message602      'ErrorBoundary componentDidCatch',603      'ErrorBoundary componentWillUpdate',604      'ErrorBoundary render error',605      'ErrorBoundary componentDidUpdate',606    ]);607    log.length = 0;608    ReactDOM.unmountComponentAtNode(container);609    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);610  });611  it('renders an error state if child throws in constructor', () => {612    const container = document.createElement('div');613    ReactDOM.render(614      <ErrorBoundary>615        <BrokenConstructor />616      </ErrorBoundary>,617      container,618    );619    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');620    expect(log).toEqual([621      'ErrorBoundary constructor',622      'ErrorBoundary componentWillMount',623      'ErrorBoundary render success',624      'BrokenConstructor constructor [!]',625      // Fiber mounts with null children before capturing error626      'ErrorBoundary componentDidMount',627      // Catch and render an error message628      'ErrorBoundary componentDidCatch',629      'ErrorBoundary componentWillUpdate',630      'ErrorBoundary render error',631      'ErrorBoundary componentDidUpdate',632    ]);633    log.length = 0;634    ReactDOM.unmountComponentAtNode(container);635    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);636  });637  it('renders an error state if child throws in componentWillMount', () => {638    const container = document.createElement('div');639    ReactDOM.render(640      <ErrorBoundary>641        <BrokenComponentWillMount />642      </ErrorBoundary>,643      container,644    );645    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');646    expect(log).toEqual([647      'ErrorBoundary constructor',648      'ErrorBoundary componentWillMount',649      'ErrorBoundary render success',650      'BrokenComponentWillMount constructor',651      'BrokenComponentWillMount componentWillMount [!]',652      'ErrorBoundary componentDidMount',653      'ErrorBoundary componentDidCatch',654      'ErrorBoundary componentWillUpdate',655      'ErrorBoundary render error',656      'ErrorBoundary componentDidUpdate',657    ]);658    log.length = 0;659    ReactDOM.unmountComponentAtNode(container);660    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);661  });662  it('renders an error state if context provider throws in componentWillMount', () => {663    class BrokenComponentWillMountWithContext extends React.Component {664      static childContextTypes = {foo: PropTypes.number};665      getChildContext() {666        return {foo: 42};667      }668      render() {669        return <div>{this.props.children}</div>;670      }671      UNSAFE_componentWillMount() {672        throw new Error('Hello');673      }674    }675    const container = document.createElement('div');676    ReactDOM.render(677      <ErrorBoundary>678        <BrokenComponentWillMountWithContext />679      </ErrorBoundary>,680      container,681    );682    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');683  });684  it('renders an error state if module-style context provider throws in componentWillMount', () => {685    function BrokenComponentWillMountWithContext() {686      return {687        getChildContext() {688          return {foo: 42};689        },690        render() {691          return <div>{this.props.children}</div>;692        },693        UNSAFE_componentWillMount() {694          throw new Error('Hello');695        },696      };697    }698    BrokenComponentWillMountWithContext.childContextTypes = {699      foo: PropTypes.number,700    };701    const container = document.createElement('div');702    ReactDOM.render(703      <ErrorBoundary>704        <BrokenComponentWillMountWithContext />705      </ErrorBoundary>,706      container,707    );708    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');709  });710  it('mounts the error message if mounting fails', () => {711    function renderError(error) {712      return <ErrorMessage message={error.message} />;713    }714    const container = document.createElement('div');715    ReactDOM.render(716      <ErrorBoundary renderError={renderError}>717        <BrokenRender />718      </ErrorBoundary>,719      container,720    );721    expect(log).toEqual([722      'ErrorBoundary constructor',723      'ErrorBoundary componentWillMount',724      'ErrorBoundary render success',725      'BrokenRender constructor',726      'BrokenRender componentWillMount',727      'BrokenRender render [!]',728      'ErrorBoundary componentDidMount',729      'ErrorBoundary componentDidCatch',730      'ErrorBoundary componentWillUpdate',731      'ErrorBoundary render error',732      'ErrorMessage constructor',733      'ErrorMessage componentWillMount',734      'ErrorMessage render',735      'ErrorMessage componentDidMount',736      'ErrorBoundary componentDidUpdate',737    ]);738    log.length = 0;739    ReactDOM.unmountComponentAtNode(container);740    expect(log).toEqual([741      'ErrorBoundary componentWillUnmount',742      'ErrorMessage componentWillUnmount',743    ]);744  });745  it('propagates errors on retry on mounting', () => {746    const container = document.createElement('div');747    ReactDOM.render(748      <ErrorBoundary>749        <RetryErrorBoundary>750          <BrokenRender />751        </RetryErrorBoundary>752      </ErrorBoundary>,753      container,754    );755    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');756    expect(log).toEqual([757      'ErrorBoundary constructor',758      'ErrorBoundary componentWillMount',759      'ErrorBoundary render success',760      'RetryErrorBoundary constructor',761      'RetryErrorBoundary componentWillMount',762      'RetryErrorBoundary render',763      'BrokenRender constructor',764      'BrokenRender componentWillMount',765      'BrokenRender render [!]',766      // In Fiber, failed error boundaries render null before attempting to recover767      'RetryErrorBoundary componentDidMount',768      'RetryErrorBoundary componentDidCatch [!]',769      'ErrorBoundary componentDidMount',770      // Retry771      'RetryErrorBoundary render',772      'BrokenRender constructor',773      'BrokenRender componentWillMount',774      'BrokenRender render [!]',775      // This time, the error propagates to the higher boundary776      'RetryErrorBoundary componentWillUnmount',777      'ErrorBoundary componentDidCatch',778      // Render the error779      'ErrorBoundary componentWillUpdate',780      'ErrorBoundary render error',781      'ErrorBoundary componentDidUpdate',782    ]);783    log.length = 0;784    ReactDOM.unmountComponentAtNode(container);785    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);786  });787  it('propagates errors inside boundary during componentWillMount', () => {788    const container = document.createElement('div');789    ReactDOM.render(790      <ErrorBoundary>791        <BrokenComponentWillMountErrorBoundary />792      </ErrorBoundary>,793      container,794    );795    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');796    expect(log).toEqual([797      'ErrorBoundary constructor',798      'ErrorBoundary componentWillMount',799      'ErrorBoundary render success',800      'BrokenComponentWillMountErrorBoundary constructor',801      'BrokenComponentWillMountErrorBoundary componentWillMount [!]',802      // The error propagates to the higher boundary803      'ErrorBoundary componentDidMount',804      'ErrorBoundary componentDidCatch',805      'ErrorBoundary componentWillUpdate',806      'ErrorBoundary render error',807      'ErrorBoundary componentDidUpdate',808    ]);809    log.length = 0;810    ReactDOM.unmountComponentAtNode(container);811    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);812  });813  it('propagates errors inside boundary while rendering error state', () => {814    const container = document.createElement('div');815    ReactDOM.render(816      <ErrorBoundary>817        <BrokenRenderErrorBoundary>818          <BrokenRender />819        </BrokenRenderErrorBoundary>820      </ErrorBoundary>,821      container,822    );823    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');824    expect(log).toEqual([825      'ErrorBoundary constructor',826      'ErrorBoundary componentWillMount',827      'ErrorBoundary render success',828      'BrokenRenderErrorBoundary constructor',829      'BrokenRenderErrorBoundary componentWillMount',830      'BrokenRenderErrorBoundary render success',831      'BrokenRender constructor',832      'BrokenRender componentWillMount',833      'BrokenRender render [!]',834      // The first error boundary catches the error835      // It adjusts state but throws displaying the message836      // Finish mounting with null children837      'BrokenRenderErrorBoundary componentDidMount',838      // Attempt to handle the error839      'BrokenRenderErrorBoundary componentDidCatch',840      'ErrorBoundary componentDidMount',841      'BrokenRenderErrorBoundary render error [!]',842      // Boundary fails with new error, propagate to next boundary843      'BrokenRenderErrorBoundary componentWillUnmount',844      // Attempt to handle the error again845      'ErrorBoundary componentDidCatch',846      'ErrorBoundary componentWillUpdate',847      'ErrorBoundary render error',848      'ErrorBoundary componentDidUpdate',849    ]);850    log.length = 0;851    ReactDOM.unmountComponentAtNode(container);852    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);853  });854  it('does not call componentWillUnmount when aborting initial mount', () => {855    const container = document.createElement('div');856    ReactDOM.render(857      <ErrorBoundary>858        <Normal />859        <BrokenRender />860        <Normal />861      </ErrorBoundary>,862      container,863    );864    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');865    expect(log).toEqual([866      'ErrorBoundary constructor',867      'ErrorBoundary componentWillMount',868      'ErrorBoundary render success',869      // Render first child870      'Normal constructor',871      'Normal componentWillMount',872      'Normal render',873      // Render second child (it throws)874      'BrokenRender constructor',875      'BrokenRender componentWillMount',876      'BrokenRender render [!]',877      // Render third child, even though an earlier sibling threw.878      'Normal constructor',879      'Normal componentWillMount',880      'Normal render',881      // Finish mounting with null children882      'ErrorBoundary componentDidMount',883      // Handle the error884      'ErrorBoundary componentDidCatch',885      // Render the error message886      'ErrorBoundary componentWillUpdate',887      'ErrorBoundary render error',888      'ErrorBoundary componentDidUpdate',889    ]);890    log.length = 0;891    ReactDOM.unmountComponentAtNode(container);892    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);893  });894  it('resets callback refs if mounting aborts', () => {895    function childRef(x) {896      log.push('Child ref is set to ' + x);897    }898    function errorMessageRef(x) {899      log.push('Error message ref is set to ' + x);900    }901    const container = document.createElement('div');902    ReactDOM.render(903      <ErrorBoundary errorMessageRef={errorMessageRef}>904        <div ref={childRef} />905        <BrokenRender />906      </ErrorBoundary>,907      container,908    );909    expect(container.textContent).toBe('Caught an error: Hello.');910    expect(log).toEqual([911      'ErrorBoundary constructor',912      'ErrorBoundary componentWillMount',913      'ErrorBoundary render success',914      'BrokenRender constructor',915      'BrokenRender componentWillMount',916      'BrokenRender render [!]',917      // Handle error:918      // Finish mounting with null children919      'ErrorBoundary componentDidMount',920      // Handle the error921      'ErrorBoundary componentDidCatch',922      // Render the error message923      'ErrorBoundary componentWillUpdate',924      'ErrorBoundary render error',925      'Error message ref is set to [object HTMLDivElement]',926      'ErrorBoundary componentDidUpdate',927    ]);928    log.length = 0;929    ReactDOM.unmountComponentAtNode(container);930    expect(log).toEqual([931      'ErrorBoundary componentWillUnmount',932      'Error message ref is set to null',933    ]);934  });935  it('resets object refs if mounting aborts', () => {936    let childRef = React.createRef();937    let errorMessageRef = React.createRef();938    const container = document.createElement('div');939    ReactDOM.render(940      <ErrorBoundary errorMessageRef={errorMessageRef}>941        <div ref={childRef} />942        <BrokenRender />943      </ErrorBoundary>,944      container,945    );946    expect(container.textContent).toBe('Caught an error: Hello.');947    expect(log).toEqual([948      'ErrorBoundary constructor',949      'ErrorBoundary componentWillMount',950      'ErrorBoundary render success',951      'BrokenRender constructor',952      'BrokenRender componentWillMount',953      'BrokenRender render [!]',954      // Handle error:955      // Finish mounting with null children956      'ErrorBoundary componentDidMount',957      // Handle the error958      'ErrorBoundary componentDidCatch',959      // Render the error message960      'ErrorBoundary componentWillUpdate',961      'ErrorBoundary render error',962      'ErrorBoundary componentDidUpdate',963    ]);964    expect(errorMessageRef.current.toString()).toEqual(965      '[object HTMLDivElement]',966    );967    log.length = 0;968    ReactDOM.unmountComponentAtNode(container);969    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);970    expect(errorMessageRef.current).toEqual(null);971  });972  it('successfully mounts if no error occurs', () => {973    const container = document.createElement('div');974    ReactDOM.render(975      <ErrorBoundary>976        <div>Mounted successfully.</div>977      </ErrorBoundary>,978      container,979    );980    expect(container.firstChild.textContent).toBe('Mounted successfully.');981    expect(log).toEqual([982      'ErrorBoundary constructor',983      'ErrorBoundary componentWillMount',984      'ErrorBoundary render success',985      'ErrorBoundary componentDidMount',986    ]);987    log.length = 0;988    ReactDOM.unmountComponentAtNode(container);989    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);990  });991  it('catches if child throws in constructor during update', () => {992    const container = document.createElement('div');993    ReactDOM.render(994      <ErrorBoundary>995        <Normal />996      </ErrorBoundary>,997      container,998    );999    log.length = 0;1000    ReactDOM.render(1001      <ErrorBoundary>1002        <Normal />1003        <Normal logName="Normal2" />1004        <BrokenConstructor />1005      </ErrorBoundary>,1006      container,1007    );1008    expect(container.textContent).toBe('Caught an error: Hello.');1009    expect(log).toEqual([1010      'ErrorBoundary componentWillReceiveProps',1011      'ErrorBoundary componentWillUpdate',1012      'ErrorBoundary render success',1013      'Normal componentWillReceiveProps',1014      'Normal componentWillUpdate',1015      'Normal render',1016      // Normal2 will attempt to mount:1017      'Normal2 constructor',1018      'Normal2 componentWillMount',1019      'Normal2 render',1020      // BrokenConstructor will abort rendering:1021      'BrokenConstructor constructor [!]',1022      // Finish updating with null children1023      'Normal componentWillUnmount',1024      'ErrorBoundary componentDidUpdate',1025      // Handle the error1026      'ErrorBoundary componentDidCatch',1027      // Render the error message1028      'ErrorBoundary componentWillUpdate',1029      'ErrorBoundary render error',1030      'ErrorBoundary componentDidUpdate',1031    ]);1032    log.length = 0;1033    ReactDOM.unmountComponentAtNode(container);1034    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1035  });1036  it('catches if child throws in componentWillMount during update', () => {1037    const container = document.createElement('div');1038    ReactDOM.render(1039      <ErrorBoundary>1040        <Normal />1041      </ErrorBoundary>,1042      container,1043    );1044    log.length = 0;1045    ReactDOM.render(1046      <ErrorBoundary>1047        <Normal />1048        <Normal logName="Normal2" />1049        <BrokenComponentWillMount />1050      </ErrorBoundary>,1051      container,1052    );1053    expect(container.textContent).toBe('Caught an error: Hello.');1054    expect(log).toEqual([1055      'ErrorBoundary componentWillReceiveProps',1056      'ErrorBoundary componentWillUpdate',1057      'ErrorBoundary render success',1058      'Normal componentWillReceiveProps',1059      'Normal componentWillUpdate',1060      'Normal render',1061      // Normal2 will attempt to mount:1062      'Normal2 constructor',1063      'Normal2 componentWillMount',1064      'Normal2 render',1065      // BrokenComponentWillMount will abort rendering:1066      'BrokenComponentWillMount constructor',1067      'BrokenComponentWillMount componentWillMount [!]',1068      // Finish updating with null children1069      'Normal componentWillUnmount',1070      'ErrorBoundary componentDidUpdate',1071      // Handle the error1072      'ErrorBoundary componentDidCatch',1073      // Render the error message1074      'ErrorBoundary componentWillUpdate',1075      'ErrorBoundary render error',1076      'ErrorBoundary componentDidUpdate',1077    ]);1078    log.length = 0;1079    ReactDOM.unmountComponentAtNode(container);1080    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1081  });1082  it('catches if child throws in componentWillReceiveProps during update', () => {1083    const container = document.createElement('div');1084    ReactDOM.render(1085      <ErrorBoundary>1086        <Normal />1087        <BrokenComponentWillReceiveProps />1088      </ErrorBoundary>,1089      container,1090    );1091    log.length = 0;1092    ReactDOM.render(1093      <ErrorBoundary>1094        <Normal />1095        <BrokenComponentWillReceiveProps />1096      </ErrorBoundary>,1097      container,1098    );1099    expect(container.textContent).toBe('Caught an error: Hello.');1100    expect(log).toEqual([1101      'ErrorBoundary componentWillReceiveProps',1102      'ErrorBoundary componentWillUpdate',1103      'ErrorBoundary render success',1104      'Normal componentWillReceiveProps',1105      'Normal componentWillUpdate',1106      'Normal render',1107      // BrokenComponentWillReceiveProps will abort rendering:1108      'BrokenComponentWillReceiveProps componentWillReceiveProps [!]',1109      // Finish updating with null children1110      'Normal componentWillUnmount',1111      'BrokenComponentWillReceiveProps componentWillUnmount',1112      'ErrorBoundary componentDidUpdate',1113      // Handle the error1114      'ErrorBoundary componentDidCatch',1115      'ErrorBoundary componentWillUpdate',1116      'ErrorBoundary render error',1117      'ErrorBoundary componentDidUpdate',1118    ]);1119    log.length = 0;1120    ReactDOM.unmountComponentAtNode(container);1121    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1122  });1123  it('catches if child throws in componentWillUpdate during update', () => {1124    const container = document.createElement('div');1125    ReactDOM.render(1126      <ErrorBoundary>1127        <Normal />1128        <BrokenComponentWillUpdate />1129      </ErrorBoundary>,1130      container,1131    );1132    log.length = 0;1133    ReactDOM.render(1134      <ErrorBoundary>1135        <Normal />1136        <BrokenComponentWillUpdate />1137      </ErrorBoundary>,1138      container,1139    );1140    expect(container.textContent).toBe('Caught an error: Hello.');1141    expect(log).toEqual([1142      'ErrorBoundary componentWillReceiveProps',1143      'ErrorBoundary componentWillUpdate',1144      'ErrorBoundary render success',1145      'Normal componentWillReceiveProps',1146      'Normal componentWillUpdate',1147      'Normal render',1148      // BrokenComponentWillUpdate will abort rendering:1149      'BrokenComponentWillUpdate componentWillReceiveProps',1150      'BrokenComponentWillUpdate componentWillUpdate [!]',1151      // Finish updating with null children1152      'Normal componentWillUnmount',1153      'BrokenComponentWillUpdate componentWillUnmount',1154      'ErrorBoundary componentDidUpdate',1155      // Handle the error1156      'ErrorBoundary componentDidCatch',1157      'ErrorBoundary componentWillUpdate',1158      'ErrorBoundary render error',1159      'ErrorBoundary componentDidUpdate',1160    ]);1161    log.length = 0;1162    ReactDOM.unmountComponentAtNode(container);1163    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1164  });1165  it('catches if child throws in render during update', () => {1166    const container = document.createElement('div');1167    ReactDOM.render(1168      <ErrorBoundary>1169        <Normal />1170      </ErrorBoundary>,1171      container,1172    );1173    log.length = 0;1174    ReactDOM.render(1175      <ErrorBoundary>1176        <Normal />1177        <Normal logName="Normal2" />1178        <BrokenRender />1179      </ErrorBoundary>,1180      container,1181    );1182    expect(container.textContent).toBe('Caught an error: Hello.');1183    expect(log).toEqual([1184      'ErrorBoundary componentWillReceiveProps',1185      'ErrorBoundary componentWillUpdate',1186      'ErrorBoundary render success',1187      'Normal componentWillReceiveProps',1188      'Normal componentWillUpdate',1189      'Normal render',1190      // Normal2 will attempt to mount:1191      'Normal2 constructor',1192      'Normal2 componentWillMount',1193      'Normal2 render',1194      // BrokenRender will abort rendering:1195      'BrokenRender constructor',1196      'BrokenRender componentWillMount',1197      'BrokenRender render [!]',1198      // Finish updating with null children1199      'Normal componentWillUnmount',1200      'ErrorBoundary componentDidUpdate',1201      // Handle the error1202      'ErrorBoundary componentDidCatch',1203      'ErrorBoundary componentWillUpdate',1204      'ErrorBoundary render error',1205      'ErrorBoundary componentDidUpdate',1206    ]);1207    log.length = 0;1208    ReactDOM.unmountComponentAtNode(container);1209    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1210  });1211  it('keeps refs up-to-date during updates', () => {1212    function child1Ref(x) {1213      log.push('Child1 ref is set to ' + x);1214    }1215    function child2Ref(x) {1216      log.push('Child2 ref is set to ' + x);1217    }1218    function errorMessageRef(x) {1219      log.push('Error message ref is set to ' + x);1220    }1221    const container = document.createElement('div');1222    ReactDOM.render(1223      <ErrorBoundary errorMessageRef={errorMessageRef}>1224        <div ref={child1Ref} />1225      </ErrorBoundary>,1226      container,1227    );1228    expect(log).toEqual([1229      'ErrorBoundary constructor',1230      'ErrorBoundary componentWillMount',1231      'ErrorBoundary render success',1232      'Child1 ref is set to [object HTMLDivElement]',1233      'ErrorBoundary componentDidMount',1234    ]);1235    log.length = 0;1236    ReactDOM.render(1237      <ErrorBoundary errorMessageRef={errorMessageRef}>1238        <div ref={child1Ref} />1239        <div ref={child2Ref} />1240        <BrokenRender />1241      </ErrorBoundary>,1242      container,1243    );1244    expect(container.textContent).toBe('Caught an error: Hello.');1245    expect(log).toEqual([1246      'ErrorBoundary componentWillReceiveProps',1247      'ErrorBoundary componentWillUpdate',1248      'ErrorBoundary render success',1249      // BrokenRender will abort rendering:1250      'BrokenRender constructor',1251      'BrokenRender componentWillMount',1252      'BrokenRender render [!]',1253      // Finish updating with null children1254      'Child1 ref is set to null',1255      'ErrorBoundary componentDidUpdate',1256      // Handle the error1257      'ErrorBoundary componentDidCatch',1258      'ErrorBoundary componentWillUpdate',1259      'ErrorBoundary render error',1260      'Error message ref is set to [object HTMLDivElement]',1261      // Child2 ref is never set because its mounting aborted1262      'ErrorBoundary componentDidUpdate',1263    ]);1264    log.length = 0;1265    ReactDOM.unmountComponentAtNode(container);1266    expect(log).toEqual([1267      'ErrorBoundary componentWillUnmount',1268      'Error message ref is set to null',1269    ]);1270  });1271  it('recovers from componentWillUnmount errors on update', () => {1272    const container = document.createElement('div');1273    ReactDOM.render(1274      <ErrorBoundary>1275        <BrokenComponentWillUnmount />1276        <BrokenComponentWillUnmount />1277        <Normal />1278      </ErrorBoundary>,1279      container,1280    );1281    log.length = 0;1282    ReactDOM.render(1283      <ErrorBoundary>1284        <BrokenComponentWillUnmount />1285      </ErrorBoundary>,1286      container,1287    );1288    expect(container.textContent).toBe('Caught an error: Hello.');1289    expect(log).toEqual([1290      'ErrorBoundary componentWillReceiveProps',1291      'ErrorBoundary componentWillUpdate',1292      'ErrorBoundary render success',1293      // Update existing child:1294      'BrokenComponentWillUnmount componentWillReceiveProps',1295      'BrokenComponentWillUnmount componentWillUpdate',1296      'BrokenComponentWillUnmount render',1297      // Unmounting throws:1298      'BrokenComponentWillUnmount componentWillUnmount [!]',1299      // Fiber proceeds with lifecycles despite errors1300      'Normal componentWillUnmount',1301      // The components have updated in this phase1302      'BrokenComponentWillUnmount componentDidUpdate',1303      'ErrorBoundary componentDidUpdate',1304      // Now that commit phase is done, Fiber unmounts the boundary's children1305      'BrokenComponentWillUnmount componentWillUnmount [!]',1306      'ErrorBoundary componentDidCatch',1307      // The initial render was aborted, so1308      // Fiber retries from the root.1309      'ErrorBoundary componentWillUpdate',1310      'ErrorBoundary componentDidUpdate',1311      // The second willUnmount error should be captured and logged, too.1312      'ErrorBoundary componentDidCatch',1313      'ErrorBoundary componentWillUpdate',1314      // Render an error now (stack will do it later)1315      'ErrorBoundary render error',1316      // Attempt to unmount previous child:1317      // Done1318      'ErrorBoundary componentDidUpdate',1319    ]);1320    log.length = 0;1321    ReactDOM.unmountComponentAtNode(container);1322    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1323  });1324  it('recovers from nested componentWillUnmount errors on update', () => {1325    const container = document.createElement('div');1326    ReactDOM.render(1327      <ErrorBoundary>1328        <Normal>1329          <BrokenComponentWillUnmount />1330        </Normal>1331        <BrokenComponentWillUnmount />1332      </ErrorBoundary>,1333      container,1334    );1335    log.length = 0;1336    ReactDOM.render(1337      <ErrorBoundary>1338        <Normal>1339          <BrokenComponentWillUnmount />1340        </Normal>1341      </ErrorBoundary>,1342      container,1343    );1344    expect(container.textContent).toBe('Caught an error: Hello.');1345    expect(log).toEqual([1346      'ErrorBoundary componentWillReceiveProps',1347      'ErrorBoundary componentWillUpdate',1348      'ErrorBoundary render success',1349      // Update existing children:1350      'Normal componentWillReceiveProps',1351      'Normal componentWillUpdate',1352      'Normal render',1353      'BrokenComponentWillUnmount componentWillReceiveProps',1354      'BrokenComponentWillUnmount componentWillUpdate',1355      'BrokenComponentWillUnmount render',1356      // Unmounting throws:1357      'BrokenComponentWillUnmount componentWillUnmount [!]',1358      // Fiber proceeds with lifecycles despite errors1359      'BrokenComponentWillUnmount componentDidUpdate',1360      'Normal componentDidUpdate',1361      'ErrorBoundary componentDidUpdate',1362      'Normal componentWillUnmount',1363      'BrokenComponentWillUnmount componentWillUnmount [!]',1364      // Now that commit phase is done, Fiber handles errors1365      'ErrorBoundary componentDidCatch',1366      // The initial render was aborted, so1367      // Fiber retries from the root.1368      'ErrorBoundary componentWillUpdate',1369      'ErrorBoundary componentDidUpdate',1370      // The second willUnmount error should be captured and logged, too.1371      'ErrorBoundary componentDidCatch',1372      'ErrorBoundary componentWillUpdate',1373      // Render an error now (stack will do it later)1374      'ErrorBoundary render error',1375      // Done1376      'ErrorBoundary componentDidUpdate',1377    ]);1378    log.length = 0;1379    ReactDOM.unmountComponentAtNode(container);1380    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1381  });1382  it('picks the right boundary when handling unmounting errors', () => {1383    function renderInnerError(error) {1384      return <div>Caught an inner error: {error.message}.</div>;1385    }1386    function renderOuterError(error) {1387      return <div>Caught an outer error: {error.message}.</div>;1388    }1389    const container = document.createElement('div');1390    ReactDOM.render(1391      <ErrorBoundary1392        logName="OuterErrorBoundary"1393        renderError={renderOuterError}>1394        <ErrorBoundary1395          logName="InnerErrorBoundary"1396          renderError={renderInnerError}>1397          <BrokenComponentWillUnmount />1398        </ErrorBoundary>1399      </ErrorBoundary>,1400      container,1401    );1402    log.length = 0;1403    ReactDOM.render(1404      <ErrorBoundary1405        logName="OuterErrorBoundary"1406        renderError={renderOuterError}>1407        <ErrorBoundary1408          logName="InnerErrorBoundary"1409          renderError={renderInnerError}1410        />1411      </ErrorBoundary>,1412      container,1413    );1414    expect(container.textContent).toBe('Caught an inner error: Hello.');1415    expect(log).toEqual([1416      // Update outer boundary1417      'OuterErrorBoundary componentWillReceiveProps',1418      'OuterErrorBoundary componentWillUpdate',1419      'OuterErrorBoundary render success',1420      // Update inner boundary1421      'InnerErrorBoundary componentWillReceiveProps',1422      'InnerErrorBoundary componentWillUpdate',1423      'InnerErrorBoundary render success',1424      // Try unmounting child1425      'BrokenComponentWillUnmount componentWillUnmount [!]',1426      // Fiber proceeds with lifecycles despite errors1427      // Inner and outer boundaries have updated in this phase1428      'InnerErrorBoundary componentDidUpdate',1429      'OuterErrorBoundary componentDidUpdate',1430      // Now that commit phase is done, Fiber handles errors1431      // Only inner boundary receives the error:1432      'InnerErrorBoundary componentDidCatch',1433      'InnerErrorBoundary componentWillUpdate',1434      // Render an error now1435      'InnerErrorBoundary render error',1436      // In Fiber, this was a local update to the1437      // inner boundary so only its hook fires1438      'InnerErrorBoundary componentDidUpdate',1439    ]);1440    log.length = 0;1441    ReactDOM.unmountComponentAtNode(container);1442    expect(log).toEqual([1443      'OuterErrorBoundary componentWillUnmount',1444      'InnerErrorBoundary componentWillUnmount',1445    ]);1446  });1447  it('can recover from error state', () => {1448    const container = document.createElement('div');1449    ReactDOM.render(1450      <ErrorBoundary>1451        <BrokenRender />1452      </ErrorBoundary>,1453      container,1454    );1455    ReactDOM.render(1456      <ErrorBoundary>1457        <Normal />1458      </ErrorBoundary>,1459      container,1460    );1461    // Error boundary doesn't retry by itself:1462    expect(container.textContent).toBe('Caught an error: Hello.');1463    // Force the success path:1464    log.length = 0;1465    ReactDOM.render(1466      <ErrorBoundary forceRetry={true}>1467        <Normal />1468      </ErrorBoundary>,1469      container,1470    );1471    expect(container.textContent).not.toContain('Caught an error');1472    expect(log).toEqual([1473      'ErrorBoundary componentWillReceiveProps',1474      'ErrorBoundary componentWillUpdate',1475      'ErrorBoundary render success',1476      // Mount children:1477      'Normal constructor',1478      'Normal componentWillMount',1479      'Normal render',1480      // Finalize updates:1481      'Normal componentDidMount',1482      'ErrorBoundary componentDidUpdate',1483    ]);1484    log.length = 0;1485    ReactDOM.unmountComponentAtNode(container);1486    expect(log).toEqual([1487      'ErrorBoundary componentWillUnmount',1488      'Normal componentWillUnmount',1489    ]);1490  });1491  it('can update multiple times in error state', () => {1492    const container = document.createElement('div');1493    ReactDOM.render(1494      <ErrorBoundary>1495        <BrokenRender />1496      </ErrorBoundary>,1497      container,1498    );1499    expect(container.textContent).toBe('Caught an error: Hello.');1500    ReactDOM.render(1501      <ErrorBoundary>1502        <BrokenRender />1503      </ErrorBoundary>,1504      container,1505    );1506    expect(container.textContent).toBe('Caught an error: Hello.');1507    ReactDOM.render(<div>Other screen</div>, container);1508    expect(container.textContent).toBe('Other screen');1509    ReactDOM.unmountComponentAtNode(container);1510  });1511  it("doesn't get into inconsistent state during removals", () => {1512    const container = document.createElement('div');1513    ReactDOM.render(1514      <ErrorBoundary>1515        <Normal />1516        <BrokenComponentWillUnmount />1517        <Normal />1518      </ErrorBoundary>,1519      container,1520    );1521    ReactDOM.render(<ErrorBoundary />, container);1522    expect(container.textContent).toBe('Caught an error: Hello.');1523    log.length = 0;1524    ReactDOM.unmountComponentAtNode(container);1525    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1526  });1527  it("doesn't get into inconsistent state during additions", () => {1528    const container = document.createElement('div');1529    ReactDOM.render(<ErrorBoundary />, container);1530    ReactDOM.render(1531      <ErrorBoundary>1532        <Normal />1533        <BrokenRender />1534        <Normal />1535      </ErrorBoundary>,1536      container,1537    );1538    expect(container.textContent).toBe('Caught an error: Hello.');1539    log.length = 0;1540    ReactDOM.unmountComponentAtNode(container);1541    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1542  });1543  it("doesn't get into inconsistent state during reorders", () => {1544    function getAMixOfNormalAndBrokenRenderElements() {1545      const elements = [];1546      for (let i = 0; i < 100; i++) {1547        elements.push(<Normal key={i} />);1548      }1549      elements.push(<MaybeBrokenRender key={100} />);1550      let currentIndex = elements.length;1551      while (0 !== currentIndex) {1552        const randomIndex = Math.floor(Math.random() * currentIndex);1553        currentIndex -= 1;1554        const temporaryValue = elements[currentIndex];1555        elements[currentIndex] = elements[randomIndex];1556        elements[randomIndex] = temporaryValue;1557      }1558      return elements;1559    }1560    class MaybeBrokenRender extends React.Component {1561      render() {1562        if (fail) {1563          throw new Error('Hello');1564        }1565        return <div>{this.props.children}</div>;1566      }1567    }1568    let fail = false;1569    const container = document.createElement('div');1570    ReactDOM.render(1571      <ErrorBoundary>{getAMixOfNormalAndBrokenRenderElements()}</ErrorBoundary>,1572      container,1573    );1574    expect(container.textContent).not.toContain('Caught an error');1575    fail = true;1576    ReactDOM.render(1577      <ErrorBoundary>{getAMixOfNormalAndBrokenRenderElements()}</ErrorBoundary>,1578      container,1579    );1580    expect(container.textContent).toBe('Caught an error: Hello.');1581    log.length = 0;1582    ReactDOM.unmountComponentAtNode(container);1583    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1584  });1585  it('catches errors originating downstream', () => {1586    let fail = false;1587    class Stateful extends React.Component {1588      state = {shouldThrow: false};1589      render() {1590        if (fail) {1591          log.push('Stateful render [!]');1592          throw new Error('Hello');1593        }1594        return <div>{this.props.children}</div>;1595      }1596    }1597    let statefulInst;1598    const container = document.createElement('div');1599    ReactDOM.render(1600      <ErrorBoundary>1601        <Stateful ref={inst => (statefulInst = inst)} />1602      </ErrorBoundary>,1603      container,1604    );1605    log.length = 0;1606    expect(() => {1607      fail = true;1608      statefulInst.forceUpdate();1609    }).not.toThrow();1610    expect(log).toEqual([1611      'Stateful render [!]',1612      'ErrorBoundary componentDidCatch',1613      'ErrorBoundary componentWillUpdate',1614      'ErrorBoundary render error',1615      'ErrorBoundary componentDidUpdate',1616    ]);1617    log.length = 0;1618    ReactDOM.unmountComponentAtNode(container);1619    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1620  });1621  it('catches errors in componentDidMount', () => {1622    const container = document.createElement('div');1623    ReactDOM.render(1624      <ErrorBoundary>1625        <BrokenComponentWillUnmount>1626          <Normal />1627        </BrokenComponentWillUnmount>1628        <BrokenComponentDidMount />1629        <Normal logName="LastChild" />1630      </ErrorBoundary>,1631      container,1632    );1633    expect(log).toEqual([1634      'ErrorBoundary constructor',1635      'ErrorBoundary componentWillMount',1636      'ErrorBoundary render success',1637      'BrokenComponentWillUnmount constructor',1638      'BrokenComponentWillUnmount componentWillMount',1639      'BrokenComponentWillUnmount render',1640      'Normal constructor',1641      'Normal componentWillMount',1642      'Normal render',1643      'BrokenComponentDidMount constructor',1644      'BrokenComponentDidMount componentWillMount',1645      'BrokenComponentDidMount render',1646      'LastChild constructor',1647      'LastChild componentWillMount',1648      'LastChild render',1649      // Start flushing didMount queue1650      'Normal componentDidMount',1651      'BrokenComponentWillUnmount componentDidMount',1652      'BrokenComponentDidMount componentDidMount [!]',1653      // Continue despite the error1654      'LastChild componentDidMount',1655      'ErrorBoundary componentDidMount',1656      // Now we are ready to handle the error1657      // Safely unmount every child1658      'BrokenComponentWillUnmount componentWillUnmount [!]',1659      // Continue unmounting safely despite any errors1660      'Normal componentWillUnmount',1661      'BrokenComponentDidMount componentWillUnmount',1662      'LastChild componentWillUnmount',1663      // Handle the error1664      'ErrorBoundary componentDidCatch',1665      'ErrorBoundary componentWillUpdate',1666      // The willUnmount error should be captured and logged, too.1667      'ErrorBoundary componentDidUpdate',1668      'ErrorBoundary componentDidCatch',1669      'ErrorBoundary componentWillUpdate',1670      'ErrorBoundary render error',1671      // The update has finished1672      'ErrorBoundary componentDidUpdate',1673    ]);1674    log.length = 0;1675    ReactDOM.unmountComponentAtNode(container);1676    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1677  });1678  it('catches errors in componentDidUpdate', () => {1679    const container = document.createElement('div');1680    ReactDOM.render(1681      <ErrorBoundary>1682        <BrokenComponentDidUpdate />1683      </ErrorBoundary>,1684      container,1685    );1686    log.length = 0;1687    ReactDOM.render(1688      <ErrorBoundary>1689        <BrokenComponentDidUpdate />1690      </ErrorBoundary>,1691      container,1692    );1693    expect(log).toEqual([1694      'ErrorBoundary componentWillReceiveProps',1695      'ErrorBoundary componentWillUpdate',1696      'ErrorBoundary render success',1697      'BrokenComponentDidUpdate componentWillReceiveProps',1698      'BrokenComponentDidUpdate componentWillUpdate',1699      'BrokenComponentDidUpdate render',1700      // All lifecycles run1701      'BrokenComponentDidUpdate componentDidUpdate [!]',1702      'ErrorBoundary componentDidUpdate',1703      'BrokenComponentDidUpdate componentWillUnmount',1704      // Then, error is handled1705      'ErrorBoundary componentDidCatch',1706      'ErrorBoundary componentWillUpdate',1707      'ErrorBoundary render error',1708      'ErrorBoundary componentDidUpdate',1709    ]);1710    log.length = 0;1711    ReactDOM.unmountComponentAtNode(container);1712    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1713  });1714  it('propagates errors inside boundary during componentDidMount', () => {1715    const container = document.createElement('div');1716    ReactDOM.render(1717      <ErrorBoundary>1718        <BrokenComponentDidMountErrorBoundary1719          renderError={error => (1720            <div>We should never catch our own error: {error.message}.</div>1721          )}1722        />1723      </ErrorBoundary>,1724      container,1725    );1726    expect(container.firstChild.textContent).toBe('Caught an error: Hello.');1727    expect(log).toEqual([1728      'ErrorBoundary constructor',1729      'ErrorBoundary componentWillMount',1730      'ErrorBoundary render success',1731      'BrokenComponentDidMountErrorBoundary constructor',1732      'BrokenComponentDidMountErrorBoundary componentWillMount',1733      'BrokenComponentDidMountErrorBoundary render success',1734      'BrokenComponentDidMountErrorBoundary componentDidMount [!]',1735      // Fiber proceeds with the hooks1736      'ErrorBoundary componentDidMount',1737      'BrokenComponentDidMountErrorBoundary componentWillUnmount',1738      // The error propagates to the higher boundary1739      'ErrorBoundary componentDidCatch',1740      // Fiber retries from the root1741      'ErrorBoundary componentWillUpdate',1742      'ErrorBoundary render error',1743      'ErrorBoundary componentDidUpdate',1744    ]);1745    log.length = 0;1746    ReactDOM.unmountComponentAtNode(container);1747    expect(log).toEqual(['ErrorBoundary componentWillUnmount']);1748  });1749  it('calls componentDidCatch for each error that is captured', () => {1750    function renderUnmountError(error) {1751      return <div>Caught an unmounting error: {error.message}.</div>;1752    }1753    function renderUpdateError(error) {1754      return <div>Caught an updating error: {error.message}.</div>;1755    }1756    const container = document.createElement('div');1757    ReactDOM.render(1758      <ErrorBoundary logName="OuterErrorBoundary">1759        <ErrorBoundary1760          logName="InnerUnmountBoundary"1761          renderError={renderUnmountError}>1762          <BrokenComponentWillUnmount errorText="E1" />1763          <BrokenComponentWillUnmount errorText="E2" />1764        </ErrorBoundary>1765        <ErrorBoundary1766          logName="InnerUpdateBoundary"1767          renderError={renderUpdateError}>1768          <BrokenComponentDidUpdate errorText="E3" />1769          <BrokenComponentDidUpdate errorText="E4" />1770        </ErrorBoundary>1771      </ErrorBoundary>,1772      container,1773    );1774    log.length = 0;1775    ReactDOM.render(1776      <ErrorBoundary logName="OuterErrorBoundary">1777        <ErrorBoundary1778          logName="InnerUnmountBoundary"1779          renderError={renderUnmountError}1780        />1781        <ErrorBoundary1782          logName="InnerUpdateBoundary"1783          renderError={renderUpdateError}>1784          <BrokenComponentDidUpdate errorText="E3" />1785          <BrokenComponentDidUpdate errorText="E4" />1786        </ErrorBoundary>1787      </ErrorBoundary>,1788      container,1789    );1790    expect(container.firstChild.textContent).toBe(1791      'Caught an unmounting error: E2.' + 'Caught an updating error: E4.',1792    );1793    expect(log).toEqual([1794      // Begin update phase1795      'OuterErrorBoundary componentWillReceiveProps',1796      'OuterErrorBoundary componentWillUpdate',1797      'OuterErrorBoundary render success',1798      'InnerUnmountBoundary componentWillReceiveProps',1799      'InnerUnmountBoundary componentWillUpdate',1800      'InnerUnmountBoundary render success',1801      'InnerUpdateBoundary componentWillReceiveProps',1802      'InnerUpdateBoundary componentWillUpdate',1803      'InnerUpdateBoundary render success',1804      // First come the updates1805      'BrokenComponentDidUpdate componentWillReceiveProps',1806      'BrokenComponentDidUpdate componentWillUpdate',1807      'BrokenComponentDidUpdate render',1808      'BrokenComponentDidUpdate componentWillReceiveProps',1809      'BrokenComponentDidUpdate componentWillUpdate',1810      'BrokenComponentDidUpdate render',1811      // We're in commit phase now, deleting1812      'BrokenComponentWillUnmount componentWillUnmount [!]',1813      'BrokenComponentWillUnmount componentWillUnmount [!]',1814      // Continue despite errors, handle them after commit is done1815      'InnerUnmountBoundary componentDidUpdate',1816      // We're still in commit phase, now calling update lifecycles1817      'BrokenComponentDidUpdate componentDidUpdate [!]',1818      // Again, continue despite errors, we'll handle them later1819      'BrokenComponentDidUpdate componentDidUpdate [!]',1820      'InnerUpdateBoundary componentDidUpdate',1821      'OuterErrorBoundary componentDidUpdate',1822      // After the commit phase, attempt to recover from any errors that1823      // were captured1824      'BrokenComponentDidUpdate componentWillUnmount',1825      'BrokenComponentDidUpdate componentWillUnmount',1826      'InnerUnmountBoundary componentDidCatch',1827      'InnerUnmountBoundary componentDidCatch',1828      'InnerUpdateBoundary componentDidCatch',1829      'InnerUpdateBoundary componentDidCatch',1830      'InnerUnmountBoundary componentWillUpdate',1831      'InnerUnmountBoundary render error',1832      'InnerUpdateBoundary componentWillUpdate',1833      'InnerUpdateBoundary render error',1834      'InnerUnmountBoundary componentDidUpdate',1835      'InnerUpdateBoundary componentDidUpdate',1836    ]);1837    log.length = 0;1838    ReactDOM.unmountComponentAtNode(container);1839    expect(log).toEqual([1840      'OuterErrorBoundary componentWillUnmount',1841      'InnerUnmountBoundary componentWillUnmount',1842      'InnerUpdateBoundary componentWillUnmount',1843    ]);1844  });1845  it('discards a bad root if the root component fails', () => {1846    const X = null;1847    const Y = undefined;1848    let err1;1849    let err2;1850    try {1851      let container = document.createElement('div');1852      expect(() => ReactDOM.render(<X />, container)).toWarnDev(1853        'React.createElement: type is invalid -- expected a string ' +1854          '(for built-in components) or a class/function ' +1855          '(for composite components) but got: null.',1856      );1857    } catch (err) {1858      err1 = err;1859    }1860    try {1861      let container = document.createElement('div');1862      expect(() => ReactDOM.render(<Y />, container)).toWarnDev(1863        'React.createElement: type is invalid -- expected a string ' +1864          '(for built-in components) or a class/function ' +1865          '(for composite components) but got: undefined.',1866      );1867    } catch (err) {1868      err2 = err;1869    }1870    expect(err1.message).toMatch(/got: null/);1871    expect(err2.message).toMatch(/got: undefined/);1872  });1873  it('renders empty output if error boundary does not handle the error', () => {1874    const container = document.createElement('div');1875    expect(() => {1876      ReactDOM.render(1877        <div>1878          Sibling1879          <NoopErrorBoundary>1880            <BrokenRender />1881          </NoopErrorBoundary>1882        </div>,1883        container,1884      );1885    }).toWarnDev(1886      'ErrorBoundary: Error boundaries should implement getDerivedStateFromError()',1887      {withoutStack: true},1888    );1889    expect(container.firstChild.textContent).toBe('Sibling');1890    expect(log).toEqual([1891      'NoopErrorBoundary constructor',1892      'NoopErrorBoundary componentWillMount',1893      'NoopErrorBoundary render',1894      'BrokenRender constructor',1895      'BrokenRender componentWillMount',1896      'BrokenRender render [!]',1897      // In Fiber, noop error boundaries render null1898      'NoopErrorBoundary componentDidMount',1899      'NoopErrorBoundary componentDidCatch',1900      // Nothing happens.1901    ]);1902    log.length = 0;1903    ReactDOM.unmountComponentAtNode(container);1904    expect(log).toEqual(['NoopErrorBoundary componentWillUnmount']);1905  });1906  it('passes first error when two errors happen in commit', () => {1907    const errors = [];1908    let caughtError;1909    class Parent extends React.Component {1910      render() {1911        return <Child />;1912      }1913      componentDidMount() {1914        errors.push('parent sad');1915        throw new Error('parent sad');1916      }1917    }1918    class Child extends React.Component {1919      render() {1920        return <div />;1921      }1922      componentDidMount() {1923        errors.push('child sad');1924        throw new Error('child sad');1925      }1926    }1927    const container = document.createElement('div');1928    try {1929      // Here, we test the behavior where there is no error boundary and we1930      // delegate to the host root.1931      ReactDOM.render(<Parent />, container);1932    } catch (e) {1933      if (e.message !== 'parent sad' && e.message !== 'child sad') {1934        throw e;1935      }1936      caughtError = e;1937    }1938    expect(errors).toEqual(['child sad', 'parent sad']);1939    // Error should be the first thrown1940    expect(caughtError.message).toBe('child sad');1941  });1942  it('propagates uncaught error inside unbatched initial mount', () => {1943    function Foo() {1944      throw new Error('foo error');1945    }1946    const container = document.createElement('div');1947    expect(() => {1948      ReactDOM.unstable_batchedUpdates(() => {1949        ReactDOM.render(<Foo />, container);1950      });1951    }).toThrow('foo error');1952  });1953  it('handles errors that occur in before-mutation commit hook', () => {1954    const errors = [];1955    let caughtError;1956    class Parent extends React.Component {1957      getSnapshotBeforeUpdate() {1958        errors.push('parent sad');1959        throw new Error('parent sad');1960      }1961      componentDidUpdate() {}1962      render() {1963        return <Child {...this.props} />;1964      }1965    }1966    class Child extends React.Component {1967      getSnapshotBeforeUpdate() {1968        errors.push('child sad');1969        throw new Error('child sad');1970      }1971      componentDidUpdate() {}1972      render() {1973        return <div />;1974      }1975    }1976    const container = document.createElement('div');1977    ReactDOM.render(<Parent value={1} />, container);1978    try {1979      ReactDOM.render(<Parent value={2} />, container);1980    } catch (e) {1981      if (e.message !== 'parent sad' && e.message !== 'child sad') {1982        throw e;1983      }1984      caughtError = e;1985    }1986    expect(errors).toEqual(['child sad', 'parent sad']);1987    // Error should be the first thrown1988    expect(caughtError.message).toBe('child sad');1989  });...

Full Screen

Full Screen

ReactIncrementalErrorHandling-test.internal.js

Source:ReactIncrementalErrorHandling-test.internal.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @emails react-core8 * @jest-environment node9 */10'use strict';11let PropTypes;12let ReactFeatureFlags;13let React;14let ReactNoop;15describe('ReactIncrementalErrorHandling', () => {16  beforeEach(() => {17    jest.resetModules();18    ReactFeatureFlags = require('shared/ReactFeatureFlags');19    ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;20    ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false;21    PropTypes = require('prop-types');22    React = require('react');23    ReactNoop = require('react-noop-renderer');24  });25  function div(...children) {26    children = children.map(c => (typeof c === 'string' ? {text: c} : c));27    return {type: 'div', children, prop: undefined, hidden: false};28  }29  function span(prop) {30    return {type: 'span', children: [], prop, hidden: false};31  }32  function normalizeCodeLocInfo(str) {33    return str && str.replace(/\(at .+?:\d+\)/g, '(at **)');34  }35  it('recovers from errors asynchronously', () => {36    class ErrorBoundary extends React.Component {37      state = {error: null};38      static getDerivedStateFromError(error) {39        ReactNoop.yield('getDerivedStateFromError');40        return {error};41      }42      render() {43        if (this.state.error) {44          ReactNoop.yield('ErrorBoundary (catch)');45          return <ErrorMessage error={this.state.error} />;46        }47        ReactNoop.yield('ErrorBoundary (try)');48        return this.props.children;49      }50    }51    function ErrorMessage(props) {52      ReactNoop.yield('ErrorMessage');53      return <span prop={`Caught an error: ${props.error.message}`} />;54    }55    function Indirection(props) {56      ReactNoop.yield('Indirection');57      return props.children || null;58    }59    function BadRender() {60      ReactNoop.yield('throw');61      throw new Error('oops!');62    }63    ReactNoop.render(64      <ErrorBoundary>65        <Indirection>66          <Indirection>67            <Indirection>68              <BadRender />69              <Indirection />70              <Indirection />71            </Indirection>72          </Indirection>73        </Indirection>74      </ErrorBoundary>,75    );76    // Start rendering asynchronously77    ReactNoop.flushThrough([78      'ErrorBoundary (try)',79      'Indirection',80      'Indirection',81      'Indirection',82      // An error is thrown. React keeps rendering asynchronously.83      'throw',84    ]);85    // Still rendering async...86    ReactNoop.flushThrough(['Indirection']);87    ReactNoop.flushThrough([88      'Indirection',89      // Call getDerivedStateFromError and re-render the error boundary, this90      // time rendering an error message.91      'getDerivedStateFromError',92      'ErrorBoundary (catch)',93      'ErrorMessage',94    ]);95    // Since the error was thrown during an async render, React won't commit96    // the result yet.97    expect(ReactNoop.getChildren()).toEqual([]);98    // Instead, it will try rendering one more time, synchronously, in case that99    // happens to fix the error.100    expect(ReactNoop.flushNextYield()).toEqual([101      'ErrorBoundary (try)',102      'Indirection',103      'Indirection',104      'Indirection',105      // The error was thrown again. This time, React will actually commit106      // the result.107      'throw',108      'Indirection',109      'Indirection',110      'getDerivedStateFromError',111      'ErrorBoundary (catch)',112      'ErrorMessage',113    ]);114    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: oops!')]);115  });116  it('recovers from errors asynchronously (legacy, no getDerivedStateFromError)', () => {117    class ErrorBoundary extends React.Component {118      state = {error: null};119      componentDidCatch(error) {120        ReactNoop.yield('componentDidCatch');121        this.setState({error});122      }123      render() {124        if (this.state.error) {125          ReactNoop.yield('ErrorBoundary (catch)');126          return <ErrorMessage error={this.state.error} />;127        }128        ReactNoop.yield('ErrorBoundary (try)');129        return this.props.children;130      }131    }132    function ErrorMessage(props) {133      ReactNoop.yield('ErrorMessage');134      return <span prop={`Caught an error: ${props.error.message}`} />;135    }136    function Indirection(props) {137      ReactNoop.yield('Indirection');138      return props.children || null;139    }140    function BadRender() {141      ReactNoop.yield('throw');142      throw new Error('oops!');143    }144    ReactNoop.render(145      <ErrorBoundary>146        <Indirection>147          <Indirection>148            <Indirection>149              <BadRender />150              <Indirection />151              <Indirection />152            </Indirection>153          </Indirection>154        </Indirection>155      </ErrorBoundary>,156    );157    // Start rendering asynchronously158    ReactNoop.flushThrough([159      'ErrorBoundary (try)',160      'Indirection',161      'Indirection',162      'Indirection',163      // An error is thrown. React keeps rendering asynchronously.164      'throw',165    ]);166    // Still rendering async...167    ReactNoop.flushThrough(['Indirection']);168    ReactNoop.flushThrough([169      'Indirection',170      // Now that the tree is complete, and there's no remaining work, React171      // reverts to sync mode to retry one more time before handling the error.172      'ErrorBoundary (try)',173      'Indirection',174      'Indirection',175      'Indirection',176      // The error was thrown again. Now we can handle it.177      'throw',178      'Indirection',179      'Indirection',180      'componentDidCatch',181      'ErrorBoundary (catch)',182      'ErrorMessage',183    ]);184    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: oops!')]);185  });186  it("retries at a lower priority if there's additional pending work", () => {187    function App(props) {188      if (props.isBroken) {189        ReactNoop.yield('error');190        throw new Error('Oops!');191      }192      ReactNoop.yield('success');193      return <span prop="Everything is fine." />;194    }195    function onCommit() {196      ReactNoop.yield('commit');197    }198    ReactNoop.render(<App isBroken={true} />, onCommit);199    ReactNoop.expire(2000);200    ReactNoop.render(<App isBroken={false} />, onCommit);201    expect(ReactNoop.flush()).toEqual([202      // The first render fails. But because there's a lower priority pending203      // update, it doesn't throw.204      'error',205      // Now we retry at the lower priority. This time it succeeds.206      'success',207      // Nothing commits until the second update completes.208      'commit',209      'commit',210    ]);211    expect(ReactNoop.getChildren()).toEqual([span('Everything is fine.')]);212  });213  it('on error, retries at a lower priority using the expiration of higher priority', () => {214    class Parent extends React.Component {215      state = {hideChild: false};216      componentDidUpdate() {217        ReactNoop.yield('commit: ' + this.state.hideChild);218      }219      render() {220        if (this.state.hideChild) {221          ReactNoop.yield('(empty)');222          return <span prop="(empty)" />;223        }224        return <Child isBroken={this.props.childIsBroken} />;225      }226    }227    function Child(props) {228      if (props.isBroken) {229        ReactNoop.yield('Error!');230        throw new Error('Error!');231      }232      ReactNoop.yield('Child');233      return <span prop="Child" />;234    }235    // Initial mount236    const parent = React.createRef(null);237    ReactNoop.render(<Parent ref={parent} childIsBroken={false} />);238    expect(ReactNoop.flush()).toEqual(['Child']);239    expect(ReactNoop.getChildren()).toEqual([span('Child')]);240    // Schedule a low priority update to hide the child241    parent.current.setState({hideChild: true});242    // Before the low priority update is flushed, synchronously trigger an243    // error in the child.244    ReactNoop.flushSync(() => {245      ReactNoop.render(<Parent ref={parent} childIsBroken={true} />);246    });247    expect(ReactNoop.clearYields()).toEqual([248      // First the sync update triggers an error249      'Error!',250      // Because there's a pending low priority update, we restart at the251      // lower priority. This hides the children, suppressing the error.252      '(empty)',253      // Now the tree can commit.254      'commit: true',255    ]);256    expect(ReactNoop.getChildren()).toEqual([span('(empty)')]);257  });258  it('retries one more time before handling error', () => {259    let ops = [];260    function BadRender() {261      ops.push('BadRender');262      ReactNoop.yield('BadRender');263      throw new Error('oops');264    }265    function Sibling() {266      ops.push('Sibling');267      ReactNoop.yield('Sibling');268      return <span prop="Sibling" />;269    }270    function Parent() {271      ops.push('Parent');272      ReactNoop.yield('Parent');273      return (274        <React.Fragment>275          <BadRender />276          <Sibling />277        </React.Fragment>278      );279    }280    ReactNoop.render(<Parent />);281    // Render the bad component asynchronously282    ReactNoop.flushThrough(['Parent', 'BadRender']);283    // Finish the rest of the async work284    ReactNoop.flushThrough(['Sibling']);285    // Rendering two more units of work should be enough to trigger the retry286    // and synchronously throw an error.287    ops = [];288    expect(() => ReactNoop.flushUnitsOfWork(2)).toThrow('oops');289    expect(ops).toEqual(['Parent', 'BadRender', 'Sibling']);290  });291  // TODO: This is currently unobservable, but will be once we lift renderRoot292  // and commitRoot into the renderer.293  // it("does not retry synchronously if there's an update between complete and commit");294  it('calls componentDidCatch multiple times for multiple errors', () => {295    let id = 0;296    class BadMount extends React.Component {297      componentDidMount() {298        throw new Error(`Error ${++id}`);299      }300      render() {301        ReactNoop.yield('BadMount');302        return null;303      }304    }305    class ErrorBoundary extends React.Component {306      state = {errorCount: 0};307      componentDidCatch(error) {308        ReactNoop.yield(`componentDidCatch: ${error.message}`);309        this.setState(state => ({errorCount: state.errorCount + 1}));310      }311      render() {312        if (this.state.errorCount > 0) {313          return <span prop={`Number of errors: ${this.state.errorCount}`} />;314        }315        ReactNoop.yield('ErrorBoundary');316        return this.props.children;317      }318    }319    ReactNoop.render(320      <ErrorBoundary>321        <BadMount />322        <BadMount />323        <BadMount />324      </ErrorBoundary>,325    );326    expect(ReactNoop.flush()).toEqual([327      'ErrorBoundary',328      'BadMount',329      'BadMount',330      'BadMount',331      'componentDidCatch: Error 1',332      'componentDidCatch: Error 2',333      'componentDidCatch: Error 3',334    ]);335    expect(ReactNoop.getChildren()).toEqual([span('Number of errors: 3')]);336  });337  it('catches render error in a boundary during full deferred mounting', () => {338    class ErrorBoundary extends React.Component {339      state = {error: null};340      componentDidCatch(error) {341        this.setState({error});342      }343      render() {344        if (this.state.error) {345          return (346            <span prop={`Caught an error: ${this.state.error.message}.`} />347          );348        }349        return this.props.children;350      }351    }352    function BrokenRender(props) {353      throw new Error('Hello');354    }355    ReactNoop.render(356      <ErrorBoundary>357        <BrokenRender />358      </ErrorBoundary>,359    );360    ReactNoop.flushDeferredPri();361    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: Hello.')]);362  });363  it('catches render error in a boundary during partial deferred mounting', () => {364    class ErrorBoundary extends React.Component {365      state = {error: null};366      componentDidCatch(error) {367        ReactNoop.yield('ErrorBoundary componentDidCatch');368        this.setState({error});369      }370      render() {371        if (this.state.error) {372          ReactNoop.yield('ErrorBoundary render error');373          return (374            <span prop={`Caught an error: ${this.state.error.message}.`} />375          );376        }377        ReactNoop.yield('ErrorBoundary render success');378        return this.props.children;379      }380    }381    function BrokenRender(props) {382      ReactNoop.yield('BrokenRender');383      throw new Error('Hello');384    }385    ReactNoop.render(386      <ErrorBoundary>387        <BrokenRender />388      </ErrorBoundary>,389    );390    ReactNoop.flushThrough(['ErrorBoundary render success']);391    expect(ReactNoop.getChildren()).toEqual([]);392    expect(ReactNoop.flush()).toEqual([393      'BrokenRender',394      // React retries one more time395      'ErrorBoundary render success',396      // Errored again on retry. Now handle it.397      'BrokenRender',398      'ErrorBoundary componentDidCatch',399      'ErrorBoundary render error',400    ]);401    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: Hello.')]);402  });403  it('catches render error in a boundary during synchronous mounting', () => {404    const ops = [];405    class ErrorBoundary extends React.Component {406      state = {error: null};407      componentDidCatch(error) {408        ops.push('ErrorBoundary componentDidCatch');409        this.setState({error});410      }411      render() {412        if (this.state.error) {413          ops.push('ErrorBoundary render error');414          return (415            <span prop={`Caught an error: ${this.state.error.message}.`} />416          );417        }418        ops.push('ErrorBoundary render success');419        return this.props.children;420      }421    }422    function BrokenRender(props) {423      ops.push('BrokenRender');424      throw new Error('Hello');425    }426    ReactNoop.flushSync(() => {427      ReactNoop.render(428        <ErrorBoundary>429          <BrokenRender />430        </ErrorBoundary>,431      );432    });433    expect(ops).toEqual([434      'ErrorBoundary render success',435      'BrokenRender',436      // React doesn't retry because we're already rendering synchronously.437      'ErrorBoundary componentDidCatch',438      'ErrorBoundary render error',439    ]);440    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: Hello.')]);441  });442  it('catches render error in a boundary during batched mounting', () => {443    const ops = [];444    class ErrorBoundary extends React.Component {445      state = {error: null};446      componentDidCatch(error) {447        ops.push('ErrorBoundary componentDidCatch');448        this.setState({error});449      }450      render() {451        if (this.state.error) {452          ops.push('ErrorBoundary render error');453          return (454            <span prop={`Caught an error: ${this.state.error.message}.`} />455          );456        }457        ops.push('ErrorBoundary render success');458        return this.props.children;459      }460    }461    function BrokenRender(props) {462      ops.push('BrokenRender');463      throw new Error('Hello');464    }465    ReactNoop.flushSync(() => {466      ReactNoop.render(<ErrorBoundary>Before the storm.</ErrorBoundary>);467      ReactNoop.render(468        <ErrorBoundary>469          <BrokenRender />470        </ErrorBoundary>,471      );472    });473    expect(ops).toEqual([474      'ErrorBoundary render success',475      'BrokenRender',476      // React doesn't retry because we're already rendering synchronously.477      'ErrorBoundary componentDidCatch',478      'ErrorBoundary render error',479    ]);480    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: Hello.')]);481  });482  it('propagates an error from a noop error boundary during full deferred mounting', () => {483    const ops = [];484    class RethrowErrorBoundary extends React.Component {485      componentDidCatch(error) {486        ops.push('RethrowErrorBoundary componentDidCatch');487        throw error;488      }489      render() {490        ops.push('RethrowErrorBoundary render');491        return this.props.children;492      }493    }494    function BrokenRender() {495      ops.push('BrokenRender');496      throw new Error('Hello');497    }498    ReactNoop.render(499      <RethrowErrorBoundary>500        <BrokenRender />501      </RethrowErrorBoundary>,502    );503    expect(() => {504      ReactNoop.flush();505    }).toThrow('Hello');506    expect(ops).toEqual([507      'RethrowErrorBoundary render',508      'BrokenRender',509      // React retries one more time510      'RethrowErrorBoundary render',511      'BrokenRender',512      // Errored again on retry. Now handle it.513      'RethrowErrorBoundary componentDidCatch',514    ]);515    expect(ReactNoop.getChildren()).toEqual([]);516  });517  it('propagates an error from a noop error boundary during partial deferred mounting', () => {518    const ops = [];519    class RethrowErrorBoundary extends React.Component {520      componentDidCatch(error) {521        ops.push('RethrowErrorBoundary componentDidCatch');522        throw error;523      }524      render() {525        ops.push('RethrowErrorBoundary render');526        return this.props.children;527      }528    }529    function BrokenRender() {530      ops.push('BrokenRender');531      throw new Error('Hello');532    }533    ReactNoop.render(534      <RethrowErrorBoundary>535        <BrokenRender />536      </RethrowErrorBoundary>,537    );538    ReactNoop.flushDeferredPri(15);539    expect(ops).toEqual(['RethrowErrorBoundary render']);540    ops.length = 0;541    expect(() => {542      ReactNoop.flush();543    }).toThrow('Hello');544    expect(ops).toEqual([545      'BrokenRender',546      // React retries one more time547      'RethrowErrorBoundary render',548      'BrokenRender',549      // Errored again on retry. Now handle it.550      'RethrowErrorBoundary componentDidCatch',551    ]);552    expect(ReactNoop.getChildren()).toEqual([]);553  });554  it('propagates an error from a noop error boundary during synchronous mounting', () => {555    const ops = [];556    class RethrowErrorBoundary extends React.Component {557      componentDidCatch(error) {558        ops.push('RethrowErrorBoundary componentDidCatch');559        throw error;560      }561      render() {562        ops.push('RethrowErrorBoundary render');563        return this.props.children;564      }565    }566    function BrokenRender() {567      ops.push('BrokenRender');568      throw new Error('Hello');569    }570    expect(() => {571      ReactNoop.flushSync(() => {572        ReactNoop.render(573          <RethrowErrorBoundary>574            <BrokenRender />575          </RethrowErrorBoundary>,576        );577      });578    }).toThrow('Hello');579    expect(ops).toEqual([580      'RethrowErrorBoundary render',581      'BrokenRender',582      // React doesn't retry because we're already rendering synchronously.583      'RethrowErrorBoundary componentDidCatch',584    ]);585    expect(ReactNoop.getChildren()).toEqual([]);586  });587  it('propagates an error from a noop error boundary during batched mounting', () => {588    const ops = [];589    class RethrowErrorBoundary extends React.Component {590      componentDidCatch(error) {591        ops.push('RethrowErrorBoundary componentDidCatch');592        throw error;593      }594      render() {595        ops.push('RethrowErrorBoundary render');596        return this.props.children;597      }598    }599    function BrokenRender() {600      ops.push('BrokenRender');601      throw new Error('Hello');602    }603    expect(() => {604      ReactNoop.flushSync(() => {605        ReactNoop.render(606          <RethrowErrorBoundary>Before the storm.</RethrowErrorBoundary>,607        );608        ReactNoop.render(609          <RethrowErrorBoundary>610            <BrokenRender />611          </RethrowErrorBoundary>,612        );613      });614    }).toThrow('Hello');615    expect(ops).toEqual([616      'RethrowErrorBoundary render',617      'BrokenRender',618      // React doesn't retry because we're already rendering synchronously.619      'RethrowErrorBoundary componentDidCatch',620    ]);621    expect(ReactNoop.getChildren()).toEqual([]);622  });623  it('applies batched updates regardless despite errors in scheduling', () => {624    ReactNoop.render(<span prop="a:1" />);625    expect(() => {626      ReactNoop.batchedUpdates(() => {627        ReactNoop.render(<span prop="a:2" />);628        ReactNoop.render(<span prop="a:3" />);629        throw new Error('Hello');630      });631    }).toThrow('Hello');632    ReactNoop.flush();633    expect(ReactNoop.getChildren()).toEqual([span('a:3')]);634  });635  it('applies nested batched updates despite errors in scheduling', () => {636    ReactNoop.render(<span prop="a:1" />);637    expect(() => {638      ReactNoop.batchedUpdates(() => {639        ReactNoop.render(<span prop="a:2" />);640        ReactNoop.render(<span prop="a:3" />);641        ReactNoop.batchedUpdates(() => {642          ReactNoop.render(<span prop="a:4" />);643          ReactNoop.render(<span prop="a:5" />);644          throw new Error('Hello');645        });646      });647    }).toThrow('Hello');648    ReactNoop.flush();649    expect(ReactNoop.getChildren()).toEqual([span('a:5')]);650  });651  it('applies sync updates regardless despite errors in scheduling', () => {652    ReactNoop.render(<span prop="a:1" />);653    expect(() => {654      ReactNoop.flushSync(() => {655        ReactNoop.batchedUpdates(() => {656          ReactNoop.render(<span prop="a:2" />);657          ReactNoop.render(<span prop="a:3" />);658          throw new Error('Hello');659        });660      });661    }).toThrow('Hello');662    expect(ReactNoop.getChildren()).toEqual([span('a:3')]);663  });664  it('can schedule updates after uncaught error in render on mount', () => {665    let ops = [];666    function BrokenRender() {667      ops.push('BrokenRender');668      throw new Error('Hello');669    }670    function Foo() {671      ops.push('Foo');672      return null;673    }674    ReactNoop.render(<BrokenRender />);675    expect(() => {676      ReactNoop.flush();677    }).toThrow('Hello');678    expect(ops).toEqual([679      'BrokenRender',680      // React retries one more time681      'BrokenRender',682      // Errored again on retry683    ]);684    ops = [];685    ReactNoop.render(<Foo />);686    ReactNoop.flush();687    expect(ops).toEqual(['Foo']);688  });689  it('can schedule updates after uncaught error in render on update', () => {690    let ops = [];691    function BrokenRender(props) {692      ops.push('BrokenRender');693      if (props.throw) {694        throw new Error('Hello');695      }696      return null;697    }698    function Foo() {699      ops.push('Foo');700      return null;701    }702    ReactNoop.render(<BrokenRender throw={false} />);703    ReactNoop.flush();704    ops = [];705    expect(() => {706      ReactNoop.render(<BrokenRender throw={true} />);707      ReactNoop.flush();708    }).toThrow('Hello');709    expect(ops).toEqual([710      'BrokenRender',711      // React retries one more time712      'BrokenRender',713      // Errored again on retry714    ]);715    ops = [];716    ReactNoop.render(<Foo />);717    ReactNoop.flush();718    expect(ops).toEqual(['Foo']);719  });720  it('can schedule updates after uncaught error during umounting', () => {721    let ops = [];722    class BrokenComponentWillUnmount extends React.Component {723      render() {724        return <div />;725      }726      componentWillUnmount() {727        throw new Error('Hello');728      }729    }730    function Foo() {731      ops.push('Foo');732      return null;733    }734    ReactNoop.render(<BrokenComponentWillUnmount />);735    ReactNoop.flush();736    expect(() => {737      ReactNoop.render(<div />);738      ReactNoop.flush();739    }).toThrow('Hello');740    ops = [];741    ReactNoop.render(<Foo />);742    ReactNoop.flush();743    expect(ops).toEqual(['Foo']);744  });745  it('should not attempt to recover an unmounting error boundary', () => {746    class Parent extends React.Component {747      componentWillUnmount() {748        ReactNoop.yield('Parent componentWillUnmount');749      }750      render() {751        return <Boundary />;752      }753    }754    class Boundary extends React.Component {755      componentDidCatch(e) {756        ReactNoop.yield(`Caught error: ${e.message}`);757      }758      render() {759        return <ThrowsOnUnmount />;760      }761    }762    class ThrowsOnUnmount extends React.Component {763      componentWillUnmount() {764        ReactNoop.yield('ThrowsOnUnmount componentWillUnmount');765        throw new Error('unmount error');766      }767      render() {768        return null;769      }770    }771    ReactNoop.render(<Parent />);772    ReactNoop.flush();773    ReactNoop.render(null);774    expect(ReactNoop.flush()).toEqual([775      // Parent unmounts before the error is thrown.776      'Parent componentWillUnmount',777      'ThrowsOnUnmount componentWillUnmount',778    ]);779    ReactNoop.render(<Parent />);780  });781  it('can unmount an error boundary before it is handled', () => {782    let parent;783    class Parent extends React.Component {784      state = {step: 0};785      render() {786        parent = this;787        return this.state.step === 0 ? <Boundary /> : null;788      }789    }790    class Boundary extends React.Component {791      componentDidCatch() {}792      render() {793        return <Child />;794      }795    }796    class Child extends React.Component {797      componentDidUpdate() {798        parent.setState({step: 1});799        throw new Error('update error');800      }801      render() {802        return null;803      }804    }805    ReactNoop.render(<Parent />);806    ReactNoop.flush();807    ReactNoop.flushSync(() => {808      ReactNoop.render(<Parent />);809    });810  });811  it('continues work on other roots despite caught errors', () => {812    class ErrorBoundary extends React.Component {813      state = {error: null};814      componentDidCatch(error) {815        this.setState({error});816      }817      render() {818        if (this.state.error) {819          return (820            <span prop={`Caught an error: ${this.state.error.message}.`} />821          );822        }823        return this.props.children;824      }825    }826    function BrokenRender(props) {827      throw new Error('Hello');828    }829    ReactNoop.renderToRootWithID(830      <ErrorBoundary>831        <BrokenRender />832      </ErrorBoundary>,833      'a',834    );835    ReactNoop.renderToRootWithID(<span prop="b:1" />, 'b');836    ReactNoop.flush();837    expect(ReactNoop.getChildren('a')).toEqual([838      span('Caught an error: Hello.'),839    ]);840    expect(ReactNoop.getChildren('b')).toEqual([span('b:1')]);841  });842  it('continues work on other roots despite uncaught errors', () => {843    function BrokenRender(props) {844      throw new Error('Hello');845    }846    ReactNoop.renderToRootWithID(<BrokenRender />, 'a');847    expect(() => {848      ReactNoop.flush();849    }).toThrow('Hello');850    expect(ReactNoop.getChildren('a')).toEqual([]);851    ReactNoop.renderToRootWithID(<BrokenRender />, 'a');852    ReactNoop.renderToRootWithID(<span prop="b:2" />, 'b');853    expect(() => {854      ReactNoop.flush();855    }).toThrow('Hello');856    expect(ReactNoop.getChildren('a')).toEqual([]);857    expect(ReactNoop.getChildren('b')).toEqual([span('b:2')]);858    ReactNoop.renderToRootWithID(<span prop="a:3" />, 'a');859    ReactNoop.renderToRootWithID(<BrokenRender />, 'b');860    expect(() => {861      ReactNoop.flush();862    }).toThrow('Hello');863    expect(ReactNoop.getChildren('a')).toEqual([span('a:3')]);864    expect(ReactNoop.getChildren('b')).toEqual([]);865    ReactNoop.renderToRootWithID(<span prop="a:4" />, 'a');866    ReactNoop.renderToRootWithID(<BrokenRender />, 'b');867    ReactNoop.renderToRootWithID(<span prop="c:4" />, 'c');868    expect(() => {869      ReactNoop.flush();870    }).toThrow('Hello');871    expect(ReactNoop.getChildren('a')).toEqual([span('a:4')]);872    expect(ReactNoop.getChildren('b')).toEqual([]);873    expect(ReactNoop.getChildren('c')).toEqual([span('c:4')]);874    ReactNoop.renderToRootWithID(<span prop="a:5" />, 'a');875    ReactNoop.renderToRootWithID(<span prop="b:5" />, 'b');876    ReactNoop.renderToRootWithID(<span prop="c:5" />, 'c');877    ReactNoop.renderToRootWithID(<span prop="d:5" />, 'd');878    ReactNoop.renderToRootWithID(<BrokenRender />, 'e');879    expect(() => {880      ReactNoop.flush();881    }).toThrow('Hello');882    expect(ReactNoop.getChildren('a')).toEqual([span('a:5')]);883    expect(ReactNoop.getChildren('b')).toEqual([span('b:5')]);884    expect(ReactNoop.getChildren('c')).toEqual([span('c:5')]);885    expect(ReactNoop.getChildren('d')).toEqual([span('d:5')]);886    expect(ReactNoop.getChildren('e')).toEqual([]);887    ReactNoop.renderToRootWithID(<BrokenRender />, 'a');888    ReactNoop.renderToRootWithID(<span prop="b:6" />, 'b');889    ReactNoop.renderToRootWithID(<BrokenRender />, 'c');890    ReactNoop.renderToRootWithID(<span prop="d:6" />, 'd');891    ReactNoop.renderToRootWithID(<BrokenRender />, 'e');892    ReactNoop.renderToRootWithID(<span prop="f:6" />, 'f');893    expect(() => {894      ReactNoop.flush();895    }).toThrow('Hello');896    expect(ReactNoop.getChildren('a')).toEqual([]);897    expect(ReactNoop.getChildren('b')).toEqual([span('b:6')]);898    expect(ReactNoop.getChildren('c')).toEqual([]);899    expect(ReactNoop.getChildren('d')).toEqual([span('d:6')]);900    expect(ReactNoop.getChildren('e')).toEqual([]);901    expect(ReactNoop.getChildren('f')).toEqual([span('f:6')]);902    ReactNoop.unmountRootWithID('a');903    ReactNoop.unmountRootWithID('b');904    ReactNoop.unmountRootWithID('c');905    ReactNoop.unmountRootWithID('d');906    ReactNoop.unmountRootWithID('e');907    ReactNoop.unmountRootWithID('f');908    ReactNoop.flush();909    expect(ReactNoop.getChildren('a')).toEqual(null);910    expect(ReactNoop.getChildren('b')).toEqual(null);911    expect(ReactNoop.getChildren('c')).toEqual(null);912    expect(ReactNoop.getChildren('d')).toEqual(null);913    expect(ReactNoop.getChildren('e')).toEqual(null);914    expect(ReactNoop.getChildren('f')).toEqual(null);915  });916  it('unwinds the context stack correctly on error', () => {917    class Provider extends React.Component {918      static childContextTypes = {message: PropTypes.string};919      static contextTypes = {message: PropTypes.string};920      getChildContext() {921        return {922          message: (this.context.message || '') + this.props.message,923        };924      }925      render() {926        return this.props.children;927      }928    }929    function Connector(props, context) {930      return <span prop={context.message} />;931    }932    Connector.contextTypes = {933      message: PropTypes.string,934    };935    function BadRender() {936      throw new Error('render error');937    }938    class Boundary extends React.Component {939      state = {error: null};940      componentDidCatch(error) {941        this.setState({error});942      }943      render() {944        return (945          <Provider message="b">946            <Provider message="c">947              <Provider message="d">948                <Provider message="e">949                  {!this.state.error && <BadRender />}950                </Provider>951              </Provider>952            </Provider>953          </Provider>954        );955      }956    }957    ReactNoop.render(958      <Provider message="a">959        <Boundary />960        <Connector />961      </Provider>,962    );963    expect(ReactNoop.flush).toWarnDev(964      'Legacy context API has been detected within a strict-mode tree: \n\n' +965        'Please update the following components: Connector, Provider',966      {withoutStack: true},967    );968    // If the context stack does not unwind, span will get 'abcde'969    expect(ReactNoop.getChildren()).toEqual([span('a')]);970  });971  it('catches reconciler errors in a boundary during mounting', () => {972    class ErrorBoundary extends React.Component {973      state = {error: null};974      componentDidCatch(error) {975        this.setState({error});976      }977      render() {978        if (this.state.error) {979          return <span prop={this.state.error.message} />;980        }981        return this.props.children;982      }983    }984    const InvalidType = undefined;985    function BrokenRender(props) {986      return <InvalidType />;987    }988    ReactNoop.render(989      <ErrorBoundary>990        <BrokenRender />991      </ErrorBoundary>,992    );993    expect(ReactNoop.flush).toWarnDev([994      'Warning: React.createElement: type is invalid -- expected a string',995      // React retries once on error996      'Warning: React.createElement: type is invalid -- expected a string',997    ]);998    expect(ReactNoop.getChildren()).toEqual([999      span(1000        'Element type is invalid: expected a string (for built-in components) or ' +1001          'a class/function (for composite components) but got: undefined.' +1002          (__DEV__1003            ? " You likely forgot to export your component from the file it's " +1004              'defined in, or you might have mixed up default and named imports.' +1005              '\n\nCheck the render method of `BrokenRender`.'1006            : ''),1007      ),1008    ]);1009  });1010  it('catches reconciler errors in a boundary during update', () => {1011    class ErrorBoundary extends React.Component {1012      state = {error: null};1013      componentDidCatch(error) {1014        this.setState({error});1015      }1016      render() {1017        if (this.state.error) {1018          return <span prop={this.state.error.message} />;1019        }1020        return this.props.children;1021      }1022    }1023    const InvalidType = undefined;1024    function BrokenRender(props) {1025      return props.fail ? <InvalidType /> : <span />;1026    }1027    ReactNoop.render(1028      <ErrorBoundary>1029        <BrokenRender fail={false} />1030      </ErrorBoundary>,1031    );1032    ReactNoop.flush();1033    ReactNoop.render(1034      <ErrorBoundary>1035        <BrokenRender fail={true} />1036      </ErrorBoundary>,1037    );1038    expect(ReactNoop.flush).toWarnDev([1039      'Warning: React.createElement: type is invalid -- expected a string',1040      // React retries once on error1041      'Warning: React.createElement: type is invalid -- expected a string',1042    ]);1043    expect(ReactNoop.getChildren()).toEqual([1044      span(1045        'Element type is invalid: expected a string (for built-in components) or ' +1046          'a class/function (for composite components) but got: undefined.' +1047          (__DEV__1048            ? " You likely forgot to export your component from the file it's " +1049              'defined in, or you might have mixed up default and named imports.' +1050              '\n\nCheck the render method of `BrokenRender`.'1051            : ''),1052      ),1053    ]);1054  });1055  it('recovers from uncaught reconciler errors', () => {1056    const InvalidType = undefined;1057    expect(() => ReactNoop.render(<InvalidType />)).toWarnDev(1058      'Warning: React.createElement: type is invalid -- expected a string',1059      {withoutStack: true},1060    );1061    expect(ReactNoop.flush).toThrowError(1062      'Element type is invalid: expected a string (for built-in components) or ' +1063        'a class/function (for composite components) but got: undefined.' +1064        (__DEV__1065          ? " You likely forgot to export your component from the file it's " +1066            'defined in, or you might have mixed up default and named imports.'1067          : ''),1068    );1069    ReactNoop.render(<span prop="hi" />);1070    ReactNoop.flush();1071    expect(ReactNoop.getChildren()).toEqual([span('hi')]);1072  });1073  it('unmounts components with uncaught errors', () => {1074    const ops = [];1075    let inst;1076    class BrokenRenderAndUnmount extends React.Component {1077      state = {fail: false};1078      componentWillUnmount() {1079        ops.push('BrokenRenderAndUnmount componentWillUnmount');1080      }1081      render() {1082        inst = this;1083        if (this.state.fail) {1084          throw new Error('Hello.');1085        }1086        return null;1087      }1088    }1089    class Parent extends React.Component {1090      componentWillUnmount() {1091        ops.push('Parent componentWillUnmount [!]');1092        throw new Error('One does not simply unmount me.');1093      }1094      render() {1095        return this.props.children;1096      }1097    }1098    ReactNoop.render(1099      <Parent>1100        <Parent>1101          <BrokenRenderAndUnmount />1102        </Parent>1103      </Parent>,1104    );1105    ReactNoop.flush();1106    inst.setState({fail: true});1107    expect(() => {1108      ReactNoop.flush();1109    }).toThrowError('Hello.');1110    expect(ops).toEqual([1111      // Attempt to clean up.1112      // Errors in parents shouldn't stop children from unmounting.1113      'Parent componentWillUnmount [!]',1114      'Parent componentWillUnmount [!]',1115      'BrokenRenderAndUnmount componentWillUnmount',1116    ]);1117    expect(ReactNoop.getChildren()).toEqual([]);1118  });1119  it('does not interrupt unmounting if detaching a ref throws', () => {1120    let ops = [];1121    class Bar extends React.Component {1122      componentWillUnmount() {1123        ops.push('Bar unmount');1124      }1125      render() {1126        return <span prop="Bar" />;1127      }1128    }1129    function barRef(inst) {1130      if (inst === null) {1131        ops.push('barRef detach');1132        throw new Error('Detach error');1133      }1134      ops.push('barRef attach');1135    }1136    function Foo(props) {1137      return <div>{props.hide ? null : <Bar ref={barRef} />}</div>;1138    }1139    ReactNoop.render(<Foo />);1140    ReactNoop.flush();1141    expect(ops).toEqual(['barRef attach']);1142    expect(ReactNoop.getChildren()).toEqual([div(span('Bar'))]);1143    ops = [];1144    // Unmount1145    ReactNoop.render(<Foo hide={true} />);1146    expect(() => ReactNoop.flush()).toThrow('Detach error');1147    expect(ops).toEqual([1148      'barRef detach',1149      // Bar should unmount even though its ref threw an error while detaching1150      'Bar unmount',1151    ]);1152    // Because there was an error, entire tree should unmount1153    expect(ReactNoop.getChildren()).toEqual([]);1154  });1155  it('handles error thrown by host config while working on failed root', () => {1156    ReactNoop.render(<errorInBeginPhase />);1157    expect(() => ReactNoop.flush()).toThrow('Error in host config.');1158  });1159  it('handles error thrown by top-level callback', () => {1160    ReactNoop.render(<div />, () => {1161      throw new Error('Error!');1162    });1163    expect(() => ReactNoop.flush()).toThrow('Error!');1164  });1165  it('error boundaries capture non-errors', () => {1166    spyOnProd(console, 'error');1167    spyOnDev(console, 'error');1168    let ops = [];1169    class ErrorBoundary extends React.Component {1170      state = {error: null};1171      componentDidCatch(error) {1172        // Should not be called1173        ops.push('componentDidCatch');1174        this.setState({error});1175      }1176      render() {1177        if (this.state.error) {1178          ops.push('ErrorBoundary (catch)');1179          return (1180            <span1181              prop={`Caught an error: ${this.state.error.nonStandardMessage}`}1182            />1183          );1184        }1185        ops.push('ErrorBoundary (try)');1186        return this.props.children;1187      }1188    }1189    function Indirection(props) {1190      ops.push('Indirection');1191      return props.children;1192    }1193    const notAnError = {nonStandardMessage: 'oops'};1194    function BadRender() {1195      ops.push('BadRender');1196      throw notAnError;1197    }1198    ReactNoop.render(1199      <ErrorBoundary>1200        <Indirection>1201          <BadRender />1202        </Indirection>1203      </ErrorBoundary>,1204    );1205    ReactNoop.flush();1206    expect(ops).toEqual([1207      'ErrorBoundary (try)',1208      'Indirection',1209      'BadRender',1210      // React retries one more time1211      'ErrorBoundary (try)',1212      'Indirection',1213      'BadRender',1214      // Errored again on retry. Now handle it.1215      'componentDidCatch',1216      'ErrorBoundary (catch)',1217    ]);1218    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: oops')]);1219    if (__DEV__) {1220      expect(console.error).toHaveBeenCalledTimes(1);1221      expect(console.error.calls.argsFor(0)[0]).toContain(1222        'The above error occurred in the <BadRender> component:',1223      );1224    } else {1225      expect(console.error).toHaveBeenCalledTimes(1);1226      expect(console.error.calls.argsFor(0)[0]).toBe(notAnError);1227    }1228  });1229  // TODO: Error boundary does not catch promises1230  it('continues working on siblings of a component that throws', () => {1231    class ErrorBoundary extends React.Component {1232      state = {error: null};1233      componentDidCatch(error) {1234        ReactNoop.yield('componentDidCatch');1235        this.setState({error});1236      }1237      render() {1238        if (this.state.error) {1239          ReactNoop.yield('ErrorBoundary (catch)');1240          return <ErrorMessage error={this.state.error} />;1241        }1242        ReactNoop.yield('ErrorBoundary (try)');1243        return this.props.children;1244      }1245    }1246    function ErrorMessage(props) {1247      ReactNoop.yield('ErrorMessage');1248      return <span prop={`Caught an error: ${props.error.message}`} />;1249    }1250    function BadRenderSibling(props) {1251      ReactNoop.yield('BadRenderSibling');1252      return null;1253    }1254    function BadRender() {1255      ReactNoop.yield('throw');1256      throw new Error('oops!');1257    }1258    ReactNoop.render(1259      <ErrorBoundary>1260        <BadRender />1261        <BadRenderSibling />1262        <BadRenderSibling />1263      </ErrorBoundary>,1264    );1265    expect(ReactNoop.flush()).toEqual([1266      'ErrorBoundary (try)',1267      'throw',1268      // Continue rendering siblings after BadRender throws1269      'BadRenderSibling',1270      'BadRenderSibling',1271      // React retries one more time1272      'ErrorBoundary (try)',1273      'throw',1274      'BadRenderSibling',1275      'BadRenderSibling',1276      // Errored again on retry. Now handle it.1277      'componentDidCatch',1278      'ErrorBoundary (catch)',1279      'ErrorMessage',1280    ]);1281    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: oops!')]);1282  });1283  it('calls the correct lifecycles on the error boundary after catching an error (mixed)', () => {1284    // This test seems a bit contrived, but it's based on an actual regression1285    // where we checked for the existence of didUpdate instead of didMount, and1286    // didMount was not defined.1287    function BadRender() {1288      ReactNoop.yield('throw');1289      throw new Error('oops!');1290    }1291    class Parent extends React.Component {1292      state = {error: null, other: false};1293      componentDidCatch(error) {1294        ReactNoop.yield('did catch');1295        this.setState({error});1296      }1297      componentDidUpdate() {1298        ReactNoop.yield('did update');1299      }1300      render() {1301        if (this.state.error) {1302          ReactNoop.yield('render error message');1303          return <span prop={`Caught an error: ${this.state.error.message}`} />;1304        }1305        ReactNoop.yield('render');1306        return <BadRender />;1307      }1308    }1309    ReactNoop.render(<Parent step={1} />);1310    ReactNoop.flushThrough([1311      'render',1312      'throw',1313      'render',1314      'throw',1315      'did catch',1316      'render error message',1317      'did update',1318    ]);1319    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: oops!')]);1320  });1321  it('provides component stack to the error boundary with componentDidCatch', () => {1322    class ErrorBoundary extends React.Component {1323      state = {error: null, errorInfo: null};1324      componentDidCatch(error, errorInfo) {1325        this.setState({error, errorInfo});1326      }1327      render() {1328        if (this.state.errorInfo) {1329          ReactNoop.yield('render error message');1330          return (1331            <span1332              prop={`Caught an error:${normalizeCodeLocInfo(1333                this.state.errorInfo.componentStack,1334              )}.`}1335            />1336          );1337        }1338        return this.props.children;1339      }1340    }1341    function BrokenRender(props) {1342      throw new Error('Hello');1343    }1344    ReactNoop.render(1345      <ErrorBoundary>1346        <BrokenRender />1347      </ErrorBoundary>,1348    );1349    ReactNoop.flushDeferredPri();1350    expect(ReactNoop.getChildren()).toEqual([1351      span(1352        'Caught an error:\n' +1353          (__DEV__1354            ? '    in BrokenRender (at **)\n'1355            : '    in BrokenRender\n') +1356          (__DEV__ ? '    in ErrorBoundary (at **).' : '    in ErrorBoundary.'),1357      ),1358    ]);1359  });1360  it('does not provide component stack to the error boundary with getDerivedStateFromError', () => {1361    class ErrorBoundary extends React.Component {1362      state = {error: null};1363      static getDerivedStateFromError(error, errorInfo) {1364        expect(errorInfo).toBeUndefined();1365        return {error};1366      }1367      render() {1368        if (this.state.error) {1369          return <span prop={`Caught an error: ${this.state.error.message}`} />;1370        }1371        return this.props.children;1372      }1373    }1374    function BrokenRender(props) {1375      throw new Error('Hello');1376    }1377    ReactNoop.render(1378      <ErrorBoundary>1379        <BrokenRender />1380      </ErrorBoundary>,1381    );1382    ReactNoop.flushDeferredPri();1383    expect(ReactNoop.getChildren()).toEqual([span('Caught an error: Hello')]);1384  });1385  it('handles error thrown inside getDerivedStateFromProps of a module-style context provider', () => {1386    function Provider() {1387      return {1388        getChildContext() {1389          return {foo: 'bar'};1390        },1391        render() {1392          return 'Hi';1393        },1394      };1395    }1396    Provider.childContextTypes = {1397      x: () => {},1398    };1399    Provider.getDerivedStateFromProps = () => {1400      throw new Error('Oops!');1401    };1402    ReactNoop.render(<Provider />);1403    expect(() => {1404      expect(() => ReactNoop.flush()).toThrow('Oops!');1405    }).toWarnDev(1406      'Legacy context API has been detected within a strict-mode tree: \n\n' +1407        'Please update the following components: Provider',1408      {withoutStack: true},1409    );1410  });...

Full Screen

Full Screen

error_test.js

Source:error_test.js Github

copy

Full Screen

1// Licensed to the Software Freedom Conservancy (SFC) under one2// or more contributor license agreements.  See the NOTICE file3// distributed with this work for additional information4// regarding copyright ownership.  The SFC licenses this file5// to you under the Apache License, Version 2.0 (the6// "License"); you may not use this file except in compliance7// with the License.  You may obtain a copy of the License at8//9//   http://www.apache.org/licenses/LICENSE-2.010//11// Unless required by applicable law or agreed to in writing,12// software distributed under the License is distributed on an13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY14// KIND, either express or implied.  See the License for the15// specific language governing permissions and limitations16// under the License.17'use strict';18describe('error', function() {19  let assert = require('assert');20  let error = require('../../lib/error');21  describe('checkResponse', function() {22    it('defaults to WebDriverError if type is unrecognized', function() {23      assert.throws(24          () => error.checkResponse({error: 'foo', message: 'hi there'}),25          (e) => {26            assert.equal(e.constructor, error.WebDriverError);27            return true;28          });29    });30    it('does not throw if error property is not a string', function() {31      let resp = {error: 123, message: 'abc123'};32      let out = error.checkResponse(resp);33      assert.strictEqual(out, resp);34    });35    test('unknown error', error.WebDriverError);36    test('element not interactable', error.ElementNotInteractableError);37    test('element not selectable', error.ElementNotSelectableError);38    test('element not visible', error.ElementNotVisibleError);39    test('invalid argument', error.InvalidArgumentError);40    test('invalid cookie domain', error.InvalidCookieDomainError);41    test('invalid element coordinates', error.InvalidElementCoordinatesError);42    test('invalid element state', error.InvalidElementStateError);43    test('invalid selector', error.InvalidSelectorError);44    test('invalid session id', error.NoSuchSessionError);45    test('javascript error', error.JavascriptError);46    test('move target out of bounds', error.MoveTargetOutOfBoundsError);47    test('no such alert', error.NoSuchAlertError);48    test('no such element', error.NoSuchElementError);49    test('no such frame', error.NoSuchFrameError);50    test('no such window', error.NoSuchWindowError);51    test('script timeout', error.ScriptTimeoutError);52    test('session not created', error.SessionNotCreatedError);53    test('stale element reference', error.StaleElementReferenceError);54    test('timeout', error.TimeoutError);55    test('unable to set cookie', error.UnableToSetCookieError);56    test('unable to capture screen', error.UnableToCaptureScreenError);57    test('unexpected alert open', error.UnexpectedAlertOpenError);58    test('unknown command', error.UnknownCommandError);59    test('unknown method', error.UnknownMethodError);60    test('unsupported operation', error.UnsupportedOperationError);61    function test(status, expectedType) {62      it(`"${status}" => ${expectedType.name}`, function() {63        assert.throws(64            () => error.checkResponse({error: status, message: 'oops'}),65            (e) => {66              assert.equal(expectedType, e.constructor);67              assert.equal(e.message, 'oops');68              return true;69            });70      });71    }72  });73  describe('encodeError', function() {74    describe('defaults to an unknown error', function() {75      it('for a generic error value', function() {76        runTest('hi', 'unknown error', 'hi');77        runTest(1, 'unknown error', '1');78        runTest({}, 'unknown error', '[object Object]');79      });80      it('for a generic Error object', function() {81        runTest(Error('oops'), 'unknown error', 'oops');82        runTest(TypeError('bad value'), 'unknown error', 'bad value');83      });84    });85    test(error.WebDriverError, 'unknown error');86    test(error.ElementNotSelectableError, 'element not selectable');87    test(error.ElementNotVisibleError, 'element not visible');88    test(error.InvalidArgumentError, 'invalid argument');89    test(error.InvalidCookieDomainError, 'invalid cookie domain');90    test(error.InvalidElementStateError, 'invalid element state');91    test(error.InvalidSelectorError, 'invalid selector');92    test(error.NoSuchSessionError, 'invalid session id');93    test(error.JavascriptError, 'javascript error');94    test(error.MoveTargetOutOfBoundsError, 'move target out of bounds');95    test(error.NoSuchAlertError, 'no such alert');96    test(error.NoSuchElementError, 'no such element');97    test(error.NoSuchFrameError, 'no such frame');98    test(error.NoSuchWindowError, 'no such window');99    test(error.ScriptTimeoutError, 'script timeout');100    test(error.SessionNotCreatedError, 'session not created');101    test(error.StaleElementReferenceError, 'stale element reference');102    test(error.TimeoutError, 'timeout');103    test(error.UnableToSetCookieError, 'unable to set cookie');104    test(error.UnableToCaptureScreenError, 'unable to capture screen');105    test(error.UnexpectedAlertOpenError, 'unexpected alert open');106    test(error.UnknownCommandError, 'unknown command');107    test(error.UnknownMethodError, 'unknown method');108    test(error.UnsupportedOperationError, 'unsupported operation');109    function test(ctor, code) {110      it(`${ctor.name} => "${code}"`, () => {111        runTest(new ctor('oops'), code, 'oops');112      });113    }114    function runTest(err, code, message) {115      let obj = error.encodeError(err);116      assert.strictEqual(obj['error'], code);117      assert.strictEqual(obj['message'], message);118    }119  });120  describe('throwDecodedError', function() {121    it('defaults to WebDriverError if type is unrecognized', function() {122      assert.throws(123          () => error.throwDecodedError({error: 'foo', message: 'hi there'}),124          (e) => {125            assert.equal(e.constructor, error.WebDriverError);126            return true;127          });128    });129    it('throws generic error if encoded data is not valid', function() {130      assert.throws(131          () => error.throwDecodedError({error: 123, message: 'abc123'}),132          (e) => {133            assert.strictEqual(e.constructor, error.WebDriverError);134            return true;135          });136      assert.throws(137          () => error.throwDecodedError('null'),138          (e) => {139            assert.strictEqual(e.constructor, error.WebDriverError);140            return true;141          });142      assert.throws(143          () => error.throwDecodedError(''),144          (e) => {145            assert.strictEqual(e.constructor, error.WebDriverError);146            return true;147          });148    });149    test('unknown error', error.WebDriverError);150    test('element not selectable', error.ElementNotSelectableError);151    test('element not visible', error.ElementNotVisibleError);152    test('invalid argument', error.InvalidArgumentError);153    test('invalid cookie domain', error.InvalidCookieDomainError);154    test('invalid element coordinates', error.InvalidElementCoordinatesError);155    test('invalid element state', error.InvalidElementStateError);156    test('invalid selector', error.InvalidSelectorError);157    test('invalid session id', error.NoSuchSessionError);158    test('javascript error', error.JavascriptError);159    test('move target out of bounds', error.MoveTargetOutOfBoundsError);160    test('no such alert', error.NoSuchAlertError);161    test('no such element', error.NoSuchElementError);162    test('no such frame', error.NoSuchFrameError);163    test('no such window', error.NoSuchWindowError);164    test('script timeout', error.ScriptTimeoutError);165    test('session not created', error.SessionNotCreatedError);166    test('stale element reference', error.StaleElementReferenceError);167    test('timeout', error.TimeoutError);168    test('unable to set cookie', error.UnableToSetCookieError);169    test('unable to capture screen', error.UnableToCaptureScreenError);170    test('unexpected alert open', error.UnexpectedAlertOpenError);171    test('unknown command', error.UnknownCommandError);172    test('unknown method', error.UnknownMethodError);173    test('unsupported operation', error.UnsupportedOperationError);174    it('leaves remoteStacktrace empty if not in encoding', function() {175      assert.throws(176          () => error.throwDecodedError({177            error: 'session not created',178            message: 'oops'179          }),180          (e) => {181            assert.strictEqual(e.constructor, error.SessionNotCreatedError);182            assert.strictEqual(e.message, 'oops');183            assert.strictEqual(e.remoteStacktrace, '');184            return true;185          });186    });187    function test(status, expectedType) {188      it(`"${status}" => ${expectedType.name}`, function() {189        assert.throws(190            () => error.throwDecodedError({191              error: status,192              message: 'oops',193              stacktrace: 'some-stacktrace'194            }),195            (e) => {196              assert.strictEqual(e.constructor, expectedType);197              assert.strictEqual(e.message, 'oops');198              assert.strictEqual(e.remoteStacktrace, 'some-stacktrace');199              return true;200            });201      });202    }203  });204  describe('checkLegacyResponse', function() {205    it('does not throw for success', function() {206      let resp = {status: error.ErrorCode.SUCCESS};207      assert.strictEqual(resp, error.checkLegacyResponse(resp));208    });209    test('NO_SUCH_ELEMENT', error.NoSuchElementError);210    test('NO_SUCH_FRAME', error.NoSuchFrameError);211    test('UNKNOWN_COMMAND', error.UnsupportedOperationError);212    test('UNSUPPORTED_OPERATION', error.UnsupportedOperationError);213    test('STALE_ELEMENT_REFERENCE', error.StaleElementReferenceError);214    test('ELEMENT_NOT_VISIBLE', error.ElementNotVisibleError);215    test('INVALID_ELEMENT_STATE', error.InvalidElementStateError);216    test('UNKNOWN_ERROR', error.WebDriverError);217    test('ELEMENT_NOT_SELECTABLE', error.ElementNotSelectableError);218    test('JAVASCRIPT_ERROR', error.JavascriptError);219    test('XPATH_LOOKUP_ERROR', error.InvalidSelectorError);220    test('TIMEOUT', error.TimeoutError);221    test('NO_SUCH_WINDOW', error.NoSuchWindowError);222    test('INVALID_COOKIE_DOMAIN', error.InvalidCookieDomainError);223    test('UNABLE_TO_SET_COOKIE', error.UnableToSetCookieError);224    test('UNEXPECTED_ALERT_OPEN', error.UnexpectedAlertOpenError);225    test('NO_SUCH_ALERT', error.NoSuchAlertError);226    test('SCRIPT_TIMEOUT', error.ScriptTimeoutError);227    test('INVALID_ELEMENT_COORDINATES', error.InvalidElementCoordinatesError);228    test('INVALID_SELECTOR_ERROR', error.InvalidSelectorError);229    test('SESSION_NOT_CREATED', error.SessionNotCreatedError);230    test('MOVE_TARGET_OUT_OF_BOUNDS', error.MoveTargetOutOfBoundsError);231    test('INVALID_XPATH_SELECTOR', error.InvalidSelectorError);232    test('INVALID_XPATH_SELECTOR_RETURN_TYPE', error.InvalidSelectorError);233    test('METHOD_NOT_ALLOWED', error.UnsupportedOperationError);234    describe('UnexpectedAlertOpenError', function() {235      it('includes alert text from the response object', function() {236        let response = {237          status: error.ErrorCode.UNEXPECTED_ALERT_OPEN,238          value: {239            message: 'hi',240            alert: {text: 'alert text here'}241          }242        };243        assert.throws(244            () => error.checkLegacyResponse(response),245            (e) => {246              assert.equal(error.UnexpectedAlertOpenError, e.constructor);247              assert.equal(e.message, 'hi');248              assert.equal(e.getAlertText(), 'alert text here');249              return true;250            });251      });252      it('uses an empty string if alert text omitted', function() {253        let response = {254          status: error.ErrorCode.UNEXPECTED_ALERT_OPEN,255          value: {256            message: 'hi'257          }258        };259        assert.throws(260            () => error.checkLegacyResponse(response),261            (e) => {262              assert.equal(error.UnexpectedAlertOpenError, e.constructor);263              assert.equal(e.message, 'hi');264              assert.equal(e.getAlertText(), '');265              return true;266            });267      });268    });269    function test(codeKey, expectedType) {270      it(`${codeKey} => ${expectedType.name}`, function() {271        let code = error.ErrorCode[codeKey];272        let resp = {status: code, value: {message: 'hi'}};273        assert.throws(274            () => error.checkLegacyResponse(resp),275            (e) => {276              assert.equal(expectedType, e.constructor);277              assert.equal(e.message, 'hi');278              return true;279            });280      });281    }282  });...

Full Screen

Full Screen

error.js

Source:error.js Github

copy

Full Screen

1// Copyright 2011 The Closure Library Authors. All Rights Reserved.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7//      http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS-IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14/**15 * @fileoverview Error classes for the IndexedDB wrapper.16 *17 */18goog.provide('goog.db.Error');19goog.provide('goog.db.Error.ErrorCode');20goog.provide('goog.db.Error.ErrorName');21goog.provide('goog.db.Error.VersionChangeBlockedError');22goog.require('goog.debug.Error');23/**24 * A database error. Since the stack trace can be unhelpful in an asynchronous25 * context, the error provides a message about where it was produced.26 *27 * @param {number|!DOMError} error The DOMError instance returned by the28 *     browser for Chrome22+, or an error code for previous versions.29 * @param {string} context A description of where the error occured.30 * @param {string=} opt_message Additional message.31 * @constructor32 * @extends {goog.debug.Error}33 */34goog.db.Error = function(error, context, opt_message) {35  var errorCode = null;36  var internalError = null;37  if (goog.isNumber(error)) {38    errorCode = error;39    internalError = {name: goog.db.Error.getName(errorCode)};40  } else {41    internalError = error;42    errorCode = goog.db.Error.getCode(error.name);43  }44  /**45   * The code for this error.46   *47   * @type {number}48   */49  this.code = errorCode;50  /**51   * The DOMException as returned by the browser.52   *53   * @type {!DOMError}54   * @private55   */56  this.error_ = /** @type {!DOMError} */ (internalError);57  var msg = 'Error ' + context + ': ' + this.getName();58  if (opt_message) {59    msg += ', ' + opt_message;60  }61  goog.base(this, msg);62};63goog.inherits(goog.db.Error, goog.debug.Error);64/**65 * @return {string} The name of the error.66 */67goog.db.Error.prototype.getName = function()  {68  return this.error_.name;69};70/**71 * A specific kind of database error. If a Version Change is unable to proceed72 * due to other open database connections, it will block and this error will be73 * thrown.74 *75 * @constructor76 * @extends {goog.debug.Error}77 */78goog.db.Error.VersionChangeBlockedError = function() {79  goog.base(this, 'Version change blocked');80};81goog.inherits(goog.db.Error.VersionChangeBlockedError, goog.debug.Error);82/**83 * Synthetic error codes for database errors, for use when IndexedDB84 * support is not available. This numbering differs in practice85 * from the browser implementations, but it is not meant to be reliable:86 * this object merely ensures that goog.db.Error is loadable on platforms87 * that do not support IndexedDB.88 *89 * @enum {number}90 * @private91 */92goog.db.Error.DatabaseErrorCode_ = {93  UNKNOWN_ERR: 1,94  NON_TRANSIENT_ERR: 2,95  NOT_FOUND_ERR: 3,96  CONSTRAINT_ERR: 4,97  DATA_ERR: 5,98  NOT_ALLOWED_ERR: 6,99  TRANSACTION_INACTIVE_ERR: 7,100  ABORT_ERR: 8,101  READ_ONLY_ERR: 9,102  TRANSIENT_ERR: 11,103  TIMEOUT_ERR: 10,104  QUOTA_ERR: 11,105  INVALID_ACCESS_ERR: 12,106  INVALID_STATE_ERR: 13107};108/**109 * Error codes for database errors.110 * @see http://www.w3.org/TR/IndexedDB/#idl-def-IDBDatabaseException111 *112 * @enum {number}113 */114goog.db.Error.ErrorCode = {115  UNKNOWN_ERR: (goog.global.IDBDatabaseException ||116      goog.global.webkitIDBDatabaseException ||117      goog.db.Error.DatabaseErrorCode_).UNKNOWN_ERR,118  NON_TRANSIENT_ERR: (goog.global.IDBDatabaseException ||119      goog.global.webkitIDBDatabaseException ||120      goog.db.Error.DatabaseErrorCode_).NON_TRANSIENT_ERR,121  NOT_FOUND_ERR: (goog.global.IDBDatabaseException ||122      goog.global.webkitIDBDatabaseException ||123      goog.db.Error.DatabaseErrorCode_).NOT_FOUND_ERR,124  CONSTRAINT_ERR: (goog.global.IDBDatabaseException ||125      goog.global.webkitIDBDatabaseException ||126      goog.db.Error.DatabaseErrorCode_).CONSTRAINT_ERR,127  DATA_ERR: (goog.global.IDBDatabaseException ||128      goog.global.webkitIDBDatabaseException ||129      goog.db.Error.DatabaseErrorCode_).DATA_ERR,130  NOT_ALLOWED_ERR: (goog.global.IDBDatabaseException ||131      goog.global.webkitIDBDatabaseException ||132      goog.db.Error.DatabaseErrorCode_).NOT_ALLOWED_ERR,133  TRANSACTION_INACTIVE_ERR: (goog.global.IDBDatabaseException ||134      goog.global.webkitIDBDatabaseException ||135      goog.db.Error.DatabaseErrorCode_).TRANSACTION_INACTIVE_ERR,136  ABORT_ERR: (goog.global.IDBDatabaseException ||137      goog.global.webkitIDBDatabaseException ||138      goog.db.Error.DatabaseErrorCode_).ABORT_ERR,139  READ_ONLY_ERR: (goog.global.IDBDatabaseException ||140      goog.global.webkitIDBDatabaseException ||141      goog.db.Error.DatabaseErrorCode_).READ_ONLY_ERR,142  TIMEOUT_ERR: (goog.global.IDBDatabaseException ||143      goog.global.webkitIDBDatabaseException ||144      goog.db.Error.DatabaseErrorCode_).TIMEOUT_ERR,145  QUOTA_ERR: (goog.global.IDBDatabaseException ||146      goog.global.webkitIDBDatabaseException ||147      goog.db.Error.DatabaseErrorCode_).QUOTA_ERR,148  INVALID_ACCESS_ERR: (goog.global.DOMException ||149      goog.db.Error.DatabaseErrorCode_).INVALID_ACCESS_ERR,150  INVALID_STATE_ERR: (goog.global.DOMException ||151      goog.db.Error.DatabaseErrorCode_).INVALID_STATE_ERR152};153/**154 * Translates an error code into a more useful message.155 *156 * @param {number} code Error code.157 * @return {string} A debug message.158 */159goog.db.Error.getMessage = function(code) {160  switch (code) {161    case goog.db.Error.ErrorCode.UNKNOWN_ERR:162      return 'Unknown error';163    case goog.db.Error.ErrorCode.NON_TRANSIENT_ERR:164      return 'Invalid operation';165    case goog.db.Error.ErrorCode.NOT_FOUND_ERR:166      return 'Required database object not found';167    case goog.db.Error.ErrorCode.CONSTRAINT_ERR:168      return 'Constraint unsatisfied';169    case goog.db.Error.ErrorCode.DATA_ERR:170      return 'Invalid data';171    case goog.db.Error.ErrorCode.NOT_ALLOWED_ERR:172      return 'Operation disallowed';173    case goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR:174      return 'Transaction not active';175    case goog.db.Error.ErrorCode.ABORT_ERR:176      return 'Request aborted';177    case goog.db.Error.ErrorCode.READ_ONLY_ERR:178      return 'Modifying operation not allowed in a read-only transaction';179    case goog.db.Error.ErrorCode.TIMEOUT_ERR:180      return 'Transaction timed out';181    case goog.db.Error.ErrorCode.QUOTA_ERR:182      return 'Database storage space quota exceeded';183    case goog.db.Error.ErrorCode.INVALID_ACCESS_ERR:184      return 'Invalid operation';185    case goog.db.Error.ErrorCode.INVALID_STATE_ERR:186      return 'Invalid state';187    default:188      return 'Unrecognized exception with code ' + code;189  }190};191/**192 * Names of all possible errors as returned from the browser.193 * @see http://www.w3.org/TR/IndexedDB/#exceptions194 * @enum {string}195 */196goog.db.Error.ErrorName = {197  ABORT_ERR: 'AbortError',198  CONSTRAINT_ERR: 'ConstraintError',199  DATA_CLONE_ERR: 'DataCloneError',200  DATA_ERR: 'DataError',201  INVALID_ACCESS_ERR: 'InvalidAccessError',202  INVALID_STATE_ERR: 'InvalidStateError',203  NOT_FOUND_ERR: 'NotFoundError',204  QUOTA_EXCEEDED_ERR: 'QuotaExceededError',205  READ_ONLY_ERR: 'ReadOnlyError',206  SYNTAX_ERROR: 'SyntaxError',207  TIMEOUT_ERR: 'TimeoutError',208  TRANSACTION_INACTIVE_ERR: 'TransactionInactiveError',209  UNKNOWN_ERR: 'UnknownError',210  VERSION_ERR: 'VersionError'211};212/**213 * Translates an error name to an error code. This is purely kept for backwards214 * compatibility with Chrome21.215 *216 * @param {string} name The name of the erorr.217 * @return {number} The error code corresponding to the error.218 */219goog.db.Error.getCode = function(name) {220  switch (name) {221    case goog.db.Error.ErrorName.UNKNOWN_ERR:222      return goog.db.Error.ErrorCode.UNKNOWN_ERR;223    case goog.db.Error.ErrorName.NOT_FOUND_ERR:224      return goog.db.Error.ErrorCode.NOT_FOUND_ERR;225    case goog.db.Error.ErrorName.CONSTRAINT_ERR:226      return goog.db.Error.ErrorCode.CONSTRAINT_ERR;227    case goog.db.Error.ErrorName.DATA_ERR:228      return goog.db.Error.ErrorCode.DATA_ERR;229    case goog.db.Error.ErrorName.TRANSACTION_INACTIVE_ERR:230      return goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR;231    case goog.db.Error.ErrorName.ABORT_ERR:232      return goog.db.Error.ErrorCode.ABORT_ERR;233    case goog.db.Error.ErrorName.READ_ONLY_ERR:234      return goog.db.Error.ErrorCode.READ_ONLY_ERR;235    case goog.db.Error.ErrorName.TIMEOUT_ERR:236      return goog.db.Error.ErrorCode.TIMEOUT_ERR;237    case goog.db.Error.ErrorName.QUOTA_EXCEEDED_ERR:238      return goog.db.Error.ErrorCode.QUOTA_ERR;239    case goog.db.Error.ErrorName.INVALID_ACCESS_ERR:240      return goog.db.Error.ErrorCode.INVALID_ACCESS_ERR;241    case goog.db.Error.ErrorName.INVALID_STATE_ERR:242      return goog.db.Error.ErrorCode.INVALID_STATE_ERR;243    default:244      return goog.db.Error.ErrorCode.UNKNOWN_ERR;245  }246};247/**248 * Converts an error code used by the old spec, to an error name used by the249 * latest spec.250 * @see http://www.w3.org/TR/IndexedDB/#exceptions251 *252 * @param {!goog.db.Error.ErrorCode|number} code The error code to convert.253 * @return {!goog.db.Error.ErrorName} The corresponding name of the error.254 */255goog.db.Error.getName = function(code) {256  switch (code) {257    case goog.db.Error.ErrorCode.UNKNOWN_ERR:258      return goog.db.Error.ErrorName.UNKNOWN_ERR;259    case goog.db.Error.ErrorCode.NOT_FOUND_ERR:260      return goog.db.Error.ErrorName.NOT_FOUND_ERR;261    case goog.db.Error.ErrorCode.CONSTRAINT_ERR:262      return goog.db.Error.ErrorName.CONSTRAINT_ERR;263    case goog.db.Error.ErrorCode.DATA_ERR:264      return goog.db.Error.ErrorName.DATA_ERR;265    case goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR:266      return goog.db.Error.ErrorName.TRANSACTION_INACTIVE_ERR;267    case goog.db.Error.ErrorCode.ABORT_ERR:268      return goog.db.Error.ErrorName.ABORT_ERR;269    case goog.db.Error.ErrorCode.READ_ONLY_ERR:270      return goog.db.Error.ErrorName.READ_ONLY_ERR;271    case goog.db.Error.ErrorCode.TIMEOUT_ERR:272      return goog.db.Error.ErrorName.TIMEOUT_ERR;273    case goog.db.Error.ErrorCode.QUOTA_ERR:274      return goog.db.Error.ErrorName.QUOTA_EXCEEDED_ERR;275    case goog.db.Error.ErrorCode.INVALID_ACCESS_ERR:276      return goog.db.Error.ErrorName.INVALID_ACCESS_ERR;277    case goog.db.Error.ErrorCode.INVALID_STATE_ERR:278      return goog.db.Error.ErrorName.INVALID_STATE_ERR;279    default:280      return goog.db.Error.ErrorName.UNKNOWN_ERR;281  }282};283/**284 * Constructs an goog.db.Error instance from an IDBRequest. This abstraction is285 * necessary to provide backwards compatibility with Chrome21.286 *287 * @param {!IDBRequest} request The request that failed.288 * @param {string} message The error message to add to err if it's wrapped.289 * @return {!goog.db.Error} The error that caused the failure.290 */291goog.db.Error.fromRequest = function(request, message) {292  if ('error' in request) {293    // Chrome 21 and before.294    return new goog.db.Error(request.error, message);295  } else if ('name' in request) {296    // Chrome 22+.297    var errorName = goog.db.Error.getName(request.errorCode);298    return new goog.db.Error(299        /**@type {!DOMError} */ ({name: errorName}), message);300  } else {301    return new goog.db.Error(/** @type {!DOMError} */ (302        {name: goog.db.Error.ErrorName.UNKNOWN_ERR}), message);303  }304};305/**306 * Constructs an goog.db.Error instance from an DOMException. This abstraction307 * is necessary to provide backwards compatibility with Chrome21.308 *309 * @param {!IDBDatabaseException} ex The exception that was thrown.310 * @param {string} message The error message to add to err if it's wrapped.311 * @return {!goog.db.Error} The error that caused the failure.312 * @suppress {invalidCasts} The cast from IDBDatabaseException to DOMError313 *     is invalid and will not compile.314 */315goog.db.Error.fromException = function(ex, message) {316  if ('name' in ex) {317    // Chrome 21 and before.318    return new goog.db.Error(/** @type {!DOMError} */ (ex), message);319  } else if ('code' in ex) {320    // Chrome 22+.321    var errorName = goog.db.Error.getName(ex.code);322    return new goog.db.Error(323        /** @type {!DOMError} */ ({name: errorName}), message);324  } else {325    return new goog.db.Error(/** @type {!DOMError} */ (326        {name: goog.db.Error.ErrorName.UNKNOWN_ERR}), message);327  }...

Full Screen

Full Screen

extension_error.js

Source:extension_error.js Github

copy

Full Screen

1// Copyright 2013 The Chromium Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4cr.define('extensions', function() {5  'use strict';6  /**7   * Clone a template within the extension error template collection.8   * @param {string} templateName The class name of the template to clone.9   * @return {HTMLElement} The clone of the template.10   */11  function cloneTemplate(templateName) {12    return /** @type {HTMLElement} */($('template-collection-extension-error').13        querySelector('.' + templateName).cloneNode(true));14  }15  /**16   * Checks that an Extension ID follows the proper format (i.e., is 3217   * characters long, is lowercase, and contains letters in the range [a, p]).18   * @param {string} id The Extension ID to test.19   * @return {boolean} Whether or not the ID is valid.20   */21  function idIsValid(id) {22    return /^[a-p]{32}$/.test(id);23  }24  /**25   * @param {!Array<(ManifestError|RuntimeError)>} errors26   * @param {number} id27   * @return {number} The index of the error with |id|, or -1 if not found.28   */29  function findErrorById(errors, id) {30    for (var i = 0; i < errors.length; ++i) {31      if (errors[i].id == id)32        return i;33    }34    return -1;35  }36  /**37   * Creates a new ExtensionError HTMLElement; this is used to show a38   * notification to the user when an error is caused by an extension.39   * @param {(RuntimeError|ManifestError)} error The error the element should40   *     represent.41   * @param {Element} boundary The boundary for the focus grid.42   * @constructor43   * @extends {cr.ui.FocusRow}44   */45  function ExtensionError(error, boundary) {46    var div = cloneTemplate('extension-error-metadata');47    div.__proto__ = ExtensionError.prototype;48    div.decorateWithError_(error, boundary);49    return div;50  }51  ExtensionError.prototype = {52    __proto__: cr.ui.FocusRow.prototype,53    /** @override */54    getEquivalentElement: function(element) {55      if (element.classList.contains('extension-error-metadata'))56        return this;57      if (element.classList.contains('error-delete-button')) {58        return /** @type {!HTMLElement} */ (this.querySelector(59            '.error-delete-button'));60      }61      assertNotReached();62      return element;63    },64    /**65     * @param {(RuntimeError|ManifestError)} error The error the element should66     *     represent.67     * @param {Element} boundary The boundary for the FocusGrid.68     * @private69     */70    decorateWithError_: function(error, boundary) {71      this.decorate(boundary);72      /**73       * The backing error.74       * @type {(ManifestError|RuntimeError)}75       */76      this.error = error;77      // Add an additional class for the severity level.78      if (error.type == chrome.developerPrivate.ErrorType.RUNTIME) {79        switch (error.severity) {80          case chrome.developerPrivate.ErrorLevel.LOG:81            this.classList.add('extension-error-severity-info');82            break;83          case chrome.developerPrivate.ErrorLevel.WARN:84            this.classList.add('extension-error-severity-warning');85            break;86          case chrome.developerPrivate.ErrorLevel.ERROR:87            this.classList.add('extension-error-severity-fatal');88            break;89          default:90            assertNotReached();91        }92      } else {93        // We classify manifest errors as "warnings".94        this.classList.add('extension-error-severity-warning');95      }96      var iconNode = document.createElement('img');97      iconNode.className = 'extension-error-icon';98      // TODO(hcarmona): Populate alt text with a proper description since this99      // icon conveys the severity of the error. (info, warning, fatal).100      iconNode.alt = '';101      this.insertBefore(iconNode, this.firstChild);102      var messageSpan = this.querySelector('.extension-error-message');103      messageSpan.textContent = error.message;104      var deleteButton = this.querySelector('.error-delete-button');105      deleteButton.addEventListener('click', function(e) {106        this.dispatchEvent(107            new CustomEvent('deleteExtensionError',108                            {bubbles: true, detail: this.error}));109      }.bind(this));110      this.addEventListener('click', function(e) {111        if (e.target != deleteButton)112          this.requestActive_();113      }.bind(this));114      this.addEventListener('keydown', function(e) {115        if (e.keyIdentifier == 'Enter' && e.target != deleteButton)116          this.requestActive_();117      });118      this.addFocusableElement(this);119      this.addFocusableElement(this.querySelector('.error-delete-button'));120    },121    /**122     * Bubble up an event to request to become active.123     * @private124     */125    requestActive_: function() {126      this.dispatchEvent(127          new CustomEvent('highlightExtensionError',128                          {bubbles: true, detail: this.error}));129    },130  };131  /**132   * A variable length list of runtime or manifest errors for a given extension.133   * @param {Array<(RuntimeError|ManifestError)>} errors The list of extension134   *     errors with which to populate the list.135   * @param {string} extensionId The id of the extension.136   * @constructor137   * @extends {HTMLDivElement}138   */139  function ExtensionErrorList(errors, extensionId) {140    var div = cloneTemplate('extension-error-list');141    div.__proto__ = ExtensionErrorList.prototype;142    div.extensionId_ = extensionId;143    div.decorate(errors);144    return div;145  }146  ExtensionErrorList.prototype = {147    __proto__: HTMLDivElement.prototype,148    /**149     * Initializes the extension error list.150     * @param {Array<(RuntimeError|ManifestError)>} errors The list of errors.151     */152    decorate: function(errors) {153      /**154       * @private {!Array<(ManifestError|RuntimeError)>}155       */156      this.errors_ = [];157      this.focusGrid_ = new cr.ui.FocusGrid();158      this.gridBoundary_ = this.querySelector('.extension-error-list-contents');159      this.gridBoundary_.addEventListener('focus', this.onFocus_.bind(this));160      this.gridBoundary_.addEventListener('focusin',161                                          this.onFocusin_.bind(this));162      errors.forEach(this.addError_, this);163      this.addEventListener('highlightExtensionError', function(e) {164        this.setActiveErrorNode_(e.target);165      });166      this.addEventListener('deleteExtensionError', function(e) {167        this.removeError_(e.detail);168      });169      this.querySelector('#extension-error-list-clear').addEventListener(170          'click', function(e) {171        this.clear(true);172      }.bind(this));173      /**174       * The callback for the extension changed event.175       * @private {function(EventData):void}176       */177      this.onItemStateChangedListener_ = function(data) {178        var type = chrome.developerPrivate.EventType;179        if ((data.event_type == type.ERRORS_REMOVED ||180             data.event_type == type.ERROR_ADDED) &&181            data.extensionInfo.id == this.extensionId_) {182          var newErrors = data.extensionInfo.runtimeErrors.concat(183              data.extensionInfo.manifestErrors);184          this.updateErrors_(newErrors);185        }186      }.bind(this);187      chrome.developerPrivate.onItemStateChanged.addListener(188          this.onItemStateChangedListener_);189      /**190       * The active error element in the list.191       * @private {?}192       */193      this.activeError_ = null;194      this.setActiveError(0);195    },196    /**197     * Adds an error to the list.198     * @param {(RuntimeError|ManifestError)} error The error to add.199     * @private200     */201    addError_: function(error) {202      this.querySelector('#no-errors-span').hidden = true;203      this.errors_.push(error);204      var focusRow = new ExtensionError(error, this.gridBoundary_);205      this.gridBoundary_.appendChild(document.createElement('li')).206          appendChild(focusRow);207      this.focusGrid_.addRow(focusRow);208    },209    /**210     * Removes an error from the list.211     * @param {(RuntimeError|ManifestError)} error The error to remove.212     * @private213     */214    removeError_: function(error) {215      var index = 0;216      for (; index < this.errors_.length; ++index) {217        if (this.errors_[index].id == error.id)218          break;219      }220      assert(index != this.errors_.length);221      var errorList = this.querySelector('.extension-error-list-contents');222      var wasActive =223          this.activeError_ && this.activeError_.error.id == error.id;224      this.errors_.splice(index, 1);225      var listElement = errorList.children[index];226      listElement.parentNode.removeChild(listElement);227      if (wasActive) {228        index = Math.min(index, this.errors_.length - 1);229        this.setActiveError(index);  // Gracefully handles the -1 case.230      }231      chrome.developerPrivate.deleteExtensionErrors({232        extensionId: error.extensionId,233        errorIds: [error.id]234      });235      if (this.errors_.length == 0)236        this.querySelector('#no-errors-span').hidden = false;237    },238    /**239     * Updates the list of errors.240     * @param {!Array<(ManifestError|RuntimeError)>} newErrors The new list of241     *     errors.242     * @private243     */244    updateErrors_: function(newErrors) {245      this.errors_.forEach(function(error) {246        if (findErrorById(newErrors, error.id) == -1)247          this.removeError_(error);248      }, this);249      newErrors.forEach(function(error) {250        var index = findErrorById(this.errors_, error.id);251        if (index == -1)252          this.addError_(error);253        else254          this.errors_[index] = error;  // Update the existing reference.255      }, this);256    },257    /**258     * Called when the list is being removed.259     */260    onRemoved: function() {261      chrome.developerPrivate.onItemStateChanged.removeListener(262          this.onItemStateChangedListener_);263      this.clear(false);264    },265    /**266     * Sets the active error in the list.267     * @param {number} index The index to set to be active.268     */269    setActiveError: function(index) {270      var errorList = this.querySelector('.extension-error-list-contents');271      var item = errorList.children[index];272      this.setActiveErrorNode_(273          item ? item.querySelector('.extension-error-metadata') : null);274      var node = null;275      if (index >= 0 && index < errorList.children.length) {276        node = errorList.children[index].querySelector(277                   '.extension-error-metadata');278      }279      this.setActiveErrorNode_(node);280    },281    /**282     * Clears the list of all errors.283     * @param {boolean} deleteErrors Whether or not the errors should be deleted284     *     on the backend.285     */286    clear: function(deleteErrors) {287      if (this.errors_.length == 0)288        return;289      if (deleteErrors) {290        var ids = this.errors_.map(function(error) { return error.id; });291        chrome.developerPrivate.deleteExtensionErrors({292          extensionId: this.extensionId_,293          errorIds: ids294        });295      }296      this.setActiveErrorNode_(null);297      this.errors_.length = 0;298      var errorList = this.querySelector('.extension-error-list-contents');299      while (errorList.firstChild)300        errorList.removeChild(errorList.firstChild);301    },302    /**303     * Sets the active error in the list.304     * @param {?} node The error to make active.305     * @private306     */307    setActiveErrorNode_: function(node) {308      if (this.activeError_)309        this.activeError_.classList.remove('extension-error-active');310      if (node)311        node.classList.add('extension-error-active');312      this.activeError_ = node;313      this.dispatchEvent(314          new CustomEvent('activeExtensionErrorChanged',315                          {bubbles: true, detail: node ? node.error : null}));316    },317    /**318     * The grid should not be focusable once it or an element inside it is319     * focused. This is necessary to allow tabbing out of the grid in reverse.320     * @private321     */322    onFocusin_: function() {323      this.gridBoundary_.tabIndex = -1;324    },325    /**326     * Focus the first focusable row when tabbing into the grid for the327     * first time.328     * @private329     */330    onFocus_: function() {331      var activeRow = this.gridBoundary_.querySelector('.focus-row-active');332      activeRow.getEquivalentElement(null).focus();333    },334  };335  return {336    ExtensionErrorList: ExtensionErrorList337  };...

Full Screen

Full Screen

.eslintrc.js

Source:.eslintrc.js Github

copy

Full Screen

1module.exports = {2    "env": {3        "browser": true,4        "es6": true5    },6    "extends": "eslint:recommended",7    "parserOptions": {8        "ecmaVersion": 2017,9        "sourceType": "module"10    },11    "rules": {12        "accessor-pairs": "error",13        "array-bracket-newline": "error",14        "array-bracket-spacing": "error",15        "array-callback-return": "error",16        "array-element-newline": "error",17        "arrow-body-style": "error",18        "arrow-parens": [19            "error",20            "always"21        ],22        "arrow-spacing": [23            "error",24            {25                "after": false,26                "before": false27            }28        ],29        "block-scoped-var": "error",30        "block-spacing": "error",31        "brace-style": "error",32        "callback-return": "error",33        "camelcase": "off",34        "capitalized-comments": "error",35        "class-methods-use-this": "error",36        "comma-dangle": "error",37        "comma-spacing": "off",38        "comma-style": [39            "error",40            "last"41        ],42        "complexity": "error",43        "computed-property-spacing": [44            "error",45            "never"46        ],47        "consistent-return": "error",48        "consistent-this": "error",49        "curly": "error",50        "default-case": "error",51        "dot-location": "error",52        "dot-notation": "error",53        "eol-last": "error",54        "eqeqeq": "error",55        "func-call-spacing": "error",56        "func-name-matching": "error",57        "func-names": "off",58        "func-style": [59            "error",60            "declaration"61        ],62        "function-paren-newline": "error",63        "generator-star-spacing": "error",64        "global-require": "error",65        "guard-for-in": "error",66        "handle-callback-err": "error",67        "id-blacklist": "error",68        "id-length": "error",69        "id-match": "error",70        "implicit-arrow-linebreak": [71            "error",72            "beside"73        ],74        "indent": "off",75        "indent-legacy": "off",76        "init-declarations": "error",77        "jsx-quotes": "error",78        "key-spacing": "error",79        "keyword-spacing": "error",80        "line-comment-position": "error",81        "linebreak-style": [82            "error",83            "unix"84        ],85        "lines-around-comment": "error",86        "lines-around-directive": "error",87        "lines-between-class-members": "error",88        "max-classes-per-file": "error",89        "max-depth": "error",90        "max-len": "error",91        "max-lines": "error",92        "max-lines-per-function": "error",93        "max-nested-callbacks": "error",94        "max-params": "error",95        "max-statements": "error",96        "max-statements-per-line": "error",97        "multiline-comment-style": "error",98        "multiline-ternary": "error",99        "new-cap": "error",100        "new-parens": "error",101        "newline-after-var": "off",102        "newline-before-return": "error",103        "newline-per-chained-call": "error",104        "no-alert": "error",105        "no-array-constructor": "error",106        "no-async-promise-executor": "error",107        "no-await-in-loop": "error",108        "no-bitwise": "error",109        "no-buffer-constructor": "error",110        "no-caller": "error",111        "no-catch-shadow": "error",112        "no-confusing-arrow": "error",113        "no-continue": "error",114        "no-div-regex": "error",115        "no-duplicate-imports": "error",116        "no-else-return": "error",117        "no-empty-function": "error",118        "no-eq-null": "error",119        "no-eval": "error",120        "no-extend-native": "error",121        "no-extra-bind": "error",122        "no-extra-label": "error",123        "no-extra-parens": "off",124        "no-floating-decimal": "error",125        "no-implicit-coercion": "error",126        "no-implicit-globals": "error",127        "no-implied-eval": "error",128        "no-inline-comments": "error",129        "no-invalid-this": "error",130        "no-iterator": "error",131        "no-label-var": "error",132        "no-labels": "error",133        "no-lone-blocks": "error",134        "no-lonely-if": "error",135        "no-loop-func": "error",136        "no-magic-numbers": "off",137        "no-misleading-character-class": "error",138        "no-mixed-operators": "error",139        "no-mixed-requires": "error",140        "no-multi-assign": "error",141        "no-multi-spaces": "error",142        "no-multi-str": "error",143        "no-multiple-empty-lines": "error",144        "no-native-reassign": "error",145        "no-negated-condition": "error",146        "no-negated-in-lhs": "error",147        "no-nested-ternary": "error",148        "no-new": "error",149        "no-new-func": "error",150        "no-new-object": "error",151        "no-new-require": "error",152        "no-new-wrappers": "error",153        "no-octal-escape": "error",154        "no-param-reassign": "error",155        "no-path-concat": "error",156        "no-plusplus": "error",157        "no-process-env": "error",158        "no-process-exit": "error",159        "no-proto": "error",160        "no-prototype-builtins": "error",161        "no-restricted-globals": "error",162        "no-restricted-imports": "error",163        "no-restricted-modules": "error",164        "no-restricted-properties": "error",165        "no-restricted-syntax": "error",166        "no-return-assign": "error",167        "no-return-await": "error",168        "no-script-url": "error",169        "no-self-compare": "error",170        "no-sequences": "error",171        "no-shadow": "error",172        "no-shadow-restricted-names": "error",173        "no-spaced-func": "error",174        "no-sync": "error",175        "no-tabs": [176            "error",177            {178                "allowIndentationTabs": true179            }180        ],181        "no-template-curly-in-string": "error",182        "no-ternary": "error",183        "no-throw-literal": "error",184        "no-trailing-spaces": "error",185        "no-undef-init": "error",186        "no-undefined": "error",187        "no-underscore-dangle": "error",188        "no-unmodified-loop-condition": "error",189        "no-unneeded-ternary": "error",190        "no-unused-expressions": "error",191        "no-use-before-define": "error",192        "no-useless-call": "error",193        "no-useless-computed-key": "error",194        "no-useless-concat": "error",195        "no-useless-constructor": "error",196        "no-useless-rename": "error",197        "no-useless-return": "error",198        "no-var": "off",199        "no-void": "error",200        "no-warning-comments": "error",201        "no-whitespace-before-property": "error",202        "no-with": "error",203        "nonblock-statement-body-position": "error",204        "object-curly-newline": "error",205        "object-curly-spacing": "error",206        "object-property-newline": "error",207        "object-shorthand": "error",208        "one-var": "off",209        "one-var-declaration-per-line": "error",210        "operator-assignment": "error",211        "operator-linebreak": "error",212        "padded-blocks": "off",213        "padding-line-between-statements": "error",214        "prefer-arrow-callback": "off",215        "prefer-const": "error",216        "prefer-destructuring": "error",217        "prefer-numeric-literals": "error",218        "prefer-object-spread": "error",219        "prefer-promise-reject-errors": "error",220        "prefer-reflect": "error",221        "prefer-rest-params": "error",222        "prefer-spread": "error",223        "prefer-template": "off",224        "quote-props": "error",225        "quotes": "off",226        "radix": "error",227        "require-atomic-updates": "error",228        "require-await": "error",229        "require-jsdoc": "off",230        "require-unicode-regexp": "error",231        "rest-spread-spacing": "error",232        "semi": "error",233        "semi-spacing": "error",234        "semi-style": [235            "error",236            "last"237        ],238        "sort-imports": "error",239        "sort-keys": [240            "error",241            "asc"242        ],243        "sort-vars": "error",244        "space-before-blocks": "off",245        "space-before-function-paren": "off",246        "space-in-parens": [247            "error",248            "never"249        ],250        "space-infix-ops": "off",251        "space-unary-ops": "error",252        "spaced-comment": "error",253        "strict": "error",254        "switch-colon-spacing": "error",255        "symbol-description": "error",256        "template-curly-spacing": "error",257        "template-tag-spacing": "error",258        "unicode-bom": [259            "error",260            "never"261        ],262        "valid-jsdoc": "error",263        "vars-on-top": "error",264        "wrap-iife": "error",265        "wrap-regex": "error",266        "yield-star-spacing": "error",267        "yoda": "error"268    }...

Full Screen

Full Screen

ReactErrorUtils-test.internal.js

Source:ReactErrorUtils-test.internal.js Github

copy

Full Screen

1/**2 * Copyright (c) Facebook, Inc. and its affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @emails react-core8 */9'use strict';10let ReactErrorUtils;11describe('ReactErrorUtils', () => {12  beforeEach(() => {13    // TODO: can we express this test with only public API?14    ReactErrorUtils = require('shared/ReactErrorUtils');15  });16  it(`it should rethrow caught errors`, () => {17    const err = new Error('foo');18    const callback = function() {19      throw err;20    };21    ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError(22      'foo',23      callback,24      null,25    );26    expect(ReactErrorUtils.hasCaughtError()).toBe(false);27    expect(() => ReactErrorUtils.rethrowCaughtError()).toThrow(err);28  });29  it(`should call the callback the passed arguments`, () => {30    const callback = jest.fn();31    ReactErrorUtils.invokeGuardedCallback(32      'foo',33      callback,34      null,35      'arg1',36      'arg2',37    );38    expect(callback).toBeCalledWith('arg1', 'arg2');39  });40  it(`should call the callback with the provided context`, () => {41    const context = {didCall: false};42    ReactErrorUtils.invokeGuardedCallback(43      'foo',44      function() {45        this.didCall = true;46      },47      context,48    );49    expect(context.didCall).toBe(true);50  });51  it(`should catch errors`, () => {52    const error = new Error();53    const returnValue = ReactErrorUtils.invokeGuardedCallback(54      'foo',55      function() {56        throw error;57      },58      null,59      'arg1',60      'arg2',61    );62    expect(returnValue).toBe(undefined);63    expect(ReactErrorUtils.hasCaughtError()).toBe(true);64    expect(ReactErrorUtils.clearCaughtError()).toBe(error);65  });66  it(`should return false from clearCaughtError if no error was thrown`, () => {67    const callback = jest.fn();68    ReactErrorUtils.invokeGuardedCallback('foo', callback, null);69    expect(ReactErrorUtils.hasCaughtError()).toBe(false);70    expect(ReactErrorUtils.clearCaughtError).toThrow('no error was captured');71  });72  it(`can nest with same debug name`, () => {73    const err1 = new Error();74    let err2;75    const err3 = new Error();76    let err4;77    ReactErrorUtils.invokeGuardedCallback(78      'foo',79      function() {80        ReactErrorUtils.invokeGuardedCallback(81          'foo',82          function() {83            throw err1;84          },85          null,86        );87        err2 = ReactErrorUtils.clearCaughtError();88        throw err3;89      },90      null,91    );92    err4 = ReactErrorUtils.clearCaughtError();93    expect(err2).toBe(err1);94    expect(err4).toBe(err3);95  });96  it(`handles nested errors`, () => {97    const err1 = new Error();98    let err2;99    ReactErrorUtils.invokeGuardedCallback(100      'foo',101      function() {102        ReactErrorUtils.invokeGuardedCallback(103          'foo',104          function() {105            throw err1;106          },107          null,108        );109        err2 = ReactErrorUtils.clearCaughtError();110      },111      null,112    );113    // Returns null because inner error was already captured114    expect(ReactErrorUtils.hasCaughtError()).toBe(false);115    expect(err2).toBe(err1);116  });117  it('handles nested errors in separate renderers', () => {118    const ReactErrorUtils1 = require('shared/ReactErrorUtils');119    jest.resetModules();120    const ReactErrorUtils2 = require('shared/ReactErrorUtils');121    expect(ReactErrorUtils1).not.toEqual(ReactErrorUtils2);122    let ops = [];123    ReactErrorUtils1.invokeGuardedCallback(124      null,125      () => {126        ReactErrorUtils2.invokeGuardedCallback(127          null,128          () => {129            throw new Error('nested error');130          },131          null,132        );133        // ReactErrorUtils2 should catch the error134        ops.push(ReactErrorUtils2.hasCaughtError());135        ops.push(ReactErrorUtils2.clearCaughtError().message);136      },137      null,138    );139    // ReactErrorUtils1 should not catch the error140    ops.push(ReactErrorUtils1.hasCaughtError());141    expect(ops).toEqual([true, 'nested error', false]);142  });143  if (!__DEV__) {144    // jsdom doesn't handle this properly, but Chrome and Firefox should. Test145    // this with a fixture.146    it('catches null values', () => {147      ReactErrorUtils.invokeGuardedCallback(148        null,149        function() {150          throw null; // eslint-disable-line no-throw-literal151        },152        null,153      );154      expect(ReactErrorUtils.hasCaughtError()).toBe(true);155      expect(ReactErrorUtils.clearCaughtError()).toBe(null);156    });157  }158  it(`can be shimmed`, () => {159    const ops = [];160    jest.resetModules();161    jest.mock(162      'shared/invokeGuardedCallbackImpl',163      () =>164        function invokeGuardedCallback(name, func, context, a) {165          ops.push(a);166          try {167            func.call(context, a);168          } catch (error) {169            this.onError(error);170          }171        },172    );173    ReactErrorUtils = require('shared/ReactErrorUtils');174    try {175      const err = new Error('foo');176      const callback = function() {177        throw err;178      };179      ReactErrorUtils.invokeGuardedCallbackAndCatchFirstError(180        'foo',181        callback,182        null,183        'somearg',184      );185      expect(() => ReactErrorUtils.rethrowCaughtError()).toThrow(err);186      expect(ops).toEqual(['somearg']);187    } finally {188      jest.unmock('shared/invokeGuardedCallbackImpl');189    }190  });...

Full Screen

Full Screen

errors.js

Source:errors.js Github

copy

Full Screen

1'use strict';2Object.defineProperty(exports, "__esModule", {3  value: true4});5exports.decorateBadRequestError = decorateBadRequestError;6exports.isBadRequestError = isBadRequestError;7exports.decorateNotAuthorizedError = decorateNotAuthorizedError;8exports.isNotAuthorizedError = isNotAuthorizedError;9exports.decorateForbiddenError = decorateForbiddenError;10exports.isForbiddenError = isForbiddenError;11exports.decorateNotFoundError = decorateNotFoundError;12exports.isNotFoundError = isNotFoundError;13exports.decorateConflictError = decorateConflictError;14exports.isConflictError = isConflictError;15exports.decorateEsUnavailableError = decorateEsUnavailableError;16exports.isEsUnavailableError = isEsUnavailableError;17exports.decorateGeneralError = decorateGeneralError;18var _boom = require('boom');19var _boom2 = _interopRequireDefault(_boom);20function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }21const code = Symbol('SavedObjectsClientErrorCode');22function decorate(error, errorCode, statusCode, message) {23  const boom = _boom2.default.boomify(error, {24    statusCode,25    message,26    override: false27  });28  boom[code] = errorCode;29  return boom;30}31// 400 - badRequest32const CODE_BAD_REQUEST = 'SavedObjectsClient/badRequest';33function decorateBadRequestError(error, reason) {34  return decorate(error, CODE_BAD_REQUEST, 400, reason);35}36function isBadRequestError(error) {37  return error && error[code] === CODE_BAD_REQUEST;38}39// 401 - Not Authorized40const CODE_NOT_AUTHORIZED = 'SavedObjectsClient/notAuthorized';41function decorateNotAuthorizedError(error, reason) {42  return decorate(error, CODE_NOT_AUTHORIZED, 401, reason);43}44function isNotAuthorizedError(error) {45  return error && error[code] === CODE_NOT_AUTHORIZED;46}47// 403 - Forbidden48const CODE_FORBIDDEN = 'SavedObjectsClient/forbidden';49function decorateForbiddenError(error, reason) {50  return decorate(error, CODE_FORBIDDEN, 403, reason);51}52function isForbiddenError(error) {53  return error && error[code] === CODE_FORBIDDEN;54}55// 404 - Not Found56const CODE_NOT_FOUND = 'SavedObjectsClient/notFound';57function decorateNotFoundError(error, reason) {58  return decorate(error, CODE_NOT_FOUND, 404, reason);59}60function isNotFoundError(error) {61  return error && error[code] === CODE_NOT_FOUND;62}63// 409 - Conflict64const CODE_CONFLICT = 'SavedObjectsClient/conflict';65function decorateConflictError(error, reason) {66  return decorate(error, CODE_CONFLICT, 409, reason);67}68function isConflictError(error) {69  return error && error[code] === CODE_CONFLICT;70}71// 500 - Es Unavailable72const CODE_ES_UNAVAILABLE = 'SavedObjectsClient/esUnavailable';73function decorateEsUnavailableError(error, reason) {74  return decorate(error, CODE_ES_UNAVAILABLE, 503, reason);75}76function isEsUnavailableError(error) {77  return error && error[code] === CODE_ES_UNAVAILABLE;78}79// 500 - General Error80const CODE_GENERAL_ERROR = 'SavedObjectsClient/generalError';81function decorateGeneralError(error, reason) {82  return decorate(error, CODE_GENERAL_ERROR, 500, reason);...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1app.use((err, req, res, next) => {2    res.status(500).send({ error: err.message })3})4app.use((err, req, res, next) => {5    res.status(500).send({ error: err.message })6})7app.use((err, req, res, next) => {8    res.status(500).send({ error: err.message })9})10app.use((err, req, res, next) => {11    res.status(500).send({ error: err.message })12})13app.use((err, req, res, next) => {14    res.status(500).send({ error: err.message })15})16app.use((err, req, res, next) => {17    res.status(500).send({ error: err.message })18})19app.use((err, req, res, next) => {20    res.status(500).send({ error: err.message })21})22app.use((err, req, res, next) => {23    res.status(500).send({ error: err.message })24})25app.use((err, req, res, next) => {26    res.status(500).send({ error: err.message })27})28app.use((err, req, res, next) => {29    res.status(500).send({ error: err.message })30})31app.use((err, req, res, next) => {32    res.status(500).send({ error: err.message })33})34app.use((err, req, res, next) =>

Full Screen

Using AI Code Generation

copy

Full Screen

1const express = require('express');2const app = express();3app.get('/', (req, res) => {4    res.status(404).send('Not Found');5});6app.listen(3000, () => console.log('Listening on port 3000...'));7const express = require('express');8const app = express();9app.get('/', (req, res) => {10    res.status(404).send('Not Found');11});12app.listen(3000, () => console.log('Listening on port 3000...'));13const express = require('express');14const app = express();15app.get('/', (req, res) => {16    res.status(404).send('Not Found');17});18app.listen(3000, () => console.log('Listening on port 3000...'));19const express = require('express');20const app = express();21app.get('/', (req, res) => {22    res.status(404).send('Not Found');23});24app.listen(3000, () => console.log('Listening on port 3000...'));25const express = require('express');26const app = express();27app.get('/', (req, res) => {28    res.status(404).send('Not Found');29});30app.listen(3000, () => console.log('Listening on port 3000...'));31const express = require('express');32const app = express();33app.get('/', (req, res) => {34    res.status(404).send('Not Found');35});36app.listen(3000, () => console.log('Listening on port 3000...'));37const express = require('express');38const app = express();39app.get('/', (req, res) => {40    res.status(404).send('Not Found');41});42app.listen(3000, () => console.log('Listening on port 3000...'));

Full Screen

Using AI Code Generation

copy

Full Screen

1var fs = require('fs');2fs.readFile('input.txt', function (err, data) {3   if (err) {4      return console.error(err);5   }6   console.log("Asynchronous read: " + data.toString());7});8var fs = require('fs');9fs.readFile('input.txt', function (err, data) {10   if (err) {11      console.log(err.stack);12      return;13   }14   console.log(data.toString());15});16console.log("Program Ended");17var fs = require('fs');18fs.readFile('input.txt', function (err, data) {19   if (err) {20      console.log(err.stack);21      return;22   }23   console.log(data.toString());24});25console.log("Program Ended");

Full Screen

Using AI Code Generation

copy

Full Screen

1console.error("Error message");2console.warn("Warning message");3console.log("Log message");4console.info("Info message");5console.time("Time message");6console.timeEnd("Time message");7console.table("Table message");8console.group("Group message");9console.groupEnd("Group message");10console.groupCollapsed("Group message");11console.groupEnd("Group message");12console.assert("Assert message");13console.count("Count message");14console.dir("Dir message");15console.trace("Trace message");16console.clear("Clear message");17console.dirxml("Dirxml message");18console.profile("Profile message");19console.profileEnd("Profile message");20console.timeStamp("TimeStamp message");

Full Screen

Using AI Code Generation

copy

Full Screen

1var express = require('express');2var app = express();3app.get('/', function (req, res) {4res.error('This is an error!');5});6app.listen(8080);7var express = require('express');8var app = express();9app.get('/', function (req, res) {10res.error('This is an error!');11});12app.listen(8080);13var express = require('express');14var app = express();15app.get('/', function (req, res) {16res.error('This is an error!');17});18app.listen(8080);19var express = require('express');20var app = express();21app.get('/', function (req, res) {22res.error('This is an error!');23});24app.listen(8080);25var express = require('express');26var app = express();27app.get('/', function (req, res) {28res.error('This is an error!');29});30app.listen(8080);31var express = require('express');32var app = express();33app.get('/', function (req, res) {34res.error('This is an error!');35});36app.listen(8080);37var express = require('express');38var app = express();39app.get('/', function (req, res) {40res.error('This is an error!');41});42app.listen(8080);43var express = require('express');44var app = express();45app.get('/', function (req, res) {46res.error('This is an error!');47});48app.listen(8080);49var express = require('express');50var app = express();51app.get('/', function (req, res) {52res.error('This is an error!');53});54app.listen(8080);55var express = require('express');56var app = express();57app.get('/', function (req, res) {58res.error('This is an error!');59});60app.listen(8080);

Full Screen

Using AI Code Generation

copy

Full Screen

1var logger = require('./logger');2logger.error('error message');3var logger = {4    error: function(msg) {5        console.log('Error: ' + msg);6    }7};8module.exports = logger;

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs: