node-supertest-fetch icon indicating copy to clipboard operation
node-supertest-fetch copied to clipboard

expectBody not verbose enough

Open mgcrea opened this issue 6 years ago • 6 comments

When reading the docs, we could expect:

  it('should return a response', async () => {
    await fetch('/hello')
      .expect(200)
      .expect('content-type', /^application\/json/)
      .expect({greeting: 'Hello!'});
  });

to have the same behavior than:

  it('should return a response', async () => {
    const response = await fetch('/hello')
      .expect(200)
      .expect('content-type', /^application\/json/);
    expect(await response.json()).toEqual({greeting: 'Hello!'});
  });

However these two examples give very different outputs:

    AssertionError [ERR_ASSERTION]: Request "GET /me" should have expected JSON body

vs.

    expect(received).toEqual(expected)

    Expected value to equal:
      {"greeting": "Hello!"}
    Received:
      {"foo": "bar"}

    Difference:

    - Expected
    + Received

      Object {
    -   "greeting": "Hello!",
    +   "foo": "bar",
      }

Not sure if this is easily doable but having the actual expect error thrown in the first case would be great as it's quite impractical for now.

Thanks for the great lib!


EDIT I realized that this was due to the fact that I'm using jest version of expect. Since the package is quite small, I think it would be great to rely on it to test assertions. As you'll get nice diffed output.

mgcrea avatar Oct 12 '18 12:10 mgcrea

I just tried cloning a fresh copy

$ git clone [email protected]:jwalton/node-supertest-fetch.git
$ cd node-supertest-fetch
$ npm install

And then I added this to test/test.ts:

    it('should generate a nice diff if body is incorrect', async function() {
        await fetch(this.server, '/hello')
                .expectStatus(200)
                .expectHeader('content-type', 'application/json')
                .expectBody({greeting: "Hello2!"});
    });

And when I npm test, I get back:

  1) supertest-fetch
       should generate a nice diff if body is incorrect:

      AssertionError [ERR_ASSERTION]: Request "GET /hello" should have expected JSON body
      + expected - actual

       {
      -  "greeting": "Hello!"
      +  "greeting": "Hello2!"
       }

supertest-fetch is just using straight up assert, which is also what chai is based on. If you try something like this in the REPL:

> assert = require('assert');
> let err;
> try { assert.deepStrictEqual({a: "foo"}, {a: "bar"}) } catch(e) { err = e; }

And then have a look at err, it has an actual and an expected field, which is what your test runner (in my case, mocha) should be using to generate that nice looking diff.

So, I guess the first question is, what test runner are you using? I guess Jest? I've never used it, but at a glance Jest is supposed to handle this.

jwalton avatar Oct 12 '18 18:10 jwalton

Indeed I'm using jest and I'm not getting a smart output. Tried with your project using jest + ts-jest:

yarn add --dev jest
yarn add --dev ts-jest

With the following jest.config.js file:

module.exports = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  testMatch: ['**/?(*.)+(spec|test).(j|t)s?(x)'],
  setupFiles: ['<rootDir>/test/setup.js']
};

With this test/setup.js file:

global.fetch = require('node-fetch');

And the following test/test.spec.ts:

import http from 'http';
import { fetch } from '../../src';

const server = http.createServer(
    (req, res) => {
        if(req.url === '/hello') {
            res.setHeader('content-type', 'application/json');
            res.end(JSON.stringify({greeting: "Hello!"}));
        } else if(req.url === '/hellotext') {
            res.end("Hello");
        } else if(req.url === '/err') {
            res.setHeader('content-type', req.headers['content-type'] || 'text/plain');
            res.statusCode = 400;
            res.end('Boom!\nLong message\n');
        } else {
            res.statusCode = 404;
            res.end();
        }
    }
);


it('should generate a nice diff if body is incorrect', async function() {
    await fetch(server, '/hello')
        .expectStatus(200)
        .expectHeader('content-type', 'application/json')
        .expectBody({greeting: "Hello2!"});
});

Running with yarn jest test/test.spec.ts won't give you a nice diff.

mgcrea avatar Oct 15 '18 15:10 mgcrea

If you want another quick test, try writing a jest test that just does something like:

assert.deepStrictEqual({a: "foo"}, {a: "bar"});

and see what that does. If that doesn't produce a pretty diff for you, I'd suggest this is something you should raise with the jest project.

jwalton avatar Oct 15 '18 16:10 jwalton

Does seem to work fine with jest, in another project:

  it.only('test', () => {
    require('assert').deepStrictEqual({a: 'foo'}, {a: 'bar'});
  });

Gives me:

    assert.deepStrictEqual(received, expected)

    Expected value to deeply and strictly equal to:
      {"a": "bar"}
    Received:
      {"a": "foo"}

    Difference:

    - Expected
    + Received

      Object {
    -   "a": "bar",
    +   "a": "foo",
      }

mgcrea avatar Oct 15 '18 19:10 mgcrea

I believe the technical term I'm looking for is "wat!?"

This is exactly what we're doing in supertest-fetch. -_-

jwalton avatar Oct 15 '18 19:10 jwalton

I'm playing with the source to see if I can pinpoint the diff, very strange indeed:

$ /private/tmp/node-supertest-fetch/node_modules/.bin/jest test/spec/test.spec.ts
 FAIL  test/spec/test.spec.ts
  ✕ test (11ms)
  ✕ should generate a nice diff if body is incorrect (26ms)

  ● test

    assert.deepStrictEqual(received, expected)

    Expected value to deeply and strictly equal to:
      {"a": "bar"}
    Received:
      {"a": "foo"}

    Difference:

    - Expected
    + Received

      Object {
    -   "a": "bar",
    +   "a": "foo",
      }

      21 | 
      22 | it('test', () => {
    > 23 |     require('assert').deepStrictEqual({a: 'foo'}, {a: 'bar'});
         |                       ^
      24 | });
      25 | 
      26 | it('should generate a nice diff if body is incorrect', async function() {

      at Object.<anonymous> (test/spec/test.spec.ts:23:23)

  ● should generate a nice diff if body is incorrect

    AssertionError [ERR_ASSERTION]: { greeting: 'Hello!' } deepStrictEqual { greeting: 'Hello2!' }

      183 |                     });
      184 |                 }
    > 185 |                 assert.deepStrictEqual(
          |                        ^
      186 |                     jsonBody,
      187 |                     expectedBody
      188 |                 );

      at Test.<anonymous> (src/Test.ts:185:24)
      at step (src/Test.ts:32:23)
      at Object.next (src/Test.ts:13:53)
      at fulfilled (src/Test.ts:4:58)

EDIT the Jest error formatter is here: https://github.com/facebook/jest/blob/master/packages/jest-circus/src/format_node_assert_errors.js

Can't really find what might be going on.

mgcrea avatar Oct 15 '18 19:10 mgcrea