Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/423.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在安装时,如何从Ezyme实例获取HOC包装组件函数?_Javascript_Reactjs_Jestjs_Enzyme - Fatal编程技术网

Javascript 在安装时,如何从Ezyme实例获取HOC包装组件函数?

Javascript 在安装时,如何从Ezyme实例获取HOC包装组件函数?,javascript,reactjs,jestjs,enzyme,Javascript,Reactjs,Jestjs,Enzyme,我有父组件->子组件,子组件在componentDidMount中运行fetch。fetch设置位于父级之上的redux存储中的状态,并导致子组件以不同方式显示 子级还使用材质ui和样式,因此它会在组件周围创建一个HOC 在我的测试中,我需要挂载父组件,找到子组件,然后查看fetch是否正确地更改了状态并导致子组件更新 到目前为止,我的解决方案是: 装入父级,查找子级 调用child.instance().fetchFunction()。然后(()=>expect(..) 但是,在child

我有父组件->子组件,子组件在
componentDidMount
中运行fetch。fetch设置位于父级之上的redux存储中的状态,并导致子组件以不同方式显示

子级还使用
材质ui
和样式
,因此它会在组件周围创建一个HOC

在我的测试中,我需要挂载父组件,找到子组件,然后查看fetch是否正确地更改了状态并导致子组件更新

到目前为止,我的解决方案是:

  • 装入父级,查找子级
  • 调用
    child.instance().fetchFunction()。然后(()=>expect(..)
但是,在
child
上调用
instance()

child.instance(…).fetchFunction不是函数

我看到的所有解决方案都使用
shallow
dive
来绕过HOC,但是如果我使用
shallow
我将不得不在测试中创建一个模拟存储,它实际上不会将其作为集成测试进行测试

我可以测试单独的fetch调用,然后使用
shallow
测试组件,并将道具传递给它,就好像状态发生了变化一样,但这并不能证明它可以一起工作

这是一个代码沙盒,我在这里复制了这个问题:

下面是一些示例代码(基本上是codesandbox):

App.js

import React from "react";
import Child from "./Child";

class App extends React.Component {
  render() {
    return <Child />;
  }
}

export default App;
import React from "react";
import { withStyles } from "@material-ui/core/styles";

const childStyles = {
  margin: 0
};

class Child extends React.Component {
  state = {
    groceries: [],
    errorStatus: ""
  };

  componentDidMount() {
    console.log("calling fetch");

    this.fetchCall();
  }

  fetchCall = () => {
    return fetch("/api/v1/groceries")
      .then(this.checkStatus)
      .then(this.parseJSON)
      .then(this.setStateFromData)
      .catch(this.setError);
  };

  checkStatus = results => {
    if (results.status >= 400) {
      console.log("bad status");

      throw new Error("Bad Status");
    }

    return results;
  };

  setError = () => {
    console.log("error thrown");

    return this.setState({ errorStatus: "Error fetching groceries" });
  };

  parseJSON = results => {
    console.log("parse json");

    return results.json();
  };

  setStateFromData = data => {
    console.log("setting state");

    return this.setState({ groceries: data.groceries });
  };

  render() {
    const { groceries } = this.state;

    return (
      <div id="app">
        {groceries.map(grocery => {
          return <div key={grocery.id}>{grocery.item}</div>;
        })}
      </div>
    );
  }
}

export default withStyles(childStyles)(Child);
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import React from "react";
import { mount } from "enzyme";
import App from "./App";
import Child from "./Child";

Enzyme.configure({ adapter: new Adapter() });

const mockResponse = (status, statusText, response) => {
  return new window.Response(response, {
    status: status,
    statusText: statusText,
    headers: {
      "Content-type": "application/json"
    }
  });
};

describe("App", () => {
  describe("ChildApp componentDidMount", () => {
    it("sets the state componentDidMount", () => {
      console.log("starting test for 200");

      global.fetch = jest.fn().mockImplementation(() =>
        Promise.resolve(
          mockResponse(
            200,
            null,
            JSON.stringify({
              groceries: [{ item: "nuts", id: 10 }, { item: "greens", id: 3 }]
            })
          )
        )
      );

      const renderedComponent = mount(<App />);
      const childApp = renderedComponent.find(Child);

      childApp
        .instance()
        .fetchCall()
        .then(() => {
          console.log("finished test for 200");
          expect(childApp.state("groceries").length).toEqual(2);
        });
    });

    it("sets the state componentDidMount on error", () => {
      console.log("starting test for 500");

      window.fetch = jest
        .fn()
        .mockImplementation(() =>
          Promise.resolve(
            mockResponse(
              400,
              "Test Error",
              JSON.stringify({ status: 400, statusText: "Test Error!" })
            )
          )
        );

      const renderedComponent = mount(<App />);
      const childApp = renderedComponent.find(Child);
      childApp
        .instance()
        .fetchCall()
        .then(() => {
          console.log("finished test for 500");
          expect(childApp.state("errorStatus")).toEqual(
            "Error fetching groceries"
          );
        });
    });
  });
});
App.test.js

import React from "react";
import Child from "./Child";

class App extends React.Component {
  render() {
    return <Child />;
  }
}

export default App;
import React from "react";
import { withStyles } from "@material-ui/core/styles";

const childStyles = {
  margin: 0
};

class Child extends React.Component {
  state = {
    groceries: [],
    errorStatus: ""
  };

  componentDidMount() {
    console.log("calling fetch");

    this.fetchCall();
  }

  fetchCall = () => {
    return fetch("/api/v1/groceries")
      .then(this.checkStatus)
      .then(this.parseJSON)
      .then(this.setStateFromData)
      .catch(this.setError);
  };

  checkStatus = results => {
    if (results.status >= 400) {
      console.log("bad status");

      throw new Error("Bad Status");
    }

    return results;
  };

  setError = () => {
    console.log("error thrown");

    return this.setState({ errorStatus: "Error fetching groceries" });
  };

  parseJSON = results => {
    console.log("parse json");

    return results.json();
  };

  setStateFromData = data => {
    console.log("setting state");

    return this.setState({ groceries: data.groceries });
  };

  render() {
    const { groceries } = this.state;

    return (
      <div id="app">
        {groceries.map(grocery => {
          return <div key={grocery.id}>{grocery.item}</div>;
        })}
      </div>
    );
  }
}

export default withStyles(childStyles)(Child);
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import React from "react";
import { mount } from "enzyme";
import App from "./App";
import Child from "./Child";

Enzyme.configure({ adapter: new Adapter() });

const mockResponse = (status, statusText, response) => {
  return new window.Response(response, {
    status: status,
    statusText: statusText,
    headers: {
      "Content-type": "application/json"
    }
  });
};

describe("App", () => {
  describe("ChildApp componentDidMount", () => {
    it("sets the state componentDidMount", () => {
      console.log("starting test for 200");

      global.fetch = jest.fn().mockImplementation(() =>
        Promise.resolve(
          mockResponse(
            200,
            null,
            JSON.stringify({
              groceries: [{ item: "nuts", id: 10 }, { item: "greens", id: 3 }]
            })
          )
        )
      );

      const renderedComponent = mount(<App />);
      const childApp = renderedComponent.find(Child);

      childApp
        .instance()
        .fetchCall()
        .then(() => {
          console.log("finished test for 200");
          expect(childApp.state("groceries").length).toEqual(2);
        });
    });

    it("sets the state componentDidMount on error", () => {
      console.log("starting test for 500");

      window.fetch = jest
        .fn()
        .mockImplementation(() =>
          Promise.resolve(
            mockResponse(
              400,
              "Test Error",
              JSON.stringify({ status: 400, statusText: "Test Error!" })
            )
          )
        );

      const renderedComponent = mount(<App />);
      const childApp = renderedComponent.find(Child);
      childApp
        .instance()
        .fetchCall()
        .then(() => {
          console.log("finished test for 500");
          expect(childApp.state("errorStatus")).toEqual(
            "Error fetching groceries"
          );
        });
    });
  });
});
从“酶”导入酶;
从“酶-适配器-反应-16”导入适配器;
从“React”导入React;
从“酶”导入{mount};
从“/App”导入应用程序;
从“/Child”导入子项;
configure({adapter:newadapter()});
const mockResponse=(状态、状态文本、响应)=>{
返回新窗口。响应(响应{
状态:状态,
statusText:statusText,
标题:{
“内容类型”:“应用程序/json”
}
});
};
描述(“应用程序”,()=>{
描述(“ChildApp componentDidMount”,()=>{
它(“设置状态组件didmount”,()=>{
console.log(“200的启动测试”);
global.fetch=jest.fn().mockImplementation(()=>
承诺,决心(
模拟反应(
200,
无效的
JSON.stringify({
杂货:[{项目:“坚果”,id:10},{项目:“绿色”,id:3}]
})
)
)
);
const renderedComponent=mount();
const childApp=renderedComponent.find(Child);
childApp
.instance()
.fetchCall()
.然后(()=>{
console.log(“已完成200的测试”);
预计(儿童用品州(“杂货店”)。长度)。toEqual(2);
});
});
它(“在错误时设置状态组件didmount”,()=>{
console.log(“500的启动测试”);
window.fetch=jest
.fn()
.mockImplementation(()=>
承诺,决心(
模拟反应(
400,
“测试错误”,
stringify({status:400,statusText:“测试错误!”})
)
)
);
const renderedComponent=mount();
const childApp=renderedComponent.find(Child);
childApp
.instance()
.fetchCall()
.然后(()=>{
console.log(“完成500的测试”);
expect(childApp.state(“errorStatus”).toEqual(
“提取杂货时出错”
);
});
});
});
});

写了这篇文章后,我找到了答案,但我觉得这值得分享,因为我对此感到非常困惑

不要使用
app.find(Child)
(组件构造函数),而是使用
app.find('Child')
(组件显示名称)。这将找到实际的组件,而不是hoc包装的组件


测试方法存在问题。它实际上不会像我想的那样,端到端地测试这个。。。调用child.instance().fetchFunction()。然后(()=>expect(..)-这不是e2e测试,而是某种低效的集成测试。您仍在直接测试子单元,但这样做的方式很难证明是合理的。并没有任何东西需要将孩子作为应用程序测试的一部分进行测试。不管怎样,您都可以通过
innerRef
获得对内部组件的引用,您是对的,它不是e2e,我已将其改为“集成测试”。我尝试过使用
instance().innerRef
,但它返回
undefined