为什么Jest不能正确地推断测试覆盖率行?

4xy9mtcn  于 2022-12-16  发布在  Jest
关注(0)|答案(1)|浏览(265)

我没有得到下面的文件100%的覆盖率,我不知道为什么会发生这种情况...

**问题的重点:**了解为什么Jest不考虑我的测试,这些测试覆盖了Jest抱怨没有覆盖的行。

Jest抱怨以下代码行:26-27,33-34,38-39,45-46,但是这些行被覆盖了,正如在我将粘贴到生产文件下面的测试文件上可以看到的那样。
26日至27日:

return badRequest(new MissingParamError(field))
      }

33-34

return badRequest(new InvalidParamError('confirmPassword'))
      }

38-39

return badRequest(new InvalidParamError('email'))
      }

45-46

return serverError()
     }

以下是我的生产文件:signup.ts

import { badRequest, serverError, ok } from '../../helpers/http-helper'
import {
  HttpRequest,
  HttpResponse,
  Controller,
  EmailValidator,
  AddAccount
} from './signup-protocols'
import { MissingParamError } from '../../errors/missing-param-error'
import { InvalidParamError } from '../../errors'

export class SignUpController implements Controller {
  private readonly emailValidator: EmailValidator
  private readonly addAccount: AddAccount

  constructor (emailValidator: EmailValidator, addAccount: AddAccount) {
    this.emailValidator = emailValidator
    this.addAccount = addAccount
  }

  async handle (httpRequest: HttpRequest): Promise<HttpResponse> {
    try {
      const bodyFields = ['name', 'email', 'password', 'confirmPassword']
      for (const field of bodyFields) {
        if (!httpRequest.body[field]) {
          return badRequest(new MissingParamError(field))
        }
      }

      const { name, email, password, confirmPassword } = httpRequest.body

      if (password !== confirmPassword) {
        return badRequest(new InvalidParamError('confirmPassword'))
      }

      const isValidMail = this.emailValidator.isValid(email)
      if (!isValidMail) {
        return badRequest(new InvalidParamError('email'))
      }

      const newAccount = await this.addAccount.add({ name, password, email })

      return ok(newAccount)
    } catch (err) {
      return serverError()
    }
  }
}

下面是我的测试文件:

import { SignUpController } from './signup'
import { MissingParamError, InvalidParamError, ServerError } from '../../errors'
import { EmailValidator, AddAccount, AddAccountModel, AccountModel } from './signup-protocols'

const makeEmailValidator = (): EmailValidator => {
  class EmailValidatorStub implements EmailValidator {
    isValid (email: string): boolean {
      return true
    }
  }
  return new EmailValidatorStub()
}

const makeAddAccount = (): AddAccount => {
  class AddAccountStub implements AddAccount {
    async add (account: AddAccountModel): Promise<AccountModel> {
      const fakeAccount = {
        id: 'valid_id',
        name: 'valid_name',
        email: 'valid@email.com',
        password: 'valid_password'
      }
      return await new Promise(resolve => resolve(fakeAccount))
    }
  }
  return new AddAccountStub()
}

interface SutTypes {
  sut: SignUpController
  emailValidatorStub: EmailValidator
  addAccountStub: AddAccount
}

const makeSut = (): SutTypes => {
  const emailValidatorStub = makeEmailValidator()
  const addAccountStub = makeAddAccount()
  const sut = new SignUpController(emailValidatorStub, addAccountStub)
  return {
    sut,
    emailValidatorStub,
    addAccountStub
  }
}

describe('Auth Controller', () => {
  beforeEach(() => {
    jest.clearAllMocks()
  })
  test('should return 400 if no name is provided', async () => {
    const { sut } = makeSut()

    const httpRequest = {
      body: {
        email: 'any@mail.com',
        password: 'any',
        confirmPassword: 'any'
      }
    }

    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.statusCode).toBe(400)
    expect(httpResponse.body).toEqual(new MissingParamError('name'))
  })
  test('should return 400 if no email is provided', async () => {
    const { sut } = makeSut()

    const httpRequest = {
      body: {
        name: 'any',
        password: 'any',
        confirmPassword: 'any'
      }
    }

    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.statusCode).toBe(400)
    expect(httpResponse.body).toEqual(new MissingParamError('email'))
  })
  test('should return 400 if no password is provided', async () => {
    const { sut } = makeSut()

    const httpRequest = {
      body: {
        name: 'any',
        email: 'any@mail.com',
        confirmPassword: 'any'
      }
    }

    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.statusCode).toBe(400)
    expect(httpResponse.body).toEqual(new MissingParamError('password'))
  })
  test('should return 400 if no password confirmation is provided', async () => {
    const { sut } = makeSut()

    const httpRequest = {
      body: {
        name: 'any',
        email: 'any@mail.com',
        password: 'any'
      }
    }

    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.statusCode).toBe(400)
    expect(httpResponse.body).toEqual(new MissingParamError('confirmPassword'))
  })
  test('should return 400 if an invalid email is provided', async () => {
    const { sut, emailValidatorStub } = makeSut()

    jest.spyOn(emailValidatorStub, 'isValid').mockReturnValueOnce(false)

    const httpRequest = {
      body: {
        name: 'any',
        email: 'invalid_mail@mail.com',
        password: 'any',
        confirmPassword: 'any'
      }
    }

    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.statusCode).toBe(400)
    expect(httpResponse.body).toEqual(new InvalidParamError('email'))
  })
  test('should call emailValidator with correct email', async () => {
    const { sut, emailValidatorStub } = makeSut()

    const isValidSpy = jest.spyOn(emailValidatorStub, 'isValid')

    const httpRequest = {
      body: {
        name: 'any',
        email: 'bla@mail.com',
        password: 'any',
        confirmPassword: 'any'
      }
    }

    await sut.handle(httpRequest)
    expect(isValidSpy).toHaveBeenCalledWith('bla@mail.com')
  })
  test('should return 500 if emailValidator throws', async () => {
    const { sut, emailValidatorStub } = makeSut()

    jest.spyOn(emailValidatorStub, 'isValid').mockImplementationOnce(() => {
      throw new Error()
    })

    const httpRequest = {
      body: {
        name: 'any',
        email: 'invalid_mail@mail.com',
        password: 'any',
        confirmPassword: 'any'
      }
    }

    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.statusCode).toBe(500)
    expect(httpResponse.body).toEqual(new ServerError())
  })
  test('should return 400 if password and confirmPassword do not match', async () => {
    const { sut } = makeSut()
    const httpRequest = {
      body: {
        name: 'any',
        email: 'invalid_mail@mail.com',
        password: 'any',
        confirmPassword: 'any1'
      }
    }

    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.body).toEqual(new InvalidParamError('confirmPassword'))
  })
  test('should call add with the proper params', async () => {
    const { sut, addAccountStub } = makeSut()
    const addSpy = jest.spyOn(addAccountStub, 'add')
    const httpRequest = {
      body: {
        name: 'any',
        email: 'invalid_mail@mail.com',
        password: 'any',
        confirmPassword: 'any'
      }
    }
    await sut.handle(httpRequest)
    expect(addSpy).toHaveBeenCalledWith({
      name: 'any',
      email: 'invalid_mail@mail.com',
      password: 'any'
    })
  })
  test('should return 500 if AddAccount throws', async () => {
    const { sut, addAccountStub } = makeSut()
    jest.spyOn(addAccountStub, 'add').mockImplementationOnce(async () => {
      return await new Promise((resolve, reject) => reject(new Error()))
    })
    const httpRequest = {
      body: {
        name: 'any',
        email: 'invalid_mail@mail.com',
        password: 'any',
        confirmPassword: 'any'
      }
    }
    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.statusCode).toBe(500)
    expect(httpResponse.body).toEqual(new ServerError())
  })
  test('Should return 200 if the proper data is provided', async () => {
    const { sut } = makeSut()
    const httpRequest = {
      body: {
        name: 'valid_name',
        email: 'valid@email.com',
        password: 'valid_password',
        confirmPassword: 'valid_password'
      }
    }
    const httpResponse = await sut.handle(httpRequest)
    expect(httpResponse.statusCode).toBe(200)
    expect(httpResponse.body).toEqual({
      id: 'valid_id',
      name: 'valid_name',
      email: 'valid@email.com',
      password: 'valid_password'
    })
  })
})

这是我的覆盖率测试脚本的结果:

git push origin master                                     
husky > pre-push (node v16.5.0)

> clean-express@1.0.0 test:ci
> npm test -- --coverage

> clean-express@1.0.0 test
> jest --passWithNoTests --silent --noStackTrace --runInBand "--coverage"

(node:4470) [MDEP001] DeprecationWarning: "MongoMemoryReplSet.getConnectionString" is deprecated, use ".getUri"
(Use `node --trace-deprecation ...` to show where the warning was created)
 PASS  src/main/Routes/signup-route.test.ts
 PASS  src/presentation/controllers/signup/signup.spec.ts
 PASS  src/main/Middlewares/content-type.test.ts
 PASS  src/main/Middlewares/body-parser.test.ts
 PASS  src/main/Middlewares/cors.test.ts
 PASS  src/infra/db/mongodb/account-repository/account.spec.ts
 PASS  src/infra/cryptography/bcrypt-adapter.spec.ts
 PASS  src/data/usecases/add-account/db-add-account.spec.ts
 PASS  src/utils/email-validator-adapter.spec.ts
-------------------------------------|---------|----------|---------|---------|-------------------------
File                                 | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s       
-------------------------------------|---------|----------|---------|---------|-------------------------
All files                            |   95.63 |    83.33 |     100 |   95.63 |                         
 data/usecases/add-account           |     100 |      100 |     100 |     100 |                         
  db-add-account.ts                  |     100 |      100 |     100 |     100 |                         
 infra/cryptography                  |     100 |      100 |     100 |     100 |                         
  bcrypt-adapter.ts                  |     100 |      100 |     100 |     100 |                         
 infra/db/mongodb/account-repository |     100 |      100 |     100 |     100 |                         
  account.ts                         |     100 |      100 |     100 |     100 |                         
 infra/db/mongodb/helpers            |     100 |      100 |     100 |     100 |                         
  mongo-helper.ts                    |     100 |      100 |     100 |     100 |                         
 presentation/controllers/signup     |   83.33 |    42.86 |     100 |   83.33 |                         
  signup.ts                          |   83.33 |    42.86 |     100 |   83.33 | 26-27,33-34,38-39,45-46 
 presentation/errors                 |     100 |      100 |     100 |     100 |                         
  base-error.ts                      |     100 |      100 |     100 |     100 |                         
  index.ts                           |     100 |      100 |     100 |     100 |                         
  invalid-param-error.ts             |     100 |      100 |     100 |     100 |                         
  missing-param-error.ts             |     100 |      100 |     100 |     100 |                         
  server-error.ts                    |     100 |      100 |     100 |     100 |                         
 presentation/helpers                |     100 |      100 |     100 |     100 |                         
  http-helper.ts                     |     100 |      100 |     100 |     100 |                         
 utils                               |     100 |      100 |     100 |     100 |                         
  email-validator-adapter.ts         |     100 |      100 |     100 |     100 |                         
-------------------------------------|---------|----------|---------|---------|-------------------------

Test Suites: 9 passed, 9 total
Tests:       28 passed, 28 total
Snapshots:   0 total
Time:        6.436 s, estimated 8 s
Enumerating objects: 21, done.

配置

{
    "compilerOptions": {
        "outDir": "./dist",
        "module": "commonjs",
        "target": "es2019",
        "esModuleInterop": true,
        "allowJs": true,
        "strictNullChecks": true
        
    }
}

package.json

{
  "name": "clean-express",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "sucrase-node src/main/server.ts",
    "test:verbose": "jest --passWithNoTests --runInBand",
    "test": "jest --passWithNoTests --silent --noStackTrace --runInBand",
    "test:unit": "npm test -- --watch -c jest-unit-config.js",
    "test:integration": "npm test -- --watch -c jest-integration-config.js",
    "test:staged": "npm test -- --findRelatedTests",
    "test:ci": "npm test -- --coverage"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "devDependencies": {
    "@shelf/jest-mongodb": "^1.2.4",
    "@types/bcrypt": "^3.0.1",
    "@types/express": "^4.17.13",
    "@types/jest": "^26.0.23",
    "@types/mongodb": "^3.6.12",
    "@types/node": "^15.0.1",
    "@types/supertest": "^2.0.11",
    "@types/validator": "^13.1.3",
    "@typescript-eslint/eslint-plugin": "^4.22.1",
    "eslint": "^7.25.0",
    "eslint-config-standard-with-typescript": "^20.0.0",
    "eslint-plugin-import": "^2.22.1",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^4.3.1",
    "git-commit-msg-linter": "^3.1.0",
    "husky": "^4.3.8",
    "jest": "^26.6.3",
    "lint-staged": "^10.5.4",
    "prettier": "^2.3.2",
    "sucrase": "^3.20.0",
    "supertest": "^6.1.4",
    "ts-jest": "^26.5.5",
    "typescript": "^4.2.4"
  },
  "dependencies": {
    "bcrypt": "^5.0.1",
    "express": "^4.17.1",
    "fast-glob": "^3.2.7",
    "mongodb": "^3.6.6",
    "validator": "^13.6.0"
  }
}

jest.config.js

module.exports = {
  roots: ['<rootDir>/src'],
  collectCoverageFrom: [
    '<rootDir>/src/**/*.ts',
    '!<rootDir>/src/main/**'
  ],
  coverageDirectory: 'coverage',
  coverageProvider: 'v8',
  testEnvironment: 'node',
  transform: {
    '.+\\.ts$': 'ts-jest'
  },
  coveragePathIgnorePatterns: ['protocols', 'domain'],
  preset: '@shelf/jest-mongodb'
}

jest-integration.config.js

const config = require('./jest.config')
config.testMatch = ['**/*.test.ts']
module.exports = config

jest-mongodb-config.js

module.exports = {
  mongodbMemoryServerOptions: {
    binary: {
      version: '4.0.3',
      skipMD5: true
    },
    autoStart: false,
    instance: {}
  }
}

jest-unit-config.js

const config = require('./jest.config')
config.testMatch = ['**/*.spec.ts']
module.exports = config

相关问题