diff --git a/enzyme/enzyme-tests.tsx b/enzyme/enzyme-tests.tsx new file mode 100644 index 000000000..71e82351f --- /dev/null +++ b/enzyme/enzyme-tests.tsx @@ -0,0 +1,574 @@ +/// +/// + +import { shallow, mount, render, describeWithDOM, spyLifecycle } from "enzyme"; +import * as React from "react"; +import {Component, ReactElement} from "react"; +import {ShallowWrapper, ReactWrapper, CheerioWrapper} from "enzyme"; + + +// Help classes/interfaces +interface MyComponentProps { + propsProperty: any; +} + +interface MyComponentState { + stateProperty: any; +} + +class MyComponent extends Component { + setState(...args: any[]) { + } +} + +// API +module SpyLifecycleTest { + spyLifecycle(MyComponent); +} + +// ShallowWrapper +module ShallowWrapperTest { + var shallowWrapper: ShallowWrapper = + shallow(); + + var reactElement: ReactElement, + objectVal: Object, + boolVal: Boolean, + stringVal: String; + + function test_find() { + shallowWrapper = shallowWrapper.find('.selector'); + shallowWrapper = shallowWrapper.find(MyComponent); + } + + function test_findWhere() { + shallowWrapper = + shallowWrapper.findWhere((aShallowWrapper: ShallowWrapper) => true); + } + + function test_filter() { + shallowWrapper = shallowWrapper.filter('.selector'); + shallowWrapper = shallowWrapper.filter(MyComponent); + } + + function test_filterWhere() { + shallowWrapper = + shallowWrapper.filterWhere((aShallowWrapper: ShallowWrapper) => true); + } + + function test_contains() { + boolVal = shallowWrapper.contains(
); + } + + function test_hasClass() { + boolVal = shallowWrapper.find('.my-button').hasClass('disabled'); + } + + function test_is() { + boolVal = shallowWrapper.is('.some-class'); + } + + function test_not() { + shallowWrapper = shallowWrapper.find('.foo').not('.bar'); + } + + function test_children() { + shallowWrapper = shallowWrapper.children(); + } + + function test_parents() { + shallowWrapper = shallowWrapper.parents(); + } + + function test_parent() { + shallowWrapper = shallowWrapper.parent(); + } + + function test_closest() { + shallowWrapper = shallowWrapper.closest('.selector'); + shallowWrapper = shallowWrapper.closest(MyComponent); + } + + function test_shallow() { + shallowWrapper = shallowWrapper.shallow(); + } + + function test_render() { + var cheerioWrapper: CheerioWrapper = shallowWrapper.render(); + } + + function test_text() { + stringVal = shallowWrapper.text(); + } + + + function test_html() { + stringVal = shallowWrapper.html(); + } + + function test_get() { + reactElement = shallowWrapper.get(1); + } + + function test_at() { + shallowWrapper = shallowWrapper.at(1); + } + + function test_first() { + shallowWrapper = shallowWrapper.first(); + } + + function test_last() { + shallowWrapper = shallowWrapper.last(); + } + + function test_state() { + shallowWrapper.state(); + shallowWrapper.state('key'); + } + + function test_props() { + objectVal = shallowWrapper.props(); + } + + function test_prop() { + shallowWrapper.prop('key'); + } + + + function test_simulate(...args: any[]) { + shallowWrapper.simulate('click'); + shallowWrapper.simulate('click', args); + } + + function test_setState() { + shallowWrapper = shallowWrapper.setState({stateProperty: 'state'}); + } + + function test_setProps() { + shallowWrapper = shallowWrapper.setProps({propsProperty: 'foo'}); + } + + function test_setContext() { + shallowWrapper = shallowWrapper.setContext({name: 'baz'}); + } + + function test_instance() { + var myComponent: MyComponent = shallowWrapper.instance(); + } + + function test_update() { + shallowWrapper = shallowWrapper.update(); + } + + function test_debug() { + stringVal = shallowWrapper.debug(); + } + + function test_type() { + var stringOrFunction: String|Function = shallowWrapper.type(); + } + + function test_forEach() { + shallowWrapper = + shallowWrapper.forEach((aShallowWrapper: ShallowWrapper)=> { + }); + } + + function test_map() { + var arrayVal: Array = + shallowWrapper.map((aShallowWrapper: ShallowWrapper)=> { + }); + } + + function test_reduce() { + const total: number[] = + shallowWrapper.reduce( + (amount: number, n: ShallowWrapper) => amount + n.prop('amount') + ); + } + + function test_reduceRight() { + const total: number[] = + shallowWrapper.reduceRight( + (amount: number, n: ShallowWrapper) => amount + n.prop('amount') + ); + } + + function test_some() { + boolVal = shallowWrapper.some('.selector'); + boolVal = shallowWrapper.some(MyComponent); + } + + function test_someWhere() { + boolVal = shallowWrapper.someWhere((aShallowWrapper: ShallowWrapper) => true); + } + + function test_every() { + boolVal = shallowWrapper.every('.selector'); + boolVal = shallowWrapper.every(MyComponent); + } + + function test_everyWhere() { + boolVal = shallowWrapper.everyWhere((aShallowWrapper: ShallowWrapper) => true); + } +} + + +// ReactWrapper +module ReactWrapperTest { + var reactWrapper: ReactWrapper = + mount(); + + var reactElement: ReactElement, + objectVal: Object, + boolVal: Boolean, + stringVal: String; + + function test_find() { + reactWrapper = reactWrapper.find('.selector'); + reactWrapper = reactWrapper.find(MyComponent); + } + + function test_findWhere() { + reactWrapper = + reactWrapper.findWhere((aReactWrapper: ReactWrapper) => true); + } + + function test_filter() { + reactWrapper = reactWrapper.filter('.selector'); + reactWrapper = reactWrapper.filter(MyComponent); + } + + function test_filterWhere() { + reactWrapper = + reactWrapper.filterWhere((aReactWrapper: ReactWrapper) => true); + } + + function test_contains() { + boolVal = reactWrapper.contains(
); + } + + function test_hasClass() { + boolVal = reactWrapper.find('.my-button').hasClass('disabled'); + } + + function test_is() { + boolVal = reactWrapper.is('.some-class'); + } + + function test_not() { + reactWrapper = reactWrapper.find('.foo').not('.bar'); + } + + function test_children() { + reactWrapper = reactWrapper.children(); + } + + function test_parents() { + reactWrapper = reactWrapper.parents(); + } + + function test_parent() { + reactWrapper = reactWrapper.parent(); + } + + function test_closest() { + reactWrapper = reactWrapper.closest('.selector'); + reactWrapper = reactWrapper.closest(MyComponent); + } + + function test_text() { + stringVal = reactWrapper.text(); + } + + function test_html() { + stringVal = reactWrapper.html(); + } + + function test_get() { + reactElement = reactWrapper.get(1); + } + + function test_at() { + reactWrapper = reactWrapper.at(1); + } + + function test_first() { + reactWrapper = reactWrapper.first(); + } + + function test_last() { + reactWrapper = reactWrapper.last(); + } + + function test_state() { + reactWrapper.state(); + reactWrapper.state('key'); + } + + function test_props() { + objectVal = reactWrapper.props(); + } + + function test_prop() { + reactWrapper.prop('key'); + } + + + function test_simulate(...args: any[]) { + reactWrapper.simulate('click'); + reactWrapper.simulate('click', args); + } + + function test_setState() { + reactWrapper = reactWrapper.setState({stateProperty: 'state'}); + } + + function test_setProps() { + reactWrapper = reactWrapper.setProps({propsProperty: 'foo'}); + } + + function test_setContext() { + reactWrapper = reactWrapper.setContext({name: 'baz'}); + } + + function test_instance() { + var myComponent: MyComponent = reactWrapper.instance(); + } + + function test_update() { + reactWrapper = reactWrapper.update(); + } + + function test_debug() { + stringVal = reactWrapper.debug(); + } + + function test_type() { + var stringOrFunction: String|Function = reactWrapper.type(); + } + + function test_forEach() { + reactWrapper = + reactWrapper.forEach((aReactWrapper: ReactWrapper)=> { + }); + } + + function test_map() { + var arrayVal: Array = + reactWrapper.map((aReactWrapper: ReactWrapper)=> { + }); + } + + function test_reduce() { + const total: number[] = + reactWrapper.reduce( + (amount: number, n: ReactWrapper) => amount + n.prop('amount') + ); + } + + function test_reduceRight() { + const total: number[] = + reactWrapper.reduceRight( + (amount: number, n: ReactWrapper) => amount + n.prop('amount') + ); + } + + function test_some() { + boolVal = reactWrapper.some('.selector'); + boolVal = reactWrapper.some(MyComponent); + } + + function test_someWhere() { + boolVal = reactWrapper.someWhere((aReactWrapper: ReactWrapper) => true); + } + + function test_every() { + boolVal = reactWrapper.every('.selector'); + boolVal = reactWrapper.every(MyComponent); + } + + function test_everyWhere() { + boolVal = reactWrapper.everyWhere((aReactWrapper: ReactWrapper) => true); + } +} + +// CheerioWrapper +module CheerioWrapperTest { + var cheerioWrapper: CheerioWrapper = + render(); + + var reactElement: ReactElement, + objectVal: Object, + boolVal: Boolean, + stringVal: String; + + function test_find() { + cheerioWrapper = cheerioWrapper.find('.selector'); + cheerioWrapper = cheerioWrapper.find(MyComponent); + } + + function test_findWhere() { + cheerioWrapper = + cheerioWrapper.findWhere((aCheerioWrapper: CheerioWrapper) => true); + } + + function test_filter() { + cheerioWrapper = cheerioWrapper.filter('.selector'); + cheerioWrapper = cheerioWrapper.filter(MyComponent); + } + + function test_filterWhere() { + cheerioWrapper = + cheerioWrapper.filterWhere((aCheerioWrapper: CheerioWrapper) => true); + } + + function test_contains() { + boolVal = cheerioWrapper.contains(
); + } + + function test_hasClass() { + boolVal = cheerioWrapper.find('.my-button').hasClass('disabled'); + } + + function test_is() { + boolVal = cheerioWrapper.is('.some-class'); + } + + function test_not() { + cheerioWrapper = cheerioWrapper.find('.foo').not('.bar'); + } + + function test_children() { + cheerioWrapper = cheerioWrapper.children(); + } + + function test_parents() { + cheerioWrapper = cheerioWrapper.parents(); + } + + function test_parent() { + cheerioWrapper = cheerioWrapper.parent(); + } + + function test_closest() { + cheerioWrapper = cheerioWrapper.closest('.selector'); + cheerioWrapper = cheerioWrapper.closest(MyComponent); + } + + function test_text() { + stringVal = cheerioWrapper.text(); + } + + function test_html() { + stringVal = cheerioWrapper.html(); + } + + function test_get() { + reactElement = cheerioWrapper.get(1); + } + + function test_at() { + cheerioWrapper = cheerioWrapper.at(1); + } + + function test_first() { + cheerioWrapper = cheerioWrapper.first(); + } + + function test_last() { + cheerioWrapper = cheerioWrapper.last(); + } + + function test_state() { + cheerioWrapper.state(); + cheerioWrapper.state('key'); + } + + function test_props() { + objectVal = cheerioWrapper.props(); + } + + function test_prop() { + cheerioWrapper.prop('key'); + } + + + function test_simulate(...args: any[]) { + cheerioWrapper.simulate('click'); + cheerioWrapper.simulate('click', args); + } + + function test_setState() { + cheerioWrapper = cheerioWrapper.setState({stateProperty: 'state'}); + } + + function test_setProps() { + cheerioWrapper = cheerioWrapper.setProps({propsProperty: 'foo'}); + } + + function test_setContext() { + cheerioWrapper = cheerioWrapper.setContext({name: 'baz'}); + } + + function test_instance() { + var myComponent: MyComponent = cheerioWrapper.instance(); + } + + function test_update() { + cheerioWrapper = cheerioWrapper.update(); + } + + function test_debug() { + stringVal = cheerioWrapper.debug(); + } + + function test_type() { + var stringOrFunction: String|Function = cheerioWrapper.type(); + } + + function test_forEach() { + cheerioWrapper = + cheerioWrapper.forEach((aCheerioWrapper: CheerioWrapper)=> { + }); + } + + function test_map() { + var arrayVal: Array = + cheerioWrapper.map((aCheerioWrapper: CheerioWrapper)=> { + }); + } + + function test_reduce() { + const total: number[] = + cheerioWrapper.reduce( + (amount: number, n: CheerioWrapper) => amount + n.prop('amount') + ); + } + + function test_reduceRight() { + const total: number[] = + cheerioWrapper.reduceRight( + (amount: number, n: CheerioWrapper) => amount + n.prop('amount') + ); + } + + function test_some() { + boolVal = cheerioWrapper.some('.selector'); + boolVal = cheerioWrapper.some(MyComponent); + } + + function test_someWhere() { + boolVal = cheerioWrapper.someWhere((aCheerioWrapper: CheerioWrapper) => true); + } + + function test_every() { + boolVal = cheerioWrapper.every('.selector'); + boolVal = cheerioWrapper.every(MyComponent); + } + + function test_everyWhere() { + boolVal = cheerioWrapper.everyWhere((aCheerioWrapper: CheerioWrapper) => true); + } +} diff --git a/enzyme/enzyme.d.ts b/enzyme/enzyme.d.ts new file mode 100644 index 000000000..dd0c996a7 --- /dev/null +++ b/enzyme/enzyme.d.ts @@ -0,0 +1,340 @@ +// Type definitions for Enzyme v1.2.0 +// Project: https://github.com/airbnb/enzyme +// Definitions by: Marian Palkus , Cap3 +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +/// + +declare module "enzyme" { + + import {ReactElement, Component} from "react"; + + export class ElementClass extends Component { + } + + /** + * Many methods in Enzyme's API accept a selector as an argument. Selectors in Enzyme can fall into one of the + * following three categories: + * + * 1. A Valid CSS Selector + * 2. A React Component Constructor + * 3. A React Component's displayName + */ + export type EnzymeSelector = String | typeof ElementClass; + + interface CommonWrapper { + /** + * Find every node in the render tree that matches the provided selector. + * @param selector The selector to match. + */ + find(selector: EnzymeSelector): T; + + /** + * Finds every node in the render tree that returns true for the provided predicate function. + * @param predicate + */ + findWhere(predicate: (shallowWrapper: ShallowWrapper) => Boolean): T; + + /** + * Removes nodes in the current wrapper that do not match the provided selector. + * @param selector The selector to match. + */ + filter(selector: EnzymeSelector): T; + + /** + * Returns a new wrapper with only the nodes of the current wrapper that, when passed into the provided predicate function, return true. + * @param predicate + */ + filterWhere(predicate: (shallowWrapper: ShallowWrapper) => Boolean): T; + + /** + * Returns whether or not the current wrapper has a node anywhere in it's render tree that looks like the one passed in. + * @param node + */ + contains(node: ReactElement): Boolean; + + /** + * Returns whether or not the current node has a className prop including the passed in class name. + * @param className + */ + hasClass(className: String): Boolean; + + /** + * Returns whether or not the current node matches a provided selector. + * @param selector + */ + is(selector: EnzymeSelector): Boolean; + + /** + * Returns a new wrapper with only the nodes of the current wrapper that don't match the provided selector. + * This method is effectively the negation or inverse of filter. + * @param selector + */ + not(selector: EnzymeSelector): T; + + /** + * Returns a new wrapper with all of the children of the node(s) in the current wrapper. Optionally, a selector + * can be provided and it will filter the children by this selector. + * @param [selector] + */ + children(selector?: EnzymeSelector): T; + + /** + * Returns a wrapper around all of the parents/ancestors of the wrapper. Does not include the node in the + * current wrapper. Optionally, a selector can be provided and it will filter the parents by this selector. + * + * Note: can only be called on a wrapper of a single node. + * @param [selector] + */ + parents(selector?: EnzymeSelector): T; + + /** + * Returns a wrapper with the direct parent of the node in the current wrapper. + */ + parent(): T; + + /** + * Returns a wrapper of the first element that matches the selector by traversing up through the current node's + * ancestors in the tree, starting with itself. + * + * Note: can only be called on a wrapper of a single node. + * @param selector + */ + closest(selector: EnzymeSelector): T; + + /** + * Returns a string of the rendered text of the current render tree. This function should be looked at with + * skepticism if being used to test what the actual HTML output of the component will be. If that is what you + * would like to test, use enzyme's render function instead. + * + * Note: can only be called on a wrapper of a single node. + */ + text(): String; + + /** + * Returns a string of the rendered HTML markup of the current render tree. + * + * Note: can only be called on a wrapper of a single node. + */ + html(): String; + + /** + * Returns the node at a given index of the current wrapper. + * @param index + */ + get(index: number): ReactElement; + + /** + * Returns a wrapper around the node at a given index of the current wrapper. + * @param index + */ + at(index: number): T; + + /** + * Reduce the set of matched nodes to the first in the set. + */ + first(): T; + + /** + * Reduce the set of matched nodes to the last in the set. + */ + last(): T; + + /** + * Returns the state hash for the root node of the wrapper. Optionally pass in a prop name and it will return just that value. + * @param [key] + */ + state(key?: String): any; + + /** + * Returns the props hash for the current node of the wrapper. + * + * NOTE: can only be called on a wrapper of a single node. + */ + props(): Object; + + /** + * Returns the prop value for the node of the current wrapper with the provided key. + * + * NOTE: can only be called on a wrapper of a single node. + * @param key + */ + prop(key: String): any; + + /** + * Simulate events. + * Returns itself. + * @param event + * @param args? + */ + simulate(event: String, ...args: any[]): T; + + /** + * A method to invoke setState() on the root component instance similar to how you might in the definition of + * the component, and re-renders. This method is useful for testing your component in hard to achieve states, + * however should be used sparingly. If possible, you should utilize your component's external API in order to + * get it into whatever state you want to test, in order to be as accurate of a test as possible. This is not + * always practical, however. + * Returns itself. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + * @param state + */ + setState(state: S): T; + + /** + * A method that sets the props of the root component, and re-renders. Useful for when you are wanting to test + * how the component behaves over time with changing props. Calling this, for instance, will call the + * componentWillReceiveProps lifecycle method. + * + * Similar to setState, this method accepts a props object and will merge it in with the already existing props. + * Returns itself. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + * @param state + */ + setProps(state: Object): T; + + /** + * A method that sets the context of the root component, and re-renders. Useful for when you are wanting to + * test how the component behaves over time with changing contexts. + * Returns itself. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + * @param state + */ + setContext(state: Object): T; + + /** + * Gets the instance of the component being rendered as the root node passed into shallow(). + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + */ + instance(): Component; + + /** + * Forces a re-render. Useful to run before checking the render output if something external may be updating + * the state of the component somewhere. + * Returns itself. + * + * NOTE: can only be called on a wrapper instance that is also the root instance. + */ + update(): T; + + /** + * Returns an html-like string of the wrapper for debugging purposes. Useful to print out to the console when + * tests are not passing when you expect them to. + */ + debug(): String; + + /** + * Returns the type of the current node of this wrapper. If it's a composite component, this will be the + * component constructor. If it's native DOM node, it will be a string of the tag name. + * + * Note: can only be called on a wrapper of a single node. + */ + type(): String | Function; + + /** + * Iterates through each node of the current wrapper and executes the provided function with a wrapper around + * the corresponding node passed in as the first argument. + * + * Returns itself. + * @param fn A callback to be run for every node in the collection. Should expect a ShallowWrapper as the first + * argument, and will be run with a context of the original instance. + */ + forEach(fn: (wrapper: ShallowWrapper) => void): T; + + /** + * Maps the current array of nodes to another array. Each node is passed in as a ShallowWrapper to the map + * function. + * Returns an array of the returned values from the mapping function.. + * @param fn A mapping function to be run for every node in the collection, the results of which will be mapped + * to the returned array. Should expect a ShallowWrapper as the first argument, and will be run + * with a context of the original instance. + */ + map(fn: (wrapper: ShallowWrapper) => any): Array; + + /** + * Applies the provided reducing function to every node in the wrapper to reduce to a single value. Each node + * is passed in as a ShallowWrapper, and is processed from left to right. + * @param fn + * @param initialValue + */ + reduce(fn: (prevVal: R, wrapper: ShallowWrapper, index: number) => R, initialValue?: R): R[]; + + /** + * Applies the provided reducing function to every node in the wrapper to reduce to a single value. + * Each node is passed in as a ShallowWrapper, and is processed from right to left. + * @param fn + * @param initialValue + */ + reduceRight(fn: (prevVal: R, wrapper: ShallowWrapper, index: number) => R, initialValue?: R): R[]; + + /** + * Returns whether or not any of the nodes in the wrapper match the provided selector. + * @param selector + */ + some(selector: EnzymeSelector): Boolean; + + /** + * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. + * @param fn + */ + someWhere(fn: (wrapper: ShallowWrapper) => Boolean): Boolean; + + /** + * Returns whether or not all of the nodes in the wrapper match the provided selector. + * @param selector + */ + every(selector: EnzymeSelector): Boolean; + + /** + * Returns whether or not any of the nodes in the wrapper pass the provided predicate function. + * @param fn + */ + everyWhere(fn: (wrapper: ShallowWrapper) => Boolean): Boolean; + + length: number; + } + + export interface ShallowWrapper extends CommonWrapper, P, S> { + shallow(): ShallowWrapper; + + render(): CheerioWrapper; + } + + export interface ReactWrapper extends CommonWrapper, P, S> { + + } + + export interface CheerioWrapper extends CommonWrapper, P, S> { + + } + + /** + * Shallow rendering is useful to constrain yourself to testing a component as a unit, and to ensure that + * your tests aren't indirectly asserting on behavior of child components. + * @param node + * @param [options] + */ + export function shallow(node: ReactElement

, options?: any): ShallowWrapper; + + /** + * Mounts and renders a react component into the document and provides a testing wrapper around it. + * @param node + * @param [options] + */ + export function mount(node: ReactElement

, options?: any): ReactWrapper; + + /** + * Render react components to static HTML and analyze the resulting HTML structure. + * @param node + * @param [options] + */ + export function render(node: ReactElement

, options?: any): CheerioWrapper; + + export function describeWithDOM(description: String, fn: Function): void; + + export function spyLifecycle(component: typeof Component): void; +} \ No newline at end of file