[ExceptionHandler] this.athleteRepository.findByEmail 不是函数”在 NestJs 上进行 TypeOrm 升级后

问题描述 投票:0回答:0

我正在将我的项目升级到 TypeOrm 0.3.12

我花了很多时间修复我所有的集成测试,例如我的

AthleteRepository
如下:

import { getRepositoryToken, TypeOrmModule } from '@nestjs/typeorm'
import { Test } from '@nestjs/testing'
import { config } from '../../../config'
import { TypeOrmAthleteRepository } from './typeorm-athlete.repository'
import { athleteDataBuilder } from '../data-builders/athlete.data-builder'
import { RepositoryErrors } from '../types/repository-errors.enum'
import { Biometrics } from '../../biometrics/entities/biometrics.entity'
import { biometricsDataBuilder } from '../../biometrics/data-builders/biometrics.data-builder'
import { TypeOrmBiometricsRepository } from '../../biometrics/repositories/typeorm-biometrics.repository'
import { TypeOrmDailyTaskRepository } from '../../daily-task/repositories/daily-task.typeorm.repository'
import { TypeOrmProgramRepository } from '../../program/repositories/type-orm-program.repository'
import { TypeOrmWorkoutRepository } from '../../workout/repositories/workout.typeorm.repository'
import { TypeOrmExerciseRepository } from '../../exercise/repositories/type-orm-exercise.repository'
import { TypeOrmExerciseTemplateRepository } from '../../exercise/repositories/type-orm-exercise-template.repository'
import { DailyTask } from '../../daily-task/entities/daily-task.entity'
import { dailyTaskDataBuilder } from '../../daily-task/data-builders/daily-task.data-builder'
import { programDataBuilder } from '../../program/data-builders/program.data-builder'
import { expectedBaseEntity } from '../../__infrastructure__/typeorm/expected-base-entity.data-builder'
import { TypeOrmSessionRepository } from '../../session/repositories/session.typeorm.repository'
import { TypeOrmPerformanceRepository } from '../../performance/repositories/performance.typeorm.repository'
import { Athlete } from '../entities/athlete.entity'
import { Exercise } from '../../exercise/entities/exercise.entity'
import { ExerciseTemplate } from '../../exercise/entities/exercise-template.entity'
import { Session } from '../../session/entities/session.entity'
import { Performance } from '../../performance/entities/performance.entity'
import { Workout } from '../../workout/entities/workout.entity'
import { Program } from '../../program/entities/program.entity'

const programFixtures = [
  new Program(programDataBuilder()),
  new Program(programDataBuilder()),
]
const dailyTaskFixtures = [
  new DailyTask(dailyTaskDataBuilder()),
  new DailyTask(dailyTaskDataBuilder()),
]
const biometricsFixture = new Biometrics(biometricsDataBuilder())
const athleteFixture = new Athlete(athleteDataBuilder())

describe('TypeOrmAthleteRepository', () => {
  let athleteRepository: TypeOrmAthleteRepository
  let biometricsRepository: TypeOrmBiometricsRepository
  let dailyTaskRepository: TypeOrmDailyTaskRepository
  let programRepository: TypeOrmProgramRepository

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      imports: [
        TypeOrmModule.forRoot(config.db),
        TypeOrmModule.forFeature([
          Athlete,
          Biometrics,
          DailyTask,
          Exercise,
          ExerciseTemplate,
          Program,
          Workout,
          Session,
          Performance,
        ]),
      ],
      providers: [
        TypeOrmAthleteRepository,
        TypeOrmBiometricsRepository,
        TypeOrmDailyTaskRepository,
        TypeOrmExerciseRepository,
        TypeOrmExerciseTemplateRepository,
        TypeOrmProgramRepository,
        TypeOrmWorkoutRepository,
        TypeOrmSessionRepository,
        TypeOrmPerformanceRepository,
      ],
    }).compile()

    athleteRepository = module.get<TypeOrmAthleteRepository>(
      getRepositoryToken(TypeOrmAthleteRepository),
    )
    biometricsRepository = module.get<TypeOrmBiometricsRepository>(
      getRepositoryToken(TypeOrmBiometricsRepository),
    )
    dailyTaskRepository = module.get<TypeOrmDailyTaskRepository>(
      getRepositoryToken(TypeOrmDailyTaskRepository),
    )
    programRepository = module.get<TypeOrmProgramRepository>(
      getRepositoryToken(TypeOrmProgramRepository),
    )

    const dailyTasks = await dailyTaskRepository.save(dailyTaskFixtures)
    const programs = await programRepository.save(programFixtures)
    const biometrics = await biometricsRepository.save(biometricsFixture)
    const athlete = {
      ...athleteFixture,
      biometrics,
      dailyTasks,
      programs,
    }
    await athleteRepository.save(athlete)
  })

  afterAll(async () => {
    await programRepository.query('SET FOREIGN_KEY_CHECKS=0')
    await dailyTaskRepository.query('SET FOREIGN_KEY_CHECKS=0')
    await dailyTaskRepository.query(`DELETE FROM daily_task;`)
    await athleteRepository.query(`DELETE FROM athlete;`)
    await programRepository.query(`DELETE FROM program;`)
    await biometricsRepository.query(`DELETE FROM biometrics;`)
  })

  it('should be defined', () => {
    expect(athleteRepository).toBeDefined()
  })

  it('should find an athlete by id', async () => {
    const expectedAthlete = new Athlete({
      ...athleteFixture,
      ...expectedBaseEntity,
      biometrics: new Biometrics(biometricsFixture),
      dailyTasks: dailyTaskFixtures.map(
        (fixture) =>
          new DailyTask({
            ...fixture,
            ...expectedBaseEntity,
          }),
      ),
      programs: programFixtures.map(
        (fixture) =>
          new Program({
            ...fixture,
            ...expectedBaseEntity,
          }),
      ),
    })

    const retrievedAthlete = await athleteRepository.findById(athleteFixture.id)

    expect(retrievedAthlete).toStrictEqual(expectedAthlete)
  })

  it('should find an athlete by email', async () => {
    const expectedAthlete = new Athlete({
      ...athleteFixture,
      ...expectedBaseEntity,
      biometrics: new Biometrics(biometricsFixture),
      dailyTasks: dailyTaskFixtures.map(
        (fixture) =>
          new DailyTask({
            ...fixture,
            ...expectedBaseEntity,
          }),
      ),
      programs: programFixtures.map(
        (fixture) =>
          new Program({
            ...fixture,
            ...expectedBaseEntity,
          }),
      ),
    })

    const retrievedAthlete = await athleteRepository.findByEmail(
      athleteFixture.email,
    )

    expect(retrievedAthlete).toStrictEqual(expectedAthlete)
  })

  it('should throw an error when email already used', async () => {
    const alreadyRegisteredAthlete = new Athlete(athleteDataBuilder())
    const athleteWithSameEmail = new Athlete(
      athleteDataBuilder({ email: alreadyRegisteredAthlete.email }),
    )

    const expectedErrorCode = RepositoryErrors.DUPLICATED_ENTRY

    await athleteRepository.save(alreadyRegisteredAthlete)

    let thrownError, retrievedAthlete
    try {
      retrievedAthlete = await athleteRepository.save(athleteWithSameEmail)
    } catch (e) {
      thrownError = e
    }

    expect(retrievedAthlete).toBeUndefined()
    expect(thrownError.code).toBe(expectedErrorCode)
  })
})

然而,尽管它通过得很好,但在运行我的 e2e 测试时,我有

[ExceptionHandler] this.athleteRepository.findByEmail is not a function
.

我的 e2e 的开始(我想我需要改变一些东西)是这样的:

import 'dotenv/config'
import { Test, TestingModule } from '@nestjs/testing'
import { INestApplication } from '@nestjs/common'
import * as request from 'supertest'
import { AppModule } from '../src/app.module'
import { WeekDays } from '../src/workout/types/week-days.enum'
import { generateFixtures } from './fixtures/generate-fixtures'
import { defaultExerciseTemplatesDataBuilder } from '../src/exercise/data-builders/default-exercise-templates.data-builder'
import { registerAthleteInputDataBuilder } from '../src/auth/data-builders/register-athlete-input.data-builder'
import { exerciseDetailsInputDataBuilder } from '../src/exercise/data-builders/exercise-details-input.data-builder'
import { authCredentialsInputDataBuilder } from '../src/auth/data-builders/auth-credentials-input.data-builder'
import { AccessToken } from '../src/auth/types/access-token.type'
import {
  getDataKey,
  handleGraphQLResponse,
  Query,
} from './handle-graphql-response'
import { exerciseInputDataBuilder } from '../src/exercise/data-builders/exercise-input.data-builder'
import { Connection } from 'typeorm'
import { deleteFixtures } from './fixtures/delete-fixtures'
import { generateJwtToken } from './generate-jwt-token'
import {
  programDataBuilder,
  programFixture,
  programFixtures,
} from '../src/program/data-builders/program.data-builder'
import { workoutFixture } from '../src/workout/data-builders/workout.data-builder'
import { exerciseFixtures } from '../src/exercise/data-builders/exercise.data-builder'
import { biometricsFixture } from '../src/biometrics/data-builders/biometrics.data-builder'
import { dailyTaskFixtures } from '../src/daily-task/data-builders/daily-task.data-builder'
import { athleteFixture } from '../src/athlete/data-builders/athlete.data-builder'
import { sessionFixture } from '../src/session/data-builders/session.data-builder'
import { performanceFixture } from '../src/performance/data-builders/performance.data-builder'
import { HardCodedValuesEnum } from './fixtures/hard-coded-values.enum'

describe('AppController (e2e)', () => {
  let app: INestApplication
  let connection: Connection
  let token: AccessToken

  function expectGqlEndpoint(
    query: Query,
    expectedData:
      | Record<string, unknown>
      | Array<Record<string, unknown>>
      | boolean,
    isAuthenticated = true,
  ) {
    const tokenJwt = isAuthenticated ? token.token : undefined
    const dataKey = getDataKey(query)

    return request(app.getHttpServer())
      .post('/graphql')
      .set('Authorization', 'Bearer ' + tokenJwt)
      .send(query)
      .expect((response) =>
        handleGraphQLResponse(response, dataKey, expectedData),
      )
  }

  beforeAll(async () => {
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile()

    app = moduleFixture.createNestApplication()
    await app.init()

    //connection = app.get(Connection)
    //await deleteFixtures(connection)
    //await generateFixtures(connection)
    //token = await generateJwtToken(app)
  })

  afterAll(async () => {
    //await deleteFixtures(connection)
    await app.close()
  })

控制台中出现完整错误:

yarn run v1.22.17
$ jest -c ./test/jest-e2e.json --runInBand --forceExit -t 'Public Endpoints'
[Nest] 28129   - 04/01/2023, 11:32:05 PM   [ExceptionHandler] this.athleteRepository.findByEmail is not a function
TypeError: this.athleteRepository.findByEmail is not a function
    at AuthService.signIn (/Users/arthurmehmetoglu/Development/CorpoSano/back/src/auth/auth.service.ts:36:50)
    at AuthResolver.signIn (/Users/arthurmehmetoglu/Development/CorpoSano/back/src/auth/auth.resolver.ts:17:29)
    at /Users/arthurmehmetoglu/Development/CorpoSano/back/node_modules/@nestjs/core/helpers/external-context-creator.js:69:33
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at target (/Users/arthurmehmetoglu/Development/CorpoSano/back/node_modules/@nestjs/core/helpers/external-context-creator.js:76:28)
    at Object.signIn (/Users/arthurmehmetoglu/Development/CorpoSano/back/node_modules/@nestjs/core/helpers/external-proxy.js:9:24)
[Nest] 28129   - 04/01/2023, 11:32:05 PM   [ExceptionHandler] No metadata for "TypeOrmAthleteRepository" was found. +112ms
EntityMetadataNotFoundError: No metadata for "TypeOrmAthleteRepository" was found.
    at DataSource.getMetadata (/Users/arthurmehmetoglu/Development/CorpoSano/back/src/data-source/DataSource.ts:438:30)
    at Repository.get metadata [as metadata] (/Users/arthurmehmetoglu/Development/CorpoSano/back/src/repository/Repository.ts:53:40)
    at Repository.save (/Users/arthurmehmetoglu/Development/CorpoSano/back/src/repository/Repository.ts:206:18)
    at AuthService.register (/Users/arthurmehmetoglu/Development/CorpoSano/back/src/auth/auth.service.ts:63:37)
    at target (/Users/arthurmehmetoglu/Development/CorpoSano/back/node_modules/@nestjs/core/helpers/external-context-creator.js:76:28)
    at Object.registerAthlete (/Users/arthurmehmetoglu/Development/CorpoSano/back/node_modules/@nestjs/core/helpers/external-proxy.js:9:24)
  console.error
    {
      "errors": [
        {
          "message": "this.athleteRepository.findByEmail is not a function",
          "locations": [
            {
              "line": 2,
              "column": 11
            }
          ],
          "path": [
            "signIn"
          ],
          "extensions": {
            "code": "INTERNAL_SERVER_ERROR"
          }
        }
      ],
      "data": null
    }

       8 |   if (hasErrors(response)) {
       9 |     const formattedError = JSON.stringify(response.body, null, 2)
    > 10 |     console.error(formattedError)
         |             ^
      11 |   }
      12 | }
      13 |

      at displayErrors (handle-graphql-response.ts:10:13)
      at handleGraphQLResponse (handle-graphql-response.ts:36:3)
      at app.e2e-spec.ts:57:30
      at ../node_modules/supertest/lib/test.js:308:13
      at Test._assertFunction (../node_modules/supertest/lib/test.js:285:13)
      at Test.assert (../node_modules/supertest/lib/test.js:164:23)
      at Server.localAssert (../node_modules/supertest/lib/test.js:120:14)

[Nest] 28129   - 04/01/2023, 11:32:05 PM   [ExceptionHandler] this.athleteRepository.findById is not a function +8ms
TypeError: this.athleteRepository.findById is not a function
    at AuthService.sendConfirmationEmail (/Users/arthurmehmetoglu/Development/CorpoSano/back/src/auth/auth.service.ts:81:50)
    at AuthResolver.sendConfirmationEmail (/Users/arthurmehmetoglu/Development/CorpoSano/back/src/auth/auth.resolver.ts:33:29)
    at /Users/arthurmehmetoglu/Development/CorpoSano/back/node_modules/@nestjs/core/helpers/external-context-creator.js:69:33
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at target (/Users/arthurmehmetoglu/Development/CorpoSano/back/node_modules/@nestjs/core/helpers/external-context-creator.js:76:28)
    at Object.sendConfirmationEmail (/Users/arthurmehmetoglu/Development/CorpoSano/back/node_modules/@nestjs/core/helpers/external-proxy.js:9:24)
 FAIL  test/app.e2e-spec.ts (8.634 s)
  AppController (e2e)
    Public Endpoints
      ✕ Sign In (69 ms)
      ✕ Register Athlete (83 ms)
      ✕ Send Confirmation Email (7 ms)
    Queries
      ○ skipped Get All Exercise Templates
      ○ skipped Get Workout
      ○ skipped Get All Programs
      ○ skipped Get Program By Id
      ○ skipped Get Exercise
      ○ skipped Get Athlete
    Mutations
      ○ skipped Create Program
      ○ skipped Delete Program
      ○ skipped Create Workout
      ○ skipped Delete Workout
      ○ skipped Create Session
      ○ skipped Fill Workout With Exercises
      ○ skipped Schedule Workout
      ○ skipped Save Exercise's details
      ○ skipped Update Workout
      ○ skipped Delete Exercise

  ● AppController (e2e) › Public Endpoints › Sign In

    expect(received).toStrictEqual(expected) // deep equality

    Expected: {"token": Any<String>}
    Received: "error somewhere 😱"

      54 |       .set('Authorization', 'Bearer ' + tokenJwt)
      55 |       .send(query)
    > 56 |       .expect((response) =>
         |        ^
      57 |         handleGraphQLResponse(response, dataKey, expectedData),
      58 |       )
      59 |   }

      at expectGqlEndpoint (app.e2e-spec.ts:56:8)
      at Object.<anonymous> (app.e2e-spec.ts:97:14)
      ----
      at handleGraphQLResponse (handle-graphql-response.ts:38:25)
      at app.e2e-spec.ts:57:30
      at ../node_modules/supertest/lib/test.js:308:13
      at Test._assertFunction (../node_modules/supertest/lib/test.js:285:13)
      at Test.assert (../node_modules/supertest/lib/test.js:164:23)
      at Server.localAssert (../node_modules/supertest/lib/test.js:120:14)

  ● AppController (e2e) › Public Endpoints › Register Athlete

    expect(received).toStrictEqual(expected) // deep equality

    Expected: {"biometrics": {"bodyFat": 9538}, "email": "[email protected]", "id": Any<String>, "name": "Talon", "password": Any<String>}
    Received: "error somewhere 😱"

      54 |       .set('Authorization', 'Bearer ' + tokenJwt)
      55 |       .send(query)
    > 56 |       .expect((response) =>
         |        ^
      57 |         handleGraphQLResponse(response, dataKey, expectedData),
      58 |       )
      59 |   }

      at expectGqlEndpoint (app.e2e-spec.ts:56:8)
      at Object.<anonymous> (app.e2e-spec.ts:125:14)
      ----
      at handleGraphQLResponse (handle-graphql-response.ts:38:25)
      at app.e2e-spec.ts:57:30
      at ../node_modules/supertest/lib/test.js:308:13
      at Test._assertFunction (../node_modules/supertest/lib/test.js:285:13)
      at Test.assert (../node_modules/supertest/lib/test.js:164:23)
      at Server.localAssert (../node_modules/supertest/lib/test.js:120:14)

  ● AppController (e2e) › Public Endpoints › Send Confirmation Email

    expect(received).toStrictEqual(expected) // deep equality

    Expected: true
    Received: "error somewhere 😱"

      54 |       .set('Authorization', 'Bearer ' + tokenJwt)
      55 |       .send(query)
    > 56 |       .expect((response) =>
         |        ^
      57 |         handleGraphQLResponse(response, dataKey, expectedData),
      58 |       )
      59 |   }

      at expectGqlEndpoint (app.e2e-spec.ts:56:8)
      at Object.<anonymous> (app.e2e-spec.ts:138:14)
      ----
      at handleGraphQLResponse (handle-graphql-response.ts:38:25)
      at app.e2e-spec.ts:57:30
      at ../node_modules/supertest/lib/test.js:308:13
      at Test._assertFunction (../node_modules/supertest/lib/test.js:285:13)
      at Test.assert (../node_modules/supertest/lib/test.js:164:23)
      at Server.localAssert (../node_modules/supertest/lib/test.js:120:14)

Test Suites: 1 failed, 1 total
Tests:       3 failed, 16 skipped, 19 total
Snapshots:   0 total
Time:        8.694 s, estimated 12 s
Ran all test suites with tests matching "Public Endpoints".
Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished?
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
➜  back git:(migrate/typeorm) ✗

根据我的

AppModule
文件,非常简单,我相信是正确的:

import { Module } from '@nestjs/common'
import { ProgramModule } from './program/program.module'
import { GraphQLModule } from '@nestjs/graphql'
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'
import { TypeOrmModule } from '@nestjs/typeorm'
import { WorkoutModule } from './workout/workout.module'
import { ExerciseModule } from './exercise/exercise.module'
import { config } from '../config'
import { AthleteModule } from './athlete/athlete.module'
import { AuthModule } from './auth/auth.module'
import { BiometricsModule } from './biometrics/biometrics.module'
import { DailyTaskModule } from './daily-task/daily-task.module'
import { SessionModule } from './session/session.module'
import { PerformanceModule } from './performance/performance.module'
import { ConfigModule } from '@nestjs/config'
import { DataSource } from 'typeorm'

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: 'schema.gql',
    }),
    ConfigModule.forRoot(),
    TypeOrmModule.forRoot(config.db),
    ExerciseModule,
    ProgramModule,
    WorkoutModule,
    AthleteModule,
    AuthModule,
    BiometricsModule,
    DailyTaskModule,
    PerformanceModule,
    SessionModule,
  ],
})
export class AppModule {
  constructor(private dataSource: DataSource) {}
}

有关更多信息,请随时查看我的分支 migrate/typeorm,您可以在其中查看所有以前的更改,以及对代码的完全访问权限。如果你想玩的话,你甚至可以 git clone 这个项目。

typescript nestjs typeorm e2e-testing
© www.soinside.com 2019 - 2024. All rights reserved.