How I Fixed: uncaught at check call: argument [object Promise] is not a function

Earlier this month I started dabbling with Redux Sagas as an alternative to Redux Thunks.

At the time I was highly skeptical – largely around whether re-writing a significant portion of my JavaScript was good use of my time, given that I had no prior experience with generators, and that conceptually sagas sounded pretty hard.

But I kept hitting issues with Thunks. They just seemed so cumbersome, and error prone. I found writing tests for them to be painful, and adding in the Redux API Middleware made that even more complicated.

Ultimately, switching to Redux Saga has been one of the highlights of my current project. I love it. Every problem I have had so far has been made easier through the use of sagas.

But today I hit on a problem I haven’t seen before:

uncaught at check call: argument [object Promise] is not a function

This is a generic version of the code I am using:

export function *doRequestProfile(action) {

  try {

    yield put({
      type: types.REQUEST__STARTED,
      payload: {
        requestFrom: 'my-saga'
      }
    });

    const profile = yield call(api.fetchProfile(action.payload.accountId));

    yield put({
       type: types.PROFILE__SUCCESSFULLY_RECEIVED,
       payload: {
         profile
       }
    });

  } catch (e) {

    yield put({
      type: types.PROFILE__FAILED_RECEIVING,
      payload: {
        message: e.message,
        statusCode: e.statusCode
      }
    });

  } finally {

    yield put({
      type: types.REQUEST__FINISHED,
      payload: {
        requestFrom: 'my-saga'
      }
    });

  }
}

export function *watchRequestProfile() {
  yield* takeLatest(types.PROFILE__REQUESTED, doRequestProfile);
}

I have highlighted the problematic line.

The issue here is that the error in the browser is fairly cryptic. It took me digging into the source code to figure this one out.

But actually the issue is really simple to fix.

The highlighted line above should be :

const profile = yield call(api.fetchProfile, action.payload.accountId);

I was calling my function myself, and then passing the promise on to the Saga… whoopsie daisy.

How I Fixed: unresolved variable or type await

Ok, super easy one here, but as a newbie to async / await this did catch me out.

Let’s pretend we have a function:

export function login(username, password) {
  const requestConfig = {
    method: 'POST',
    mode: 'cors',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ username, password })
  };

  const loginResponse = await fetch('https://your.api/login', requestConfig);

This will present an error in WebStorm, and Googling came up only with a bug report from 2015.

In my case, WebStorm would give two different error messages:

webstorm-async-await-expecting-newline-or-semicolon

orwebstorm-async-await-unresolved-variable-or-type-await

Ready to kick yourself?

export async function login(username, password) {
  const requestConfig = {
    method: 'POST',
    mode: 'cors',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ username, password })
  };

  const loginResponse = await fetch('https://your.api/login', requestConfig);

This I tell you brother, you can’t have one without the other 🙂

 

Using async / await with React

I’m currently toying with thunks vs Sagas.

The idea of re-writing a significant portion of my app’s API connectivity (from thunk, to saga) is not entirely thrilling. However, sagas do appear to be the better solution given what I currently know, and would choose them if starting again from scratch.

The gist of my problem is that thunks have added in a layer of complexity – but they work.

For any API call that should be authenticated, I need to catch the call using a middleware and then add the necessary token, and so on.

Combine this with Redux Form, however, and I am left with a bit of a head-scratcher. This middleware is generic. If certain calls fail, I need to map the response (containing error messages) to an object that Redux Form understands, then dispatch the stopSubmit action.

Anyway, enough about my problem.

Before making the switch I found a potential solution that involves using async / await. Being a sucker for new and shiny, I wanted to get it into my project.

Simply trying to use async / await resulted in an error for me:

Uncaught ReferenceError: regeneratorRuntime is not defined

Boo.

To fix this, I needed to import the babel-polyfill. However, a thing I found out is that you can import this dependency once in one of your top level components, rather than per file.

For example, in my project I have an App component which contains a container which all other components in the app render into.

I added the single line:

import "babel-polyfill";

as the first line in the file, and nowasync / await works just fine.

These other two files may help in setting up:

  "devDependencies": {
    "babel-cli": "6.14.0",
    "babel-core": "6.14.0",
    "babel-es6-polyfill": "1.1.0",
    "babel-jest": "16.0.0",
    "babel-loader": "6.2.5",
    "babel-plugin-react-display-name": "2.0.0",
    "babel-plugin-transform-async-to-generator": "6.8.0",
    "babel-plugin-transform-react-constant-elements": "6.9.1",
    "babel-plugin-transform-react-remove-prop-types": "0.2.9",
    "babel-preset-es2015": "6.16.0",
    "babel-preset-latest": "6.14.0",
    "babel-preset-react": "6.11.1",
    "babel-preset-react-hmre": "1.1.1",
    "babel-preset-stage-1": "6.13.0",
    "babel-register": "6.14.0",

 

{
  "presets": [
    "latest",
    "react",
    "stage-1"
  ]
}

 

7 things I learned adding Jest to my existing JavaScript boilerplate

Here are 7 things that I encountered when trying to add Facebook’s Jest to my existing React JS project.

This project was initially based on Corey House’s boilerplate – React Slingshot. There was nothing wrong with the test setup the boilerplate provided. I just wanted an excuse to try Jest.

1. Jest doesn’t play well with importing stylesheets

Here was the code I was using:

import React from 'react';
import '../styles/about-page.css';

const AboutPage = () => {
  return (

And the associated Jest output:

 FAIL  __tests__/components/AboutPage.react-test.js
  ● Test suite failed to run

    /home/chris/Development/react-registration-demo/src/styles/about-page.css:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){.alt-header {
                                                                                             ^
    SyntaxError: Unexpected token .
      
      at transformAndBuildScript (node_modules/jest-runtime/build/transform.js:284:10)
      at Object.<anonymous> (src/components/AboutPage.react.js:2:27)
      at Object.<anonymous> (__tests__/components/AboutPage.react-test.js:2:44)

To be fair, the output looks a bit nicer in the terminal.

Removing the stylesheet line:

import React from 'react';
// import '../styles/about-page.css';

const AboutPage = () => {
  return (

Now commented out, all passing:

 PASS  __tests__/components/AboutPage.react-test.js
  ✓ Can see header (10ms)

Snapshot Summary
 › 1 snapshot written in 1 test suite.

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 added, 1 total
Time:        1.077s
Ran all test suites.

2. Tests live in the __tests__ directory

The tutorial link doesn’t make it immediately obvious that the location and naming of your test files has an assumptive default config:

(/__tests__/.*|\\.(test|spec))\\.(js|jsx)$)

The boiler plate I am using has the test files in the same directory as the component itself. I followed the boiler plate pattern first, and it didn’t work.

I was confused why my tests wouldn’t run:

> jest

No tests found
  50 files checked.
  testPathDirs: /home/chris/Development/react-registration-demo - 50 matches
  testRegex: (/__tests__/.*|\.(test|spec))\.jsx?$ - 0 matches
  testPathIgnorePatterns: /node_modules/ - 50 matches

Tests need to go in a __tests__ directory, unless you are a regex ninja.

If you do want to overwrite it then you can update your package.json with extra config:

  "jest": {
    "testRegex": "your regex here dot star hash"
  }

I went with their defaults.

Now also note, you wouldn’t have this problem if you had read the landing page and the Docs link. I made the mistake of going direct to the Docs link via Google.

3. You may need to rename things

In React so far I have seen files named like either thing.jsx,  or thing.js. I’ve never seen anyone use thing.react.js.

However, the Jest docs use this convention.

So, having made two mistakes already, I made the switch myself.

Tangible benefit: None(?)

4. Jest ran existing tests just fine

This one threw me.

I had an existing file left over from my purge of the boilerplate demo site. I manually deleted the files as I worked my way through and replaced the boilerplate parts with my own.

One such file that was left was a utility class called mathHelper.spec.js 

Jest ran this just fine:

> jest

 PASS  __tests__/components/AboutPage.react-test.js
 PASS  src/utils/mathHelper.spec.js

Test Suites: 2 passed, 2 total
Tests:       13 passed, 13 total
Snapshots:   1 passed, 1 total
Time:        1.157s

5. Snapshot Testing is a really smart idea

You are kidding me.

Another concept to learn?

When will this learning ever end? Never. Get reading.

Actually though this is fairly simple to understand, and incredibly beneficial.

An example illustrates it best.

Let’s say I have a very basic component:

import React from 'react';

const AboutPage = () => {
  return (
    <div>
      <h2 className="alt-header">About</h2>
      <p>Who wouldn't want to know more?</p>
    </div>
  );
};

export default AboutPage;

And a really simple test:

import React from 'react';
import AboutPage from '../../src/components/AboutPage.react';
import renderer from 'react-test-renderer';

test('Can see header', () => {
  const component = renderer.create(
    <AboutPage />
  );
  let tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

The first time I run the tests with npm test then Jest will create a snapshot of how this page is expected to look:

exports[`test Can see header 1`] = `
<div>
  <h2
    className="alt-header">
    About
  </h2>
  <p>
    Who wouldn\'t want to know more?
  </p>
</div>
`;

And the test output:

> jest

 PASS  __tests__/components/AboutPage.react-test.js
  ✓ Can see header (9ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 passed, 1 total
Time:        0.827s, estimated 1s
Ran all test suites.

Then, should you make a change to your component in some way which causes the output to change:

import React from 'react';

const AboutPage = () => {
  return (
    <div>
      <h2 className="alt-header">About</h2>
      <p>Changed</p>
    </div>
  );
};

export default AboutPage;

Then re-run:

> jest

 FAIL  __tests__/components/AboutPage.react-test.js
  ● Can see header

    expect(value).toMatchSnapshot()
    
    Received value does not match stored snapshot 1.
    
    - Snapshot
    + Received
    
      <div>
        <h2
          className="alt-header">
          About
        </h2>
        <p>
    -     Who wouldn't want to know more?
    +     Changed
        </p>
      </div>
      
      at Object.<anonymous> (__tests__/components/AboutPage.react-test.js:10:16)
      at process._tickCallback (internal/process/next_tick.js:103:7)

  ✕ Can see header (11ms)

Snapshot Summary
 › 1 snapshot test failed in 1 test suite. Inspect your code changes or run with `npm test -- -u` to update them.

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   1 failed, 1 total
Time:        1.078s
Ran all test suites.
npm ERR! Test failed.  See above for more details.

Again, it looks nicer in the console.

6. You probably want an alias for updating snapshots

Here’s what I use, feel free to differ:

  "scripts": {
    "test": "jest",
    "testu": "npm run test -- -u",
  },

Every time you make a change to your component you likely need to re-update your snapshots. Having an alias is better than the alternative of typing out morse code.

7. There are concerns I only found out about after reading the Snapshot announcement blog post

Dropped in at the bottom of the blog post announcing Snapshot testing is some notes about forthcoming improvements.

This one caught my eye the most:

  • Mocking: The mocking system, especially around manual mocks, is not working well and is confusing. We hope to make it more strict and easier to understand.

Thankfully I did this migration on a new git branch 🙂

An Example of JavaScript Double Negative

javascript double negative
Image credit: https://flic.kr/p/2oNKyk

I remember the first time I saw JavaScript double negative syntax. It confused the heck out of me – so much so, I thought it was a mistake.

Over time, I have seen other developers equally confused. It must get asked in Slack at least once a quarter, if not more.

In case you aren’t sure, let’s quickly cover exactly what we are talking about here:

{ isAuthenticated: !!localStorage.getItem('idToken') }

The point of interest here being the double negative / double bang / !! / double exclamation marks. I put all the alternatives I can think of in, in the hope that it helps others searching for similar.

It’s also worth pointing out that double exclamation marks are not a single operator. I guess that makes it all the more difficult to Google, and understand.

Just Tell Me What It Is

For the impatient, using Javascript double negative / not not will coerce your value to a boolean, and ensure that the output is of type boolean.

To translate that from technobabble:

The first ! will convert a value that isn’t either true or false into a value that is  true or false, and then invert it.

The second ! will invert it again.

Confusing?

An example illustrates a potential use case, which hopefully will make it slightly easier to understand.

Just Show Me An Example

Here is a real world example from an authentication reducer I am currently working on in a React / Redux project.

Let’s look at the code as it stands before adding in the double negatives:

import {
  LOGIN__FAILED,
  LOGIN__SUCCESS,
  LOGOUT__SUCCESS
} from '../constants/ActionTypes';

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: localStorage.getItem('idToken')
}, action) {

  switch (action.type) {

    case LOGIN__SUCCESS:
      return Object.assign({}, state, {
        isAuthenticated: true,
        userId: action.userId,
      });

    case LOGIN__FAILED:
      return Object.assign({}, state, {
        isAuthenticated: false,
        errorMessage: action.errorMsg
      });

    case LOGOUT__SUCCESS:
      return Object.assign({}, state, {
        isAuthenticated: false
      });

    default:
      return state;
  }
}

Most of this is not that interesting in the context of this particular example.

I have highlighted line 9 where localStorage is used to retrieve the user’s idToken, should it exist.

There is a bug in this code.

The default case of the switch statement means that when a user first loads the page / before they have ever logged in, the default state would return:

{
  sendingRequest: false,
  isAuthenticated: null
}

Instead, I want it to be:

{
  sendingRequest: false,
  isAuthenticated: false
}

I could use a ternary operator to fix this:

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: localStorage.getItem('idToken') ? true : false
}, action) {

And this would work, but WebStorm moans at me that I can do better:

webstorm-can-be-simplified
WebStorm telling me I suck

I make the change:

export default function auth(state = {
  sendingRequest: false,
  isAuthenticated: !!localStorage.getItem('idToken')
}, action) {

Why does this work?

Because by localStorage.getItem(‘idToken’) is going to either return me a string (containing my locally saved idToken), or as we have already seen, a null.

If we check whether a string is not (!) something, we would get false – because a string is definitely something.

It therefore stands that if a string is not not something, then it must be true.

Likewise, if we check if a null is not (!) something, we would get true – because a null is definitely nothing.

It equally therefore must stand that if a null  is not not nothing, then it must be false.

Still confused? Don’t feel down about it. It took me ages to grasp this, and it’s so unusual that it really won’t come up that frequently.

I would even go as far as to say consider sticking with the ternary operator approach. It is simply easier for most developers to immediately understand, even if WebStorm moans about it.