2017-08-13 6 views
0

オーケーを反応させるテストするときにNULLのプロパティ「長さ」を読み込めません、しかし、私は次のエラーを取得する:はTypeError:私はChartJSのためのコンポーネントを反応させるの作成にはかなり遠い得ているコンポーネント

FAIL lib\chart\chart.test.tsx 
    ● renders without crashing 

    TypeError: Cannot read property 'length' of null 

     at Object.acquireContext (node_modules/chart.js/src/platforms/platform.dom.js:189:19) 
     at Chart.construct (node_modules/chart.js/src/core/core.controller.js:72:27) 
     at new Chart (node_modules/chart.js/src/core/core.js:7:8) 
     at Chart.Object.<anonymous>.Chart.renderChart (lib/chart/chart.tsx:233:26) 
     at Chart.Object.<anonymous>.Chart.componentDidMount (lib/chart/chart.tsx:42:10) 
     at node_modules/react-dom/lib/ReactCompositeComponent.js:264:25 
     at measureLifeCyclePerf (node_modules/react-dom/lib/ReactCompositeComponent.js:75:12) 
     at node_modules/react-dom/lib/ReactCompositeComponent.js:263:11 
     at CallbackQueue.notifyAll (node_modules/react-dom/lib/CallbackQueue.js:76:22) 
     at ReactReconcileTransaction.close (node_modules/react-dom/lib/ReactReconcileTransaction.js:80:26) 
     at ReactReconcileTransaction.closeAll (node_modules/react-dom/lib/Transaction.js:209:25) 
     at ReactReconcileTransaction.perform (node_modules/react-dom/lib/Transaction.js:156:16) 
     at batchedMountComponentIntoNode (node_modules/react-dom/lib/ReactMount.js:126:15) 
     at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-dom/lib/Transaction.js:143:20) 
     at Object.batchedUpdates (node_modules/react-dom/lib/ReactDefaultBatchingStrategy.js:62:26) 
     at Object.batchedUpdates (node_modules/react-dom/lib/ReactUpdates.js:97:27) 
     at Object._renderNewRootComponent (node_modules/react-dom/lib/ReactMount.js:319:18) 
     at Object._renderSubtreeIntoContainer (node_modules/react-dom/lib/ReactMount.js:401:32) 
     at Object.render (node_modules/react-dom/lib/ReactMount.js:422:23) 
     at Object.<anonymous> (lib/chart/chart.test.tsx:7:12) 
      at Promise (<anonymous>) 
     at Promise.resolve.then.el (node_modules/p-map/index.js:42:16) 
      at <anonymous> 
     at process._tickCallback (internal/process/next_tick.js:169:7) 

    × renders without crashing (275ms) 

Test Suites: 1 failed, 1 total 
Tests:  1 failed, 1 total 
Snapshots: 0 total 
Time:  1.314s, estimated 3s 
Ran all test suites related to changed files. 

しかし、私はコードを見渡すのに長時間を費やしてしまい、なぜそれが正しく動作するのを拒否したのか理解できませんでした。このエラーは、新しいグラフインスタンスの作成時にrenderChart()関数から開始されます。私の最初の推測は、何らかの理由で、そのIDによって呼び出されているにもかかわらずキャンバス要素を登録していないことになります。しかし、renderChartの内容をrender()関数に移すと、同じエラーが返されます。テストされているコードは次のとおりです。

import * as React from 'react' 
import * as ClassNames from 'classnames' 
import * as ChartJS from 'chart.js' 
const IsEqual = require('lodash.isequal') 
const Find = require('lodash.find') 
const subChart = require('chart.js') 

interface IChartProps { 
    /** The user-defined classes */ 
    readonly className?: string 
    readonly width?: number 
    readonly height?: number 
    readonly reRender?: boolean 

    readonly type: ChartJS.ChartType 
    readonly data: ChartJS.ChartData 
    readonly options: ChartJS.ChartOptions 
    readonly getDatasetAtEvent?: Function 
    readonly getElementAtEvent?: Function 
    readonly getElementsAtEvent?: Function 
    readonly onElementsClick?: Function 
    readonly datasetKeyProvider?: Function 
} 

interface IChartState { 
    /** Add your states here */ 
} 

export class Chart extends React.Component<IChartProps, IChartState> { 
    // tslint:disable-next-line 
    private chartInstance: any 
    private shadowData: {} 
    constructor(props: IChartProps) { 
    super(props) 
    } 

    public componentWillMount() { 
    // this.chartInstance = undefined 
    } 

    public componentDidMount() { 
    this.renderChart() 
    } 

    // public componentWillReceiveProps(nextProps: IChartProps) {} 

    public shouldComponentUpdate(nextProps: IChartProps, nextState: IChartState) { 
    const props = this.props 
    if (nextProps.reRender === true) { 
     return true 
    } 

    if (props.height !== nextProps.height || props.width !== nextProps.width) { 
     return true 
    } 

    if (props.type !== nextProps.type) { 
     return true 
    } 

    if (!IsEqual(props.options, nextProps.options)) { 
     return true 
    } 

    const nextData = this.transformDataProp(nextProps) 

    if (!IsEqual(this.shadowData, nextData)) { 
     return true 
    } 

    return false 
    } 

    // public componentWillUpdate(nextProps: IChartProps, nextState: IChartState) {} 

    public componentDidUpdate(prevProps: IChartProps, prevState: IChartState) { 
    if (this.props.reRender) { 
     this.chartInstance.destroy() 
     this.renderChart() 
     return 
    } 
    this.updateChart() 
    } 

    public transformDataProp(props: IChartProps) { 
    const data = props.data 
    if (typeof data === 'function') { 
     const node = document.getElementById('bar-chart') as HTMLCanvasElement 
     return data(node) 
    } else { 
     return data 
    } 
    } 

    public memoizeDataProps(props?: IChartProps) { 
    if (!this.props.data) { 
     return 
    } 
    const data = this.transformDataProp(this.props) 

    this.shadowData = { 
     ...data, 
     datasets: 
     data.datasets && 
     data.datasets.map((set: string[]) => { 
      return { ...set } 
     }) 
    } 
    return data 
    } 

    public updateChart() { 
    const options = this.props.options 

    const data = this.memoizeDataProps(this.props) 

    if (!this.chartInstance) { 
     return 
    } 

    if (options) { 
     this.chartInstance.options = subChart.helpers.configMerge(
     this.chartInstance.options, 
     options 
    ) 
    } 

    let currentDatasets = 
     (this.chartInstance.config.data && 
     this.chartInstance.config.data.datasets) || 
     [] 
    const nextDatasets = data.datasets || [] 

    const currentDatasetKeys = currentDatasets.map(
     this.props.datasetKeyProvider 
    ) 
    const nextDatasetKeys = nextDatasets.map(this.props.datasetKeyProvider) 
    const newDatasets = nextDatasets.filter(
     (d: object) => 
     currentDatasetKeys.indexOf(this.props.datasetKeyProvider(d)) === -1 
    ) 

    for (let idx = currentDatasets.length - 1; idx >= 0; idx -= 1) { 
     const currentDatasetKey = this.props.datasetKeyProvider(
     currentDatasets[idx] 
    ) 
     if (nextDatasetKeys.indexOf(currentDatasetKey) === -1) { 
     // deleted series 
     currentDatasets.splice(idx, 1) 
     } else { 
     const retainedDataset = Find(
      nextDatasets, 
      (d: object) => this.props.datasetKeyProvider(d) === currentDatasetKey 
     ) 
     if (retainedDataset) { 
      // update it in place if it is a retained dataset 
      currentDatasets[idx].data.splice(retainedDataset.data.length) 
      retainedDataset.data.forEach((point: number, pid: number) => { 
      currentDatasets[idx].data[pid] = retainedDataset.data[pid] 
      }) 
      // const { data, ...otherProps } = retainedDataset 
      currentDatasets[idx] = { 
      data: currentDatasets[idx].data, 
      ...currentDatasets[idx], 
      ...retainedDataset.otherProps 
      } 
     } 
     } 
    } 
    // finally add any new series 
    newDatasets.forEach((d: object) => currentDatasets.push(d)) 
    const { datasets, ...rest } = data 

    this.chartInstance.config.data = { 
     ...this.chartInstance.config.data, 
     ...rest 
    } 

    this.chartInstance.update() 
    } 

    public componentWillUnmount() { 
    this.chartInstance.destroy() 
    } 

    public onClickEvent = (event: React.MouseEvent<HTMLCanvasElement>) => { 
    // this.props.getDatasetAtEvent && 
    this.props.getDatasetAtEvent(
     this.chartInstance.getDatasetAtEvent(event), 
     event 
    ) 

    // this.props.getElementAtEvent && 
    this.props.getElementAtEvent(
     this.chartInstance.getElementAtEvent(event), 
     event 
    ) 

    // this.props.getElementsAtEvent && 
    this.props.getElementsAtEvent(
     this.chartInstance.getElementsAtEvent(event), 
     event 
    ) 

    // this.props.onElementsClick && 
    this.props.onElementsClick(
     this.chartInstance.getElementsAtEvent(event), 
     event 
    ) 
    } 

    public render() { 
    const className = ClassNames('chart', this.props.className) 

    // bar.update() 
    return (
     <div className={className}> 
     <canvas 
      id="chart-instance" 
      width={this.props.width ? this.props.width : '400'} 
      height={this.props.height ? this.props.height : '400'} 
      onClick={this.onClickEvent} 
     /> 
     </div> 
    ) 
    } 

    public renderChart() { 
    const { options, type, data } = this.props 
    const node = document.getElementById('chart-instance') as HTMLCanvasElement 
    // const data = this.memoizeDataProps() 

    this.chartInstance = new ChartJS(node, { 
     type, 
     data, 
     options 
    }) 
    } 
} 

これが正しく動作しない理由を理解できますか?このため

+0

をエラーは、問題が何であるかを語っています。あなたが「長さ」と呼んでいるものは何も存在しません。あなたは失敗しているテストを投稿できますか?そのテストに失敗してもコンポーネントはレンダリングされますか? – archae0pteryx

+0

あなたはテスト自体を投稿していないので、 'length'はある要素のプロパティだと思います。次のようにしてください: 'const wrapper = mount(); wrapper.find( 'ElementYourWantLengthOf')。props()。length' 'find()'によって返されたノードの配列に対して 'length'を呼び出すこともできます。そして、明らかに 'find()'は、コンポーネントが正しくマウントされていないために何も見つからないことを示します。 とにかく、テストコードを投稿してください。 –

答えて

0

それは可能性があります

currentDatasets[idx].data.splice(retainedDataset.data.length)

またretainedDataset.dataのチェックを持っている必要があります。

if (retainedDataset && retainedDataset.data) { ... }

関連する問題