monkeyUser
monkeyUser

Reputation: 4671

Test functions cannot both take a 'done' callback

I'm trying to create a simple test with nestjs, and I'm getting this error

Test functions cannot both take a 'done' callback and return something. Either use a 'done' callback, or return a promise.

Returned value: Promise {}

The unit test is so simple, but I get an error when I use done();

it('throws an error if a user signs up with an email that is in use', async (done) => {
fakeUsersService.find = () => Promise.resolve([{ id: 1, email: 'a', password: '1' } as User]);
try {
  await service.signup('[email protected]', 'asdf');
} catch (err) {
  done();
}
});

Upvotes: 40

Views: 24749

Answers (9)

Sandro Skhirtladze
Sandro Skhirtladze

Reputation: 427

Just use return instead of calling done():

it('throws an error if a user signs up with an email that is in use', async () => {
  fakeUsersService.find = () =>
    Promise.resolve([{ id: 1, email: 'a', password: '1' } as User]);
  try {
    await service.signup('[email protected]', 'asdf');
  } catch {
    return;
  }
});

Upvotes: 2

Vladislav Lukyanuk
Vladislav Lukyanuk

Reputation: 1

You can use this hack for some cases =)

it('should make an api request', (done) => {
  const asyncCall = async () => {
    await callbackWithApiInside();

    setTimeout(() => {
      expect(api).toHaveBeenNthCalledWith(1, payload);
      done();
    }, 1000);
  };

  asyncCall();
});

Upvotes: -1

danny
danny

Reputation: 31

in order for it to work, you can do the following:

it('throws an error if a user signs up with an email that is in use', async () => {
fakeUsersService.find = () =>
  Promise.resolve([
    { id: 1, email: '[email protected]', password: 'somePassword' } as User,
  ]);
  expect(async () => {
  await service.signup('[email protected]', 'somePassword')
  }).rejects.toThrow(BadRequestException)
});

Upvotes: 0

Mehradi
Mehradi

Reputation: 32

it('throws an error if a user signs up with an email that is in use', async () => {
    await service.signup('[email protected]', 'asdf');
    try {
     await service.signup('[email protected]', 'asdf');
    } catch (e) {
      expect(e.toString()).toMatch('email in use');
    }
  });

Upvotes: 0

Anatolii Kosorukov
Anatolii Kosorukov

Reputation: 960

For the last version from jest, you can't use `async/await , promise and done together (Test functions cannot both take a 'done' callback and return something. Either use a 'done' callback, or return a promise.).

the solution is

user.entity.ts

import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  AfterInsert,
  AfterRemove,
  AfterUpdate,
} from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  email: string;

  @Column()

  password: string;

  @AfterInsert()
  logInsert() {
    console.log('Inserted User with id', this.id);
  }

  @AfterUpdate()
  logUpdate() {
    console.log('Updated User with id', this.id);
  }

  @AfterRemove()
  logRemove() {
    console.log('Removed User with id', this.id);
  }
}

auth.service.spec.ts

  it('throws an error if user signs up with email that is in use', async () => {
    fakeUsersService.find = () =>
      Promise.resolve([{ id: 1, email: '[email protected]', password: '1' } as User]);

    expect(async () => {
      const email = '[email protected]';
      const password = 'asdf';
      await service.signup(email, password);
    }).rejects.toThrow(BadRequestException);
  });

Upvotes: 1

Before v27, jest use jest-jasmine2 by default.

For version 27, jest uses jest-circus which doesn’t support done callback.

So you need to change the default testRunner.

Override with react-app-rewired worked for me

// config-overrides.js
module.exports.jest = (config) => {
    config.testRunner = 'jest-jasmine2';
    return config;
};

Upvotes: 4

Amr Abdalrahman Ahmed
Amr Abdalrahman Ahmed

Reputation: 1010

for the last version from jest, you can't use `async/await , promise and done together.

the solution is

 it("throws an error if user sings up with email that is in use", async () => {
    fakeUsersService.find = () =>
      Promise.resolve([{ id: 1, email: "a", password: "1" } as User]);
    await expect(service.signup("[email protected]", "asdf")).rejects.toThrow(
      BadRequestException
    );
  });

change BadRequestException according to your listening exception

Upvotes: 16

stark max
stark max

Reputation: 63

Also, if you want to use both you can downgrade your current version of jest to : 26.6.3. Worked fine for me, I'm using async + done

Upvotes: 0

Steven Scott
Steven Scott

Reputation: 11250

You are combining Async/Await and Done.

Either use asnyc/await, or done.

it('throws an error if user signs up with email that is in use', async () => {
    try {
        await service();
        expect(...);
    } catch (err) {
    }
});

or use the done format

it('throws an error if user signs up with email that is in use', (done) => {
    ...
    service()
     .then( ...) {}
     .catch( ...) {}
    }
    done();
});

Upvotes: 41

Related Questions