我正在将我的项目升级到 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 这个项目。