Skip to content
View in the app

A better way to browse. Learn more.

Web Designer Forum

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

General JavaScript

Featured Replies

I've watch the never write another HOC before, render prop callbacks are a really cool and powerful pattern. HOC can be a bit confusing how props passed in can be obfuscated from consumer, whereas render props are explicit. Bit like context, although when building a framework context is really, really useful :)

I've been waiting ages for a modular Date library as good as Moment.js is, it's huge!

  • Replies 422
  • Views 68.4k
  • Created
  • Last Reply

Top Posters In This Topic

Most Popular Posts

  • As soon as I saw the JS videos with that Mattias guy, I knew who he was straight away. He posts some really useful answers on Quora. I'd advise signing up if you haven't already. I've wasted hours re

  • Console.table, ladies and gentleman http://jsfiddle.net/juu5fx82/.   You need to use the JS console obviously, and hit 'run'. I never knew this existed.

  • jQuery's modular, you can build a custom version via Grunt, its pretty simple.   Before v3.0, which now uses requestAnimationFrame and Promises/A+, I'd use a build without Effects and Ajax with Velo

  • Author

I heard about date-fns on a Wes Bos podcast a week or so ago: https://syntax.fm/show/009/dang-that-s-handy-javascript-utility-libraries

 

Had a need for it a day or two later and tried it out. Very cool indeed. I needed to parse a partial iso8601 date format into a js date, then format it as a nice string. There's a parse function that does just that, and a format function that works just as you'd expect. Instead of using moment I just used two functions that were just a few k each. Much smaller than momentjs, and far easier than doing it natively in js.

 

Yeah, they seem to have a crazy amount of tests as well, which I guess you really need on a date library.

 

Each build CI checks more than 650 000 examples in about 400 time zones.

 

*faints*

 

Yeah, they seem to have a crazy amount of tests as well, which I guess you really need on a date library.

 

 

*faints*

I can't remember the name of the library, but there's one been worked on at the moment by *I think* Lee Byron over at Facebook that generates loads of edge case data for tests and loops over them. I would assume they are doing something like this rather than having such a high number of static tests.

 

I first heard about this at a talk I went to given by Martin Fowler a few months ago, it certainly sounded interesting.

  • 3 weeks later...
  • Author

I've wondered for a while why most modern Node tutorials use the commonJS syntax for modules. Apparently, Node doesn't support ES modules yet, without Webpack (which is probably why I've never noticed), anyway, it's super annoying. Luckily the guy behind Lodash has created this https://github.com/standard-things/esm.

I've wondered for a while why most modern Node tutorials use the commonJS syntax for modules. Apparently, Node doesn't support ES modules yet, without Webpack (which is probably why I've never noticed), anyway, it's super annoying. Luckily the guy behind Lodash has created this https://github.com/standard-things/esm.

Shouldn't really use Webpack on the server as it's intended for the client, you can transpile just using Babel.

 

Babel can to transpile your ES6+ code and dump it all in a lib folder where you server will read from, although Node has implemented the vast majority of ES features now so I prefer to just use commonJS imports.

 

To be honest I don't find using them to be much of a pain.

 

Not a Node project, but an example of using Babel in isolation to transpile some code and dump it in a lib folder

https://github.com/NebulaUI/nebula-react/blob/master/package.json#L11

Edited by rbrtsmith

  • Author

Shouldn't really use Webpack on the server as it's intended for the client, you can transpile just using Babel.

 

Babel can to transpile your ES6+ code and dump it all in a lib folder where you server will read from, although Node has implemented the vast majority of ES features now so I prefer to just use commonJS imports.

 

To be honest I don't find using them to be much of a pain.

 

Not a Node project, but an example of using Babel in isolation to transpile some code and dump it in a lib folder

https://github.com/NebulaUI/nebula-react/blob/master/package.json#L11

 

Yeah I use Webpack and Babel a lot client side, but I'm building something just in Node at the moment, so it was confusing initially to not be able to use the same import syntax. I love the ESM syntax, it ditches messy module.exports, temporary variables, and it's super easy to grab individual methods without having to assign them to anything. All in all it's a lot cleaner, and @std/esm doesn't touch Babel, so you can use the same syntax for modules everywhere. This is an inevitable upgrade from April 2018 anyway if people want to use Node 10.0.

I'm not convinced another type of module is the best approach though, it's something that will likely end up legacy and when new people come to onboard it will be a point of confusion.

I've honestly never had a problem with CommonJS syntax, ES6 imports being a minor improvement. Generally with Node I don't use Babel as the compile step is some extra complexity with not enough gain to warrant it.

The Node team are working on implementing ES6 import/export but it's more tricky than initially thought but I believe they're getting quite close now so it shouldn't be a problem for long :)

  • Author

Std/esm is standards compliant with what the Node team are working on, it's not a new module system or anything. April 2018 is supposed to be when Node 10.0 lands with the feature flag for ESM removed, at that stage you should be able to transition over. I expect there to be gains with static analysis and performance over time bringing this into Node, from what I've read, require is synchronous, and doesn't allow for much optimisation.

At the end of the day, though, I just like the syntactic sugar ¯\_(ツ)_/¯

  • 2 months later...
  • Author

https://github.com/tc39/proposal-pipeline-operator

Excited to see this at stage 1, it makes for some really clean functional patterns. I think it's highly likely it will be included in the language since other functional languages like Elixir already have and make extensive use of it.

 

  • Author

@citypaul @rbrtsmith

I'm struggling a bit to get my head around a couple TDD concepts, so I thought I'd ask both of you. I've found this to be the hardest subject to learn about so far, because there's barely anything out there with good real-world examples, and every Medium and blog post gets you to assert stuff like an add function, which is the easiest example you could give. It seems like every library out there has test coverage, so it must be coming more naturally to other developers than me.

I've been looking at some smaller libraries, utilities and some organisations on Github to see how people are writing tests. Some of them seem quite complex in terms of the code used to get a passing test. My question is, if you follow the red - green - refactor principle, writing your test first, how do you know the code for your test actually works and can be relied upon? Something like a test for an event emitter can have a lot inside the assertion to make it pass, but can you guarantee at that point your test would work, even before you've created working code and an API for it.

My second question is how many test cases you need to come up with, and how you know what they should be. There doesn't seem to be a rule here, but clearly there are things you should be testing, it's just hard to know how far you go with it. Is it a case of some tests are better than none, or should you be trying to think of as many edge cases as possible?

Lastly, some of the things I have wanted to write tests for, I can't think of a way to do it. Most of these are browser API's. Let's say you wrote a function that pushes data into localstorage, and another that gets the data out of localstorage. How would you would you test that those operations are happening. Similarly, if you have a function that returns data from a third-party API, what exactly are you testing? Are you asserting the headers and response codes, or that your data object isn't empty?

  • Author

Brilliant, thanks, there's some really helpful advice there. For me, it's never not wanting to write tests, because I completely understand the reasons why you would, but it's often I don't know how past basic assertions. It's strange that a lot of developers have grasped this so easily, when there's not really much info out there that's particularly useful. I'm starting to think a lot of developers have learnt this on the job, somewhere that uses TDD as part of their process, and have had other developers to call on for help.

I'll come up with some examples. Local storage is a good one because I can't work out how you would do it. If you checked to see the value set within the browser, that would never be the same for another developer, they may have an empty local storage console for example, and the tests that pass for you would fail for them. I'll come up with an ajax one as well.

It might help if I have a dig around for some tests that I have found to be quite complex, it's possible they are not recommended anyway.

 

  • Author
1 hour ago, citypaul said:

I've been threatening to write some tutorials for it or do some videos for the process for ages. Problem is time, and also that I'd want to do a really good job, so would have to focus and plan it properly.

You could be the next Wes Bos.

There's not much out there, a couple courses and blog posts. The closet I've seen is http://www.letscodejavascript.com.

I think Paul has answered the questions really well here.  I've spent the last week or so teaching some of the developers in Sky how to write better tests (Most of my knowledge is based on what Paul has taught me, and through me writing a lot of tests over the past two years.)

For services or API's like localStorage you can mock them.  If you are using Jest - I recommend that you do. that ships with JSDom which automatically boots up before your tests execute so you can make assertions against that.

So here's an example I worked on today.  This React component takes a latchPoint prop which is a number - essentially the Y coordinate of the latchpoint where we want BasketSummary to become sticky.  I've choosen this as an example it's one of the more difficult behaviours to test in React - without testing implementation details which should always be avoided. 
 

import React, { Component } from 'react';
import BasketSummary from './BasketSummary';

class BasketSummaryWrapper extends Component {
  state = {
    isBasketAnchored: false
  }

  timeout

  componentDidMount() {
    window.addEventListener('scroll', this.onScroll);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.onScroll);
    this.timeout = undefined;
  }

  onScroll = () => {
    this.timeout = window.requestAnimationFrame(() => {
      const scrollPosition = window.pageYOffset;
      this.setState({ isBasketAnchored: scrollPosition > this.props.latchPoint });
    });
  }

  render() {
    return (
      <BasketSummary
        isAnchored={this.state.isBasketAnchored}
        basketSummary={this.props.basketSummary}
        termAndConditions={this.props.basketLegal}
      />
    );
  }
}

export default BasketSummaryWrapper;

So the behaviours that we'd wanna test for this component are that if we are scrolled past the latch point the BasketSummary should be anchored.  If we are scrolled before the latch point then it should not.
We also want to assert that the other props are passed through but seen as there's no logic around that, merely declarations then a snapshot will be fine to ensure that doesn't regress.

And here are the tests for this component
 

import React from 'react';
import { shallow, mount } from 'enzyme';
import BasketSummaryWrapper from '../BasketSummaryWrapper';
import BasketSummary from '../BasketSummary';
import basketSummary from '../../../mocks/transformed/basketSummary';

const defaultProps = {
  basketSummary,
  termAndConditions: '<p>Need help? Call us on 08081 601 315.</p>'
};

const render = props => mount(<BasketSummaryWrapper {...defaultProps} {...props} />);

global.requestAnimationFrame = (cb) => {
  setTimeout(cb, 0);
};

describe('BasketSummaryWrapper', () => {
  test('renders correctly', () => {
    const app = shallow(<BasketSummaryWrapper {...defaultProps} />);
    expect(app).toMatchSnapshot();
  });

  test('renders BasketSummary un-anchored if not scrolled past latch point', () => {
    jest.useFakeTimers();
    Object.defineProperty(window, 'pageYOffset', {
      writable: true,
      value: 5
    });
    const app = render({ latchPoint: 10 });
    const event = new window.Event('scroll');
    window.dispatchEvent(event);
    jest.runAllTimers();

    expect(app.find(BasketSummary).prop('isAnchored')).toBe(false);
  });

  test('renders BasketSummary anchored if scrolled past latch point', () => {
    jest.useFakeTimers();
    Object.defineProperty(window, 'pageYOffset', {
      writable: true,
      value: 15
    });
    const app = render({ latchPoint: 10 });
    const event = new window.Event('scroll');
    window.dispatchEvent(event);
    jest.runAllTimers();
    app.update();
    expect(app.find(BasketSummary).prop('isAnchored')).toBe(true);
  });

  test('component cleans up on unMount', () => {
    const removeEventListener = jest.spyOn(window, 'removeEventListener');
    const app = render();
    app.unmount();
    expect(removeEventListener).toBeCalled();
  });
});

So early on in the test I mock out requestAnimationFrame with an immediate timeout, this is because requestAnimationFrame does not exist in Node and my component makes use of it to improve the scroll performance.  Seen as it's been mocked out with a timeout I can get Jest to run all timers as you can see me doing in my tests.

You can also see that I mock the return value of window.pageYOffset as JSDom just returns "0" for all of these getters.
I also use a spy to ensure that removeEventListener is called when the app unmounts.

I am happy to share some examples of more simple React testing but I thought I'd share the kind of behaviours that people often try to test by asserting against component internals and we should not do that.  A component should be a black box with input and outputs - our tests don't need to care how something works.  They care THAT it works.

Edited by rbrtsmith

  • Author
Quote

So early on in the test I mock out requestAnimationFrame with an immediate timeout, this is because requestAnimationFrame does not exist in Node and my component makes use of it to improve the scroll performance.  Seen as it's been mocked out with a timeout I can get Jest to run all timers as you can see me doing in my tests.

Is this purely to stop requestAnimationFrame from erroring inside Node? I'm not sure why you would use setTimeout in these tests.

If we take this test...

test('renders BasketSummary un-anchored if not scrolled past latch point', () => {
  jest.useFakeTimers();
  Object.defineProperty(window, 'pageYOffset', {
    writable: true,
    value: 5
  });
  const app = render({ latchPoint: 10 });
  const event = new window.Event('scroll');
  window.dispatchEvent(event);
  jest.runAllTimers();

  expect(app.find(BasketSummary).prop('isAnchored')).toBe(false);
});

Would your starting point, or failing 'red' test be...

test('renders BasketSummary un-anchored if not scrolled past latch point', () => {
});

...and then you start writing your React code? At what point do you start filling that test above in?

SetTimeout has to be mocked as when the test runs it will try to call it.  We all know what happens when we try to call a function that doesn't exist.  Because rAF takes a callback we have to mock it with a similar function that takes a callback, we could have mocked it with a function that immediately calls the callback I guess.  But because rAF delays execution it felt right to simulate similar behaviour with setTimeout, which we can then control in the test.

90-95% of the time I write test first, but in this instance it can be really hard because JSDom is not a very well documented API and you have to fiddle around with it to get things to work, which isn't ideal but now I'm getting more familiar with it I'm able to write test first more frequently in these edge cases.

I really like the test first approach and always encourage people to follow it, but sometimes when working with really unfamiliar test frameworks / APIs it can be a big ask.  Can always create a spike for something to figure out how you might implement it then start again test first once you have better domain knowledge.

So in this case we'd have the domain knowledge that we'd want rAF to be mocked with a timeout so we can write that into our test.  We know what we want our API to look like: Respond to scroll handlers and output isAnchored prop to BasketSummary, we also know that our API receives the prop latchPoint so we can build our test around that behaviour...

Given "this" latchPoint prop, when the user scrolls to a yOffset that is greater than the latchPoint we expect BasketSummary to receive a truthy isAnchored prop.

and

Given "this" latchPoint prop, when the user scrolls to a yOffset that is less than the latchPoint we expect BasketSummary to receive a falsy isAnchored prop.

You can start your first test to just call the "render()" function I created at the start of the test suite.  That will initially fail until you create a basic React component, and then implement the rest of  the initial test and then build that behaviour into the component until the test passes.  Write the opposite test so both cases are covered and you can look at refactoring your implementation to something nicer or more concise
Once they are both passing you'd write the test to clean up when the component unmounts, then implement that behaviour.
Lastly you add in your snapshot to make sure the other props being passed through don't regress.  It's a bit much to write further tests for those as there's no real logic, just passing the props through the component to it's children.

@Jack i'm not sure if you have taken the Redux course on Egghead by Dan Abramhov?  If not he demonstrates how redux reducers work in a test-first manner so that might be a decent real-world example of TDD that isn't really complex, as a reducer is a pure function - the easiest types of functions to test.

  • Author

Thanks for the replies, this is making more sense now. I think you answered my initial concern of how to write tests for something you don't know all of the implementation details for.

6 minutes ago, rbrtsmith said:

@Jack i'm not sure if you have taken the Redux course on Egghead by Dan Abramhov?  If not he demonstrates how redux reducers work in a test-first manner so that might be a decent real-world example of TDD that isn't really complex, as a reducer is a pure function - the easiest types of functions to test.

I haven't seen that course, but I'll take a look.

  • Author
1 hour ago, citypaul said:

I wouldn't recommend learning TDD along with Redux at the same time. Start simple. I still haven't quite figured out my own testing strategy when it comes to Redux yet. Planning to work on my own app in the next week and I'll get a better feel for it there.

I'd start with some more simple stuff - start by testing fairly standard React components that aren't doing anything too complicated, or perhaps even some pure JS that doesn't even require react. I'd move on to learning how to test Redux a little further down the line, as trying to learn TDD while also learning how to test Redux might be a bit much upfront.

TDD is much more about the workflow than anything else, so personally I'd recommend getting used to that workflowon a more simple and straightforward use case, and then build yourself up towards more complicated stuff like Redux.

 

I think he means to see the workflow Dan is using, but yeah I wouldn't attempt to learn both at the same time.

Testing pure functions has never been an issue, it's normally straight forward to write unit tests for them because it's just data in, data out. The problem has always been when you go outside of pure functions, into things like the DOM, server requests, database testing etc. Most articles use an add function as an example of 'getting started with TDD', when you start to consider how you take this idea and bring it into an application, things start to get incredibly confusing.

I suggested the Redux course just for his examples for testing reducers, not the entire redux flow etc :)

For databases you would typically mock the response - for front-end tests.  On the backend you will also do this for unit tests, but perhaps on integration tests you'd use the DB.

For End to end tests you don't want to mock anything out as they are typically testing user journeys.

Edited by rbrtsmith

  • Author
On 1/27/2018 at 5:24 PM, citypaul said:

Btw, I've since decided I'm scrapping that REST api in favour of a GraphQL one. So I'm finally, finally gonna have a play with it after all @Jack

GraphQL is an awesome concept, I think you'll prefer it over REST. I'm working on a todo REST API at the moment actually, for practice, and have been testing my Express endpoints using Supertest (http://willi.am/blog/2014/07/28/test-your-api-with-supertest/), but I'll likely refactor to Jest if Jest can do that sort of thing. Having multiple testing libraries seems a bit counter productive to me.

The code you wrote above makes a lot of sense, especially finding a mock for localstorage. If you didn't have that package, would it be fair to create a similar data structure to localstorage and test against that? It's basically an object, so could you just check that you're passing values into an object, and then removing them? It's not 100% accurate but it's close, and that package must be doing something similar.

On the subject of mocks, since they are mentioned a lot on here. What are your thoughts about the whole 'mocking is fragile' or 'don't use mocks' debate that you see in TDD? It seems like you need to if you're asserting an API or Database. Eric Elliot goes on about this a lot, but I'm not sure I value his opinion on some stuff.

  • Author

I was going to create a repo on Github with some examples in to test, but I've been hungover for like 2 days, because I'm getting old now. I haven't been too motivated because of it.

  • 4 months later...
  • Jo 90 locked this topic
Guest
This topic is now closed to further replies.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.