如何从 Jest Mock 引用 React.Component 的函数

问题描述 投票:0回答:1

我有以下(示例)组件,我试图将其模拟为集成测试的一部分。

interface MyComponentProps { acceptableRoles: string[]}

export default class MyComponent extends Component<React.PropsWithChildren<MyComponentProps>> {

    public canRender(currentRoles: string[]): boolean {
        // determine if any current roles intersect with acceptableRoles
    }

    public render() {
        return (
            <MyContext.Consumer>
                {(roles) => this.canRender(roles)
                    ? this.props.children
                    : null
                }
            </MyContext.Consumer>
    }
}

我想模拟

render()
的输出以删除
<MyContext.Consumer>
包装器并将
roles
传递到我的模拟中。

当在我正在测试的组件中使用时,上面的组件很简单

<MyComponent acceptableRoles={"role1", "role2"}>
    <div>Show this if allowed</div>
</MyComponent> 

我尝试了很多事情,这感觉是我能得到的最接近的;但是,我收到一条错误消息,指出

origin.canRender is not a function
。当我检查它时,它是未定义的。

const myTestRoles = ["role3", "role4"]; //changes within different tests

jest.mock("./MyComponent", () => (props: any) => {
  const origin = jest.requireActual<MyComponent>("./MyComponent");
  // console.info("Origin: " + origin.canRender); //Outputs as "Origin: undefined"

  return <div>{
            origin.canRender(_user)
            ? props.children
            : null}
          </div>;
  });

一切都“有效”,直到我添加对“origin.canRender”的调用,它提供了“不是函数”错误。

我知道严格的单元测试,我会用显式模拟跳过这个调用,但这让我真的想知道是否可以做到这一点。

是否可以从模拟方法中调用这样的实例方法?

reactjs unit-testing jestjs
1个回答
0
投票

由于您使用的是

export default MyComponent
,因此
jest.requireActual('./MyComponent')
语句将返回
{ default: [class MyComponent extends Component] }

您可以通过 JavaScript 类的

.prototype
属性访问其公共方法。

例如

MyComponent.tsx

import React, { Component } from 'react';

const MyContext = React.createContext<string[]>([]);

interface MyComponentProps {
  acceptableRoles: string[];
}

export default class MyComponent extends Component<React.PropsWithChildren<MyComponentProps>> {
  public canRender(currentRoles: string[]): boolean {
    return true;
  }

  public render() {
    return <MyContext.Consumer>{(roles) => (this.canRender(roles) ? this.props.children : null)}</MyContext.Consumer>;
  }
}

index.test.tsx

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

jest.mock('./MyComponent', () => (props: any) => {
  const origin = jest.requireActual('./MyComponent');
  console.log("🚀 ~ jest.mock ~ origin:", origin)
  console.info('Origin: ', origin.default.prototype.canRender);

  return <div>{origin.default.prototype.canRender(['role3']) ? props.children : null}</div>;
});

describe('78269182', () => {
  test('should pass', () => {
    render(
      <MyComponent acceptableRoles={['role1', 'role2']}>
        <div>Show this if allowed</div>
      </MyComponent>,
    );
    screen.debug();
  });
});

测试结果:

  console.log
    🚀 ~ jest.mock ~ origin: { default: [class MyComponent extends Component] }

      at log (stackoverflow/78269182/index.test.tsx:7:11)

  console.info
    Origin:  [Function: canRender]

      at info (stackoverflow/78269182/index.test.tsx:8:11)

  console.log
    <body>
      <div>
        <div>
          <div>
            Show this if allowed
          </div>
        </div>
      </div>
    </body>

      at logDOM (node_modules/@testing-library/dom/dist/pretty-dom.js:87:13)

 PASS  stackoverflow/78269182/index.test.tsx
  78269182
    √ should pass (40 ms)                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                         
Test Suites: 1 passed, 1 total                                                                                                                                                                                                                           
Tests:       1 passed, 1 total                                                                                                                                                                                                                           
Snapshots:   0 total
Time:        1.086 s
Ran all test suites related to changed files.

封装版本:

"jest": "^29.7.0"
© www.soinside.com 2019 - 2024. All rights reserved.