Git Product home page Git Product logo

preact-render-spy's Introduction

preact-render-spy

preact-render-spy is a package designed to cover many of the use cases for testing preact components. The API is roughly modeled after enzyme, but we do not support as many options currently.

Build Status

Support:

We do our best to support Node.JS v6.11.0 and up, and speficially testing with jest, though other test runners should have no problems.

Expressive Testing Example:

import {h} from 'preact';
import {shallow} from 'preact-render-spy';
import Testable from './testable';

it('lets you do cool things with preact components', () => {
  const context = shallow(<Testable />);
  expect(context.find('div').contains(<a>link</a>)).toBeTruthy();
  context.find('[onClick]').simulate('click');
  expect(context.find('a').text()).toBe('clicked');
});

How it works

The main render method takes some arbitrary JSX and replaces any component nodes with spies which wrap the component. These spies then look at the rendered output of the second level of JSX and stores a big map of all the JSX virtual DOM nodes that have been created by your component.

There is also concept of limiting the depth of the rendering such that it will only resolve a certain number of levels deep in the component tree. The depth of the default renderer is set to Infinity, and we provide another renderer called shallow to render with { depth: 1 }.

Jest Snapshot support

We provide a plugin for rendering your jsx snapshots to a formatted string that you can enable using the jest configuration:

{
  "snapshotSerializers": [ "preact-render-spy/snapshot" ]
}

Configuration

We export a config object which you can use to change some of the internal options. The values shown in this section are the defaults:

import {config} from 'preact-render-spy';

// This property is used by the spy renderer to pass information to the spies about where
// they are in the vdom tree, it is generally removed from the properties passed down to your
// component, but it might show up in some cases, and we want you to be able to pick it.
config.SPY_PRIVATE_KEY = 'SPY_PRIVATE_KEY';

// These options are passed to preact-render-to-string/jsx whenever you snapshot a VNode or
// FindWrapper (and on the FindWrapper's toString method)
config.toStringOptions = { shallow: true, skipFalseAttributes: false };

// This option allows you to use a custom DOM implementation instead of relying on a global
// document.createDocumentFragment()
config.createFragment = () => document.createDocumentFragment();

Exported Methods

deep(jsx, {depth = Infinity} = {})

Creates a new RenderContext and renders using opts.depth to specify how many components deep it should allow the renderer to render. Also exported as render and default.

Example:

const Deeper = () => <div>Until Infinity!</div>;
const Second = () => <Deeper />;
const First = () => <Second />;

let context;
context = deep(<First />);
expect(context.find('div').text()).toBe('Until Infinity!');

context = deep(<First />, { depth: 2 });
// We rendered First and Second, but not Deeper, so we never render a <div>
expect(context.find('div').length).toBe(0);

shallow(jsx)

Creates a new RenderContext with { depth: 1 }.

RenderContext#find(selector)

Given a rendered context, find accepts a "css like" language of selectors to search through the rendered vdom for given nodes. NOTE: We only support this very limited set of "selectors", and no nesting. We may expand this selector language in future versions, but it acheives our goals so far!

  • find('.selector') - searches for any nodes with class or className attribute that matches selector
  • find('#selector') - searches for any nodes with an id attribute that matches selector
  • find('[selector]') - searches for any nodes which have an attribute named selector
  • find('Selector') - searches for any nodes which have a nodeName that matches Selector, this will search for function/classes whos name is Selector, or displayName is Selector. If the Selector starts with a lower case letter, it will also check for tags like div.
  • find(<Selector simple="attributes" class="working" />) - searches for any nodes whos nodeName equals Selector and attributes match the ones given in the JSX. NOTE: This does not support children, just simple attributes. Can be useful to find components from minified output that don't include display names. .find(<ImportedComponent />) will look for JSX nodes using the same ImportedComponent function.

This will return you a FindWrapper which has other useful methods for testing.

RenderContext extends FindWrapper

Like #find(selector) RenderContext has the rest of FindWrapper's methods.

RenderContext#render(jsx)

Renders the root level jsx node using the same depth initially requested. This can be useful for testing componentWillReceiveProps hooks.

Example:

const Node = ({name}) => <div>{name}</div>
const context = shallow(<Node name="example" />);
expect(context.find('div').text()).toBe('example');

context.render(<Node name="second" />);
expect(context.find('div').text()).toBe('second');

RenderContext.rerender()

Calls preact.rerender() which performs any state changes in the render queue.

FindWrapper

Contains a selection of nodes from RenderContext#find(selector). Has numeric indexed properties and length like an array.

FindWrapper#at(index)

Returns another FindWrapper at the specific index in the selection. Similar to wrapper[0] but will allow using other FindWrapper methods on the result.

FindWrapper#attr(name)

Requires a single node selection to work. Returns the value of the name attribute on the jsx node.

FindWrapper#attrs()

Requires a single node selection to work. Returns a copy of the attributes passed to the jsx node.

FindWrapper#component()

Requires a single node, which is a class based component. Returns the Spied component. preact-render-spy creates a subclass of your components that enable us to spy things, you'll get a class Spy extends YourComponent instance.

Example:

const context = shallow(<MyComponent />);
expect(context.component()).toBeInstanceOf(MyComponent);

FindWrapper#contains(vdom)

Searches for any children matching the vdom or text passed.

FindWrapper#children()

Returns FindWrapper with children of current wrapper.

FindWrapper#childAt(index)

Returns FindWrapper with child at given index. This has the same effect as calling wrapper.children().at(index).

const context = shallow(<List items={items} />);
expect(context.childAt(1).text()).toBe('Second list element');

FindWrapper#exists()

Returns whether or not given node exists.

FindWrapper#filter(selector)

Returns a new FindWrapper with a subset of the previously selected elements given the selector argument.

Uses the same possible selectors as RenderContext#find(selector).

FindWrapper#map(fn)

Maps array of nodes from this FindWrapper to another array. Each node is passed in as a FindWrapper to the map function along with index number of element.

const context = shallow((
  <ul>
    <li class="item">first</li>
    <li class="item">second</li>
    <li class="item">third</li>
  </ul>
));

const items = context.find('.item').map(node => node.text());
expect(items).toEqual(['first', 'second', 'third']);

FindWrapper#find(selector)

Selects descendents of the elements previously selected. Returns a new FindWrapper with the newly selected elements.

Uses the same possible selectors as RenderContext#find(selector).

FindWrapper#first()

Returns another FindWrapper at the first index in the selection.

FindWrapper#last()

Returns another FindWrapper at the last index in the selection.

FindWrapper#setState(newState)

Requires a single node, which is a class based component. Allows you to set the state of a rendered component. Automatically rerender()s the view.

Example:

const context = shallow(<ClickCounter />);
context.setState({ count: 2 });
expect(context.text()).toEqual('2');

FindWrapper#simulate(event, ...args)

Looks for an attribute properly named onEvent or onEventCapture and calls it, passing the arguments.

FindWrapper#state(key)

Requires a single node, which is a class based component. Reads the current state from the component. When passed key, this is essentially shorthand state(key) === state()[key].

Example:

const context = shallow(<ClickCounter />);
expect(context.state()).toEqual({ count: 0 });
context.find('[onClick]').simulate('click');
expect(context.state('count')).toEqual(1);

FindWrapper#text()

Returns the flattened string of any text children of any child component.

FindWrapper#output()

Requires a single Component or functional node. Returns the vdom output of the given component. Any Component or functional nodes will be "recursive" up to the depth you specified. I.E.:

Example:

const Second = ({ children }) => <div>second {children}</div>;
const First = () => <Second>first</Second>;

// rendered deep, we get the div output
expect(deep(<First />).output()).toEqual(<div>second first</div>);
// rendered shallow, we get the <Second> jsx node back
expect(shallow(<First />).output()).toEqual(<Second>first</Second>);

Examples

There are many examples in the source files. Some tests specific to shallow, tests specific to deep, and many more tests against both.

Simulate Clicks:

class ClickCount extends Component {
  constructor(...args) {
    super(...args);

    this.state = {count: 0};
    this.onClick = this.onClick.bind(this);
  }

  onClick() {
    this.setState({count: this.state.count + 1});
  }

  render({}, {count}) {
    return <div onClick={this.onClick}>{count}</div>;
  }
}
const context = shallow(<ClickCount/>);
expect(context.find('div').contains('0')).toBeTruthy();
context.find('[onClick]').simulate('click');
expect(context.find('div').contains('1')).toBeTruthy();

Testing componentWillUnmount

import { h, Component } from 'preact';
import { shallow } from 'preact-render-spy';

class Unmount extends Component {

  componentWillUnmount() {
    this.props.onUnmount(this);
  }

  render() {
    return <div>Unmount me</div>;
  }
}

it('triggers unmount', () => {
  const trigger = jest.fn();
  const context = shallow(<Unmount onUnmount={trigger} />);
  expect(trigger).not.toHaveBeenCalled();

  // This will trigger the componentWillUnmount
  context.render(null);
  expect(trigger).toHaveBeenCalled();
});

Testing componentWillReceiveProps

import { h, Component } from 'preact';
import { shallow } from 'preact-render-spy';

class ReceivesProps extends Component {
  constructor(props) {
    this.state = { value: props.value };
  }

  componentWillReceiveProps({ value }) {
    if (value !== this.props.value) {
      this.setState({ value: `_${value}_` })
    }
  }

  render() {
    return <div>{this.state.value}</div>
  }
}

it('receives props', () => {
  const context = shallow(<ReceivesProps value="test" />);
  expect(context.text()).toBe('test');

  context.render(<ReceivesProps value="second" />);
  expect(context.text()).toBe('_second_');
});

preact-render-spy's People

Contributors

andrewiggins avatar deseteral avatar dzikowskiw avatar gnarf avatar igorfonin avatar jmfirth avatar mzgoddard avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

preact-render-spy's Issues

Documentation for running on node

Can you add documentation for running on node?

I am currently using a hack found in a closed issue:

import 'undom/register';

global['document'].createDocumentFragment = () => global['document'].createElement('#fragment');

Hopefully there's a way to do this without messing with global objects!

target.className is null

let attr = target.class || target.className;
if (typeof attr === 'object') {

Upon a couple of context.render(<Component />) calls, when calling context.find('.class') I get an exception thrown since target.className is null and typeof null === 'object'.
I am tempted to say that the flow is expected to return false in the next if and for that to happen, previous check needs to exclude null values before checking typeof.

else if (!target || target[key] !== value) {
return false;
}

But I have to say that I don't know why target.className is null in the first place.

setting a defaultProps property on a component breaks the nodeName property of RenderContext

hey there,

if you do the following:

Example.js

import { h, Component } from 'preact';
class Example extends Component {
  render() {
    return (<div>hello, world</div>);
  }
}

Example.defaultProps = {
  foo: 'bar'
}

export default Example;

and then try to inspect the nodeName property of this class instance via RenderContext, you get an interesting looking object like this:

{
    [Function: Example]
    defaultProps: { foo: 'bar'}
}

I'm unsure what exactly is going on here. It looks like the component (as a function) is being assigned as a key to the nodeName property? how do we access this, or assert against it?

if you do this:

console.log( JSON.stringify(context.nodeName) );

it returns

undefined

Testing with HOC and shallow

Hi everyone!

I'm working with preact and I'm currently doing a dependency injector for some config we have in our app. I decided to use preact-context for the new api and I'm using it through a higher order component that consumes the dependencies and injects it onto the wrapped component.

The problem I'm facing is not testing the HOC itself, but rather, when we test a wrapped component that is part of another component. We usually use shallow for testing specially on the higher level components like the page containers. The problem I'm facing is that now we have a another layer with each component created with the HOC. I've read that enzyme has a dive function that allows you to go further down the hierarchy to the wrapped component even though it is not covered by the initial shallow.

Is there something similar here or any other way to replicate that behavior here?

Issue with `FindWrapper#attr(name)` When `attr` Value is a Boolean

Say you have a component that has a boolean prop:

const Hello = ({ isActive }) => <div style={{ display: isActive ? 'block' : 'none' }}>Hello</div>
<Hello isActive={false} />

In such a case, calling shallow(<Hello isActive={false} />).attr('isActive') will return undefined instead of the false you'd expect.

The reason for this is this line, which checks the truthiness of item.attributes[name], which this case fails, thus returning undefined.

Thank you for this wonderful project.

Deprecate `childAt`

Add a deprecate message and version deadline for removing childAt. It does not add enough user value for the (albeit small) added maintenance burden.

Strange output for toString method while using preact-i18n

Hello! I was trying the latest rc.7 to port my snapshot tests from manually use preact-render-to-string to this library built-in solution.

One glitch I found is when I try to snapsnot an element which uses preact-i18n.

This is my component method:

export const Select = ({ name, value, options, htmlFor, onBlur, onChange }) => {
    return (
        <select
            name={name}
            value={value}
            onChange={onChange}
            onBlur={onBlur}
            id={htmlFor}
        >
            <option value=""><Text id="select">Select</Text></option>
            {options.map(({ value, label }, i) => <option key={i} value={value}>{label}</option>)}
        </select>
    );
}

This is the output of preact-render-to-string/jsx:

<select
    name="foo"
    id="foo"
>
    <option value="">Select</option>
    <option value={1}>bar</option>
    <option value={2}>baz</option>
</select>

While this is the output of preact-render-spy snapshot:

preact-render-spy (1 nodes)
    -------
    <select
      name="foo"
      id="foo"
    >
      <option value="">[object Object]</option>
      <option value={1}>bar</option>
      <option value={2}>baz</option>
    </select>

Notice how the <Text id="select">Select</Text> is render as [object Object] in the snapshot.

Not sure if that's a problem only of preact-i18n though.

Error on import {shallow} from 'preact-render-spy';

When I import:
import {shallow} from 'preact-render-spy';

I get error from babel:

ERROR in ./node_modules/preact-render-spy/index.js
Module build failed: ReferenceError: [BABEL] [cut]node_modules\preact-render-spy\index.js: Unkn
own option: [cut]node_modules\preact\dist\preact.js.h. Check out http://babeljs.io/docs/usage/o
ptions/ for more information about options.

my .babelrc

{
    "compact": "false",
    "presets": ["env"],
    "plugins": [
        "transform-decorators-legacy",
        "transform-object-rest-spread",
        "transform-object-assign",
        ["transform-react-jsx", { "pragma": "h" }],
        "transform-react-jsx-source"
    ]
}

Any suggestions?

Consider a TypeScript version/types definition

Lots of the preact community seems to be using TypeScript, though I'm unfamiliar with how to do it myself, it would be awesome if we could create the type defs needed for those users!

.output() API Naming Bikeshed

We currently have .output() which returns a VNode, but the more I look at this, the more I think it might of been a mistake to not return a FindWrapper instance here. We need a method that can return the FindWrapper version of component output, and we've been talking about it over in #57 PR comments.

I wouldn't be entirely against going to a 2.0 and making .output() return a FindWrapper, and .nodes() returning VNodes or something, but if we can come up with a good name for outputWrapped() we might not need to break back-compat.

Is there any way to simulate keydown events?

Hi,
I'm trying to write this bit of code in a test

my-test.test.ts

...
context.find('.search_input').simulate("keyDown", { keyCode: 65 });
...

but the test fail and says:


ReferenceError: event is not defined

      at Object.onKeyDown (src/components/search_sale.tsx:199:189)
      at FindWrapper.simulate (node_modules/preact-render-spy/src/preact-render-spy.js:252:31)
      at Object.test (src/components/search_sale.test.tsx:21:35)
          at new Promise (<anonymous>)
          at <anonymous>
      at process._tickCallback (internal/process/next_tick.js:188:7)

Any suggestions what's wrong? Or simpler, how can simulate a KeyDown? I need to fill an input field

Thank you in advance

Issue with `.attr()`: Argument not assignable to parameter of type 'never'

I'm using this to test some code in TypeScript, however when I use .attr('id'), I get a compile time error:

Argument of type '"src"' is not assignable to parameter of type 'never'.

Example below:

function Text({ id, children }: IProps) {
  return <p id={id}>{children}</p>
}
...
const instance = shallow(<Text id="test" />);
const idValue = instance.find('p').attr('id'); // error

Thanks in advance for the help!

Are components valid selectors?

Firstly, thank you to all the maintainers and contributors who have worked on this - this package makes testing Preact apps so much easier!

I was just wondering if there's there any reason why a component can't be used as a selector for the render context's find method? (find(Selector) or find(ImportedComponent), for example.)

The documentation and types added in #78 only cover nodes, but as far as I can tell this already works: selToWhere(Selector) returns { nodeName: Selector }, and isWhere already handles nodeName values that are functions.

This would make testing in TypeScript easier, as creating a JSX selector without the required props causes type errors, while including the required props can make the test overly specific.

Happy to open a PR to add tests and update the types if that's all that's required.

document.createDocumentFragment is not a function

Getting the following:

TypeError: document.createDocumentFragment is not a function
      at RenderContext (node_modules/preact-render-spy/src/preact-render-spy.js:345:46)
      at deep (node_modules/preact-render-spy/src/preact-render-spy.js:373:49)
      at Context.<anonymous> (test/components/Burnout.tests.js:12:13)

My mocha/chai setup is:

import chai from 'chai';
import assertJsx from 'preact-jsx-chai';
import 'undom/register';
import 'babel-polyfill';
import 'ignore-styles';

I am using undom as you can see - what dom do you expect?

 "devDependencies": {
    "babel-plugin-module-resolver": "^2.7.1",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.6.0",
    "babel-register": "^6.26.0",
    "chai": "^4.1.2",
    "eslint": "^4.6.1",
    "eslint-config-synacor": "^1.1.1",
    "if-env": "^1.0.0",
    "ignore-styles": "^5.0.1",
    "mocha": "^3.5.0",
    "node-sass": "^4.5.3",
    "preact-cli": "^1.4.1",
    "preact-jsx-chai": "^2.2.1",
    "preact-render-spy": "^1.0.0-rc.8",
    "sass-lint": "^1.11.1",
    "sass-loader": "^6.0.6",
    "undom": "^0.3.3"
  },
  "dependencies": {
    "preact": "^8.2.5",
    "preact-compat": "^3.17.0",
    "react": "npm:preact-compat",
    "recompose": "^0.25.0"
  }

Separate FindWrapper core and extended methods

The PRs on the new FindWrapper methods (#53, #57, #59, #63) help show a strata in the FindWrapper methods. We can categorize the existing and proposed methods as "core" and "extended".

The core methods need knowledge of the internal structure of FindWrapper to operate.

The extended methods can be implemented with the core methods and without internal knowledge of FindWrapper.

This can provide some benefits to preact-render-spy:

  • Make FindWrapper's internal surface area smaller and future changes less prone to regressions on the extended methods
  • Extended method tests do not need to test for error cases that core methods handle for them, making testing extended methods easier, easier to review, and hopefully easier to contribute.
  • Help distinguish maintenance burden: changes to core methods should receive more thought and bugs receive higher priority
  • Easier to accept new extended methods. They should still fill some user need.

The following actions need to be performed:

  • Identify core and extended methods
  • Determine a "mixin" strategy
    • How is FindWrapper "extended"?
    • How can extended methods be disabled in tests?
    • Should each extended method have a separate file and test file?
  • Test that core without access to extended methods
  • Determine if extended methods can depend on other extended methods
  • Move core methods above extended methods in the documentation

What should the API look like?

Leaving #5 as a place to discuss where and how to announce this package. This Issue is for what the API currently is and how we want it changed to get it to an announcable state.

Ensure jest isn't transpiling source files (tests only)

@mzgoddard I think something with using jest-webpack on this repo is gonna cause us trouble, in order to maintain better compatibility, do we need it? can we avoid it? jest uses something like babel-register to jsx, do we need something else from jest-webpack?

Like I think #22 could maybe have been avoided?

Control state of the component under test

Let's say I've a component like this:

class Button extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    if (this.state.loading){
      return <span>Loading ...</span>;
    }
    return <button onClick={() => this.setState({ loading: true })}></button>;
  }
}

How can I test that when loading state prop is true the loading message is displayed?
It would be super useful to have something like enzyme's setState on the component. What do you think about this?

Support `componentWillReceiveProps` on "root" nodes:

  • Wrap the stuff passed to RenderContext.render in a ContextRootComponent who's state we can mutate with the stuff passed to render
  • Write tests ensuring that the root nodes passed will be re-rendered rather than thrown out and re-created
  • Remove note in README saying that it wont componentWillReceiveProps

(copy/pasta from the slack conversation)

gnarf [10:43]
hrm

[10:43]
i think i might of just come up with a way we can support re-rendering props

[10:43]
of the root elems

z [10:44]
nods

z [10:44]
i think that’d be useful too

[10:44]
you could wrap the root in another different spy

gnarf [10:44]
if we made the actual render() call use a ContextRootComponent who's state.children we set to whatever is passed to context.render()

[10:44]
then we can just mutate the state on that component

z [10:45]
nods

gnarf [10:45]
and call rerender()

Handy debug tips

Loving preact-render-spy!

I would like to contribute, and thought maybe we can start brainstorming ideas for developer experience/ergonomics for the wiki, as writing tests can sometimes be a little tricky.

One of the issues that I have is that I want to see the HTML of the component, for development purposes. This would be handy for seeing exactly what the component is outputting.

How would I do this? Something like:

const context = shallow(<Testable />);
console.log(context.output().html())

What other ideas do other folks have?

.find by data-attributes

Hi! First, thank you for your work)

I have a problem, I cannot find by any data-attributes.
For example:

const context = shallow(<SomeComponent />);
console.log(context.find('[data-target="id"]')); // FindWrapper { length: 0 }

And .find always return 0 nodes (although this element exist).
I tried different cases: .find('[data-target="id"]'), .find('div[data-target="id"]'), .find('data-target="id"'). But nothing.

Where is my mistake?

How would you test componentWillUnmount ?

Hello,

I'm trying preact-render-spy and it does the job very well, thank you for your work.
Right now I'm wondering how would you execute and test code inside a componentWillUnmount method ?

TypeError: Cannot read property 'nodeName' of null

Hi,
Thanks for this. It looks cool.

I get this TypeError: Cannot read property 'nodeName' of null error though. I haven't looked at all the code yet but it looks like you're recursively checking the vdom and at some point you try to check the nodeName of null

I think we should add a test on vdom being null here: https://github.com/mzgoddard/preact-render-spy/blob/master/src/preact-render-spy.js#L10

It seems to work when I add this at the beginning of spyWalk:

if (vdom === null) {
  return '';
}

Does it make sense ?

Syntax error in preact-render-spy when running with jest

Hi, firstly, looks like an ace library, I was just struggling with enzyme + preact this week!

I've found a potential bug, but it may be that I've not got the correct setup as there doesnt seem to be an issue when running the tests in this repo.

Running a simple test with Jest gives this error for me, minimal reproduction here

node_modules/preact-render-spy/src/preact-render-spy.js:19
  ),
  ^
SyntaxError: Unexpected token )

its fixed by removing the trailing comma after nodeName on this line

defaultProps not working correctly with functional components

When using functional components, defaultProps do not get applied. When switching to a class component, there are no problems. I've provided a minimal example below w/ the output of running the test suite.

const propTypes = {
  price: PropTypes.number
};

const defaultProps = {
  price: 0
};

function Price(props) {
  const { price } = props;
  return (
    <div className="price">
      ${price.toLocaleString()}
    </div>
  );
}

Price.propTypes = propTypes;
Price.defaultProps = defaultProps;

export { Price };
import { shallow } from 'preact-render-spy';
import { Price } from '../components/Price';

describe('<Price>', () => {
  test('it renders default price', () => {
    const snapshot = shallow(<Price />);
    expect(snapshot.find('.price').text()).toBe('$0');
  });
});
  TypeError: Cannot read property 'toLocaleString' of undefined

      at Price (src/components/Price.jsx:51:14)
      at new <anonymous> (node_modules/preact-render-spy/src/preact-render-spy.js:67:30)
      at x [as render] (node_modules/preact/dist/preact.min.js:1:5403)
      at k (node_modules/preact/dist/preact.min.js:1:6208)
      at k (node_modules/preact/dist/preact.min.js:1:6455)
      at i (node_modules/preact/dist/preact.min.js:1:965)
      at RenderContext.ContextRootWrapper.vdom (node_modules/preact-render-spy/src/preact-render-spy.js:423:7)
      at RenderContext.render (node_modules/preact-render-spy/src/preact-render-spy.js:462:10)
      at deep (node_modules/preact-render-spy/src/preact-render-spy.js:472:76)
      at shallow (node_modules/preact-render-spy/src/preact-render-spy.js:473:25)
      at Object.<anonymous> (src/tests/Price.test.js:13:21)
      at process._tickCallback (internal/process/next_tick.js:109:7)

Maping function for FindWrapper

It would be nice to have a map function for FindWrapper.

This will allow to write tests like this:

expect(wrapper.find('MyComponent').map(n => n.text())).toEqual([
  'one',
  'two',
  'three',
]);

.text() behaviour for input elements

I just wanted to ask, if the behavior of text() not working with input elements is intended?

For example if we have a component with this output:

"preact-render-spy (1 nodes)
-------
<td class="column-text-centered input_price">
  <div>
    <input
      type="text"
      value="5,00"
      onBlur={[Function debounced]}
      class="defaultInputStyle defaultUnderline customPriceInput"
     />
    <span>EUR</span>
  </div>
</td>
"

a .text() call on .input_price will only return the span elements text but I would "expect" that it would also return the value of input? Technically it is not a plain Text Dom element but I would like to ask if it would make sense to include input (maybe also other input elements) to the .text() functionality?

Receiving function prop as undefined

Hi guys Im having a weird problem where my component receive a function parameter as undefined if:
It is not declared in the same scope
OR
I don't declare and pass other variables on the same scope

describe('myTest', () => {
  let myComponent
  let myMock

  beforeEach(() => {
    myMock = jest.fn()
    myComponent = shallow(
      <MyComponent action={myMock} />
    )
  })
})

FAIL this.props.action is undefined

describe('myTest', () => {
  let myComponent

  beforeEach(() => {
    let myMock = jest.fn() // declared on the same block
    myComponent = shallow(
      <MyComponent action={myMock} />
    )
  })
})

WORKS this.props.action is my mock

describe('myTest', () => {
  let myComponent
  let myMock

  beforeEach(() => {
    myMock = jest.fn()
	let anything = 'anything' // anything else declared and passed in the same block
    myComponent = shallow(
      <MyComponent action={myMock} anything={anything}/>
    )
  })
})

WORKS this.props.action is my mock

my deps:

{
"jest": "^23.6.0",
"preact-cli": "^2.2.1",
"preact-render-spy": "^1.3.0",
"preact": "^8.4.2"
}

any ideas?
thanks

`.output()` should "recurse" on any component nodes

Until it meets a depth that wasn't rendered. I.E.

const Second = () => <div>second</div>;
const First = () => <Second>first</Second>;
expect(deep(<First />).output()).toEqual(<div>second</div>);
expect(shallow(<First />).output()).toEqual(<Second>first</Second>);

Simplify some tests

I feel like these tests are unnecessarily brittle and hard to follow because of the dynamic class names. Instead, why not simplify by using static class names (or none at all) and change the text, something more like this:

(Note: untested)

it('componentWillReceiveProps', () => {
  class Child extends Component {
    constructor(props) {
      super(props);
      this.state = {value: props.value};
    }

    componentWillReceiveProps(newProps) {
      this.setState({value: `_${newProps.value}_`});
    }

    render(props, {value}) {
      return (
        <div>{value}</div>
      );
    }
  }

  class Parent extends Component {
    constructor(props) {
      super(props);
      this.state = {value: 'default'};
    }

    render(props, {value}) {
      return (
        <Child
          onClick={() => this.setState({value: 'clicked'})}
          value={value}
        />
      );
    }
  }

  const context = renderSpy(<Parent />);
  const getChild = () => context.find('Child').at(0);
  expect(getChild().text()).toBe('default');
  getChild().simulate('click');
  expect(getChild().text()).toBe('_clicked_');
});

TypeError: this.contextRender is not a function when using shallow

When i run test, it fails with the TypeError: this.contextRender is not a function when using shallow error.

This is my test:

import { h } from 'preact'
import { shallow } from 'preact-render-spy'
import { App } from '../../src/app'

describe('App', () => {
  test('renders', () => {
    const context = shallow(<App />)
    expect(context.find('div').contains(<a>link</a>)).toBeTruthy()
  })
})

This is error i get:

 FAIL  test/src/app.test.js
  App
    ✕ renders (4ms)

  ● App › renders

    TypeError: this.contextRender is not a function

       5 | describe('App', () => {
       6 |   test('renders', () => {
    >  7 |     const context = shallow(<App />)
         |                     ^
       8 |     expect(context.find('div').contains(<a>link</a>)).toBeTruthy()
       9 |   })
      10 | })

      at RenderContext.render (node_modules/preact-render-spy/src/preact-render-spy.js:462:10)
      at deep (node_modules/preact-render-spy/src/preact-render-spy.js:472:76)
      at shallow (node_modules/preact-render-spy/src/preact-render-spy.js:473:25)
      at Object.<anonymous> (test/src/app.test.js:7:21)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   0 total
Time:        2.196s
Ran all test suites.

Shallow or Deep can't compile the app when async module are loaded

Hi there,

I have an issue with tests when there is a module that are loaded with the !async keyword from the preact-cli project.

Let's say I have my app.js that have: import myModule from 'async!./myModule/myModule.js';

If I test an independent module (let's say myOtherModule.js and not app.js nor myModule.js, and myOtherModule has no information about the async loaded module at all), the test will still fail with: Cannot find module 'async!./myModule/myModule.js' from 'app.js'

Do you know how I can work around this error? (For now, I'm just removing the !async but that is not ideal :))

Cheers!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.