Git Product home page Git Product logo

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!

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.

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.

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!

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"
  }

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_');
});

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 ?

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.

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

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()

`.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>);

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',
]);

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

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?

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.

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?

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!

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.

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.

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

.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?

.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.

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

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?

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?

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!

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?

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)

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.

.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?

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.