Vous avez presque terminé sans aucun changement à part la façon dont vous spyOn
. Lorsque vous utilisez l'espion, vous avez deux options : spyOn
el App.prototype
ou composant component.instance()
.
const spy = jest.spyOn(Class.prototype, "method")
L'ordre d'attachement de l'espion sur le prototype de la classe et de rendu (shallow rendering) de votre instance est important.
const spy = jest.spyOn(App.prototype, "myClickFn");
const instance = shallow(<App />);
El App.prototype
sur la première ligne, il y a ce dont vous avez besoin pour que les choses fonctionnent. Un JavaScript class
ne dispose d'aucune de ses méthodes tant que vous ne l'instanciez pas avec la commande new MyClass()
ou vous plongez dans le MyClass.prototype
. Pour votre question particulière, vous aviez juste besoin d'espionner le App.prototype
méthode myClickFn
.
jest.spyOn(composant.instance(), "method")
const component = shallow(<App />);
const spy = jest.spyOn(component.instance(), "myClickFn");
Cette méthode nécessite un shallow/render/mount
instance d'un React.Component
pour être disponible. Essentiellement spyOn
est juste à la recherche de quelque chose à détourner et à mettre dans un jest.fn()
. C'est possible :
Une simple object
:
const obj = {a: x => (true)};
const spy = jest.spyOn(obj, "a");
A class
:
class Foo {
bar() {}
}
const nope = jest.spyOn(Foo, "bar");
// THROWS ERROR. Foo has no "bar" method.
// Only an instance of Foo has "bar".
const fooSpy = jest.spyOn(Foo.prototype, "bar");
// Any call to "bar" will trigger this spy; prototype or instance
const fooInstance = new Foo();
const fooInstanceSpy = jest.spyOn(fooInstance, "bar");
// Any call fooInstance makes to "bar" will trigger this spy.
Ou un React.Component instance
:
const component = shallow(<App />);
/*
component.instance()
-> {myClickFn: f(), render: f(), ...etc}
*/
const spy = jest.spyOn(component.instance(), "myClickFn");
Ou un React.Component.prototype
:
/*
App.prototype
-> {myClickFn: f(), render: f(), ...etc}
*/
const spy = jest.spyOn(App.prototype, "myClickFn");
// Any call to "myClickFn" from any instance of App will trigger this spy.
J'ai utilisé et vu les deux méthodes. Lorsque j'ai un beforeEach()
o beforeAll()
bloc, je pourrais opter pour la première approche. Si j'ai juste besoin d'un espion rapide, j'utiliserai la seconde. Il faut juste faire attention à l'ordre de fixation de l'espion.
EDIT : Si vous voulez vérifier les effets secondaires de votre myClickFn
vous pouvez simplement l'invoquer dans un test séparé.
const app = shallow(<App />);
app.instance().myClickFn()
/*
Now assert your function does what it is supposed to do...
eg.
expect(app.state("foo")).toEqual("bar");
*/
EDIT : Voici un exemple d'utilisation d'un composant fonctionnel. Gardez à l'esprit que toutes les méthodes scopées dans votre composant fonctionnel ne sont pas disponibles pour l'espionnage. Vous espionnez les fonctions passées dans votre composant fonctionnel et testez l'invocation de celles-ci. Cet exemple explore l'utilisation de jest.fn()
à l'opposé de jest.spyOn
qui partagent tous deux l'API de la fonction de simulation. Bien qu'elle ne réponde pas à la question initiale, elle donne un aperçu d'autres techniques qui pourraient convenir à des cas indirectement liés à la question.
function Component({ myClickFn, items }) {
const handleClick = (id) => {
return () => myClickFn(id);
};
return (<>
{items.map(({id, name}) => (
<div key={id} onClick={handleClick(id)}>{name}</div>
))}
</>);
}
const props = { myClickFn: jest.fn(), items: [/*...{id, name}*/] };
const component = render(<Component {...props} />);
// Do stuff to fire a click event
expect(props.myClickFn).toHaveBeenCalledWith(/*whatever*/);