Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
226 views
in Technique[技术] by (71.8m points)

reactjs - How to mock a nested component import in react js and test using react testing library

I have a component called SearchBox which is used inside SearchSection which is in turn used in MyComponent. SearchBox has a method that uses setTimeout().

SearchBox.tsx

import React from 'react';
export class SearchBox extends React.Component {
  
  private timer: (ReturnType<typeof setTimeout> | null) = null;

  public asyncmethod() {
    if (this.timer !== null) {
      clearTimeout(this.timer);
    }
    this.timer = setTimeout(() => {
      doSomething();
    }, 1000);
    console.log('using original class method');
  }

  render() {
    return (
      <div>
        ...
        ...
        {this.asyncmethod()}
        ...
        ...
      </div>
    );
  }
}

SearchSection.tsx

import React from 'react';
import { SearchBox } from './SearchBox';

export class SearchSection extends React.Component {
  render() {
    return <SearchBox />;
  }
}

MyComponent.tsx

import React from 'react';
import { SearchSection } from './SearchSection';

export class MyComponent extends React.component {
  render() {
    return <SearchSection />;
  }
}

Now I want to test MyComponent using react-testing-library and I want to mock SearchBox with overridden class method that does not use setTimeout. I tried the following

testUtil.tsx

import { SearchBox } from './SearchBox';

class MockedSearchBox extends SearchBox {
  public asyncMethod() {
    doSomething();
    console.log('using mocked class method');
  }
}

MyComponent.test.tsx

import { MockedSearchBox } from './testUtil.tsx'
import { render } from '@testing-library/react';
import { MyComponent } from './MyComponent';
 
describe('My component', () => {
  jest.mock('./SearchBox', () => {
    return {
      SearchBox: MockedSearchBox
    }
  });

  test('that my component shows text', () => {
    const { getByText } = render(<MyComponent />);
    expext(getByText('Search mock text')).toBeDefined();
  });
});

But this is not working. The original class method is being called even after writing above code. What am I doing wrong?

question from:https://stackoverflow.com/questions/65933863/how-to-mock-a-nested-component-import-in-react-js-and-test-using-react-testing-l

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You are mocking ./SearchBox module, so you'd better don't extends original SearchBox component. You should create a simple mocked version for SearchBox component.

E.g.

MyComponent.tsx:

import React from 'react';
import { SearchSection } from './SearchSection';

export class MyComponent extends React.Component {
  render() {
    return <SearchSection />;
  }
}

SearchBox.tsx:

import React from 'react';

export class SearchBox extends React.Component {
  private timer: ReturnType<typeof setTimeout> | null = null;

  public asyncmethod() {
    if (this.timer !== null) {
      clearTimeout(this.timer);
    }
    this.timer = setTimeout(() => {
      console.log('doSomething');
    }, 1000);
    console.log('using original class method');
    return 'search real text';
  }

  render() {
    return <div>{this.asyncmethod()}</div>;
  }
}

SearchBoxSection.tsx:

import React from 'react';
import { SearchBox } from './SearchBox';

export class SearchSection extends React.Component {
  render() {
    return <SearchBox />;
  }
}

testUtil.tsx

import React from 'react';

export class MockedSearchBox extends React.Component {
  public asyncMethod() {
    console.log('using mocked class method');
    return 'Search mock text';
  }
  render() {
    return <div>{this.asyncMethod()}</div>;
  }
}

MyComponent.spec.tsx:

import React from 'react';
import { render } from '@testing-library/react';
import { MyComponent } from './MyComponent';

jest.mock('./SearchBox', () => {
  const { MockedSearchBox } = require('./testUtil');

  return {
    SearchBox: MockedSearchBox,
  };
});

describe('My component', () => {
  test('that my component shows text', () => {
    const { getByText } = render(<MyComponent />);
    expect(getByText('Search mock text')).toBeDefined();
  });
});

unit test result:

 PASS  examples/65933863/MyComponent.spec.tsx (9.544 s)
  My component
    √ that my component shows text (59 ms)

  console.log
    using mocked class method

      at MockedSearchBox.asyncMethod (examples/65933863/testUtil.tsx:5:13)

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |     100 |      100 |     100 |     100 | 
 MyComponent.tsx   |     100 |      100 |     100 |     100 | 
 SearchSection.tsx |     100 |      100 |     100 |     100 | 
 testUtil.tsx      |     100 |      100 |     100 |     100 | 
-------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        11.973 s

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...