4
votes

I'm in struggle since few days with e2e testing my NestJS application using GraphQL code first approach and TypeOrm.

I'm trying to create a TestingModule by injecting nestjs GraphQLModule with autoSchemaFile and I'm always getting the error "Schema must contain uniquely named types but contains multiple types named ...".

Here a reproduction of my bug with minimal code:

character.entity.ts:

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
import { ObjectType, Field, ID } from 'type-graphql';

@Entity()
@ObjectType()
export class Character {
    @PrimaryGeneratedColumn()
    @Field(() => ID)
    id: string;

    @Column({ unique: true })
    @Field()
    name: string;
}

character.resolver.ts:

import { Query, Resolver } from '@nestjs/graphql';
import { Character } from './models/character.entity';
import { CharacterService } from './character.service';

@Resolver(() => Character)
export class CharacterResolver {
    constructor(private readonly characterService: CharacterService) {}

    @Query(() => [Character], { name: 'characters' })
    async getCharacters(): Promise<Character[]> {
        return this.characterService.findAll();
    }
}

character.module.ts:

import { Module } from '@nestjs/common';
import { CharacterResolver } from './character.resolver';
import { CharacterService } from './character.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Character } from './models/character.entity';

@Module({
    imports: [TypeOrmModule.forFeature([Character])],
    providers: [CharacterResolver, CharacterService],
})
export class CharacterModule {}

app.module.ts:

import { Module } from '@nestjs/common';
import { CharacterModule } from './character/character.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Connection } from 'typeorm';
import { GraphQLModule } from '@nestjs/graphql';

@Module({
    imports: [TypeOrmModule.forRoot(), GraphQLModule.forRoot({ autoSchemaFile: 'schema.gql' }), CharacterModule],
    controllers: [],
    providers: [],
})
export class AppModule {
    constructor(private readonly connection: Connection) {}
}

and finally: character.e2e-spec.ts:

import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CharacterModule } from '../src/character/character.module';
import { GraphQLModule } from '@nestjs/graphql';

describe('CharacterResolver (e2e)', () => {
    let app: INestApplication;

    beforeAll(async () => {
        const module: TestingModule = await Test.createTestingModule({
            imports: [
                TypeOrmModule.forRoot(),
                GraphQLModule.forRoot({ playground: false, autoSchemaFile: 'schema.gql' }),
                CharacterModule,
            ],
        }).compile();

        app = module.createNestApplication();
        await app.init();
    });

    it('should create testing module', () => {
        expect(1).toBe(1);
    });

    afterAll(async () => {
        await app.close();
    });
});

And after running npm run test:e2e:

Schema must contain uniquely named types but contains multiple types named "Character".

      at typeMapReducer (../node_modules/graphql/type/schema.js:262:13)
          at Array.reduce (<anonymous>)
      at new GraphQLSchema (../node_modules/graphql/type/schema.js:145:28)
      at Function.generateFromMetadataSync (../node_modules/type-graphql/dist/schema/schema-generator.js:31:24)
      at Function.<anonymous> (../node_modules/type-graphql/dist/schema/schema-generator.js:16:33)
      at ../node_modules/tslib/tslib.js:110:75
      at Object.__awaiter (../node_modules/tslib/tslib.js:106:16)
      at Function.generateFromMetadata (../node_modules/type-graphql/dist/schema/schema-generator.js:15:24)

I don't find any other way to create a testing module with graphql code first approach on official doc or while googling... Am I missing something ?

1
Just set this up today and found the same issue. No clue what's leading to it. I can confirm the error occurs at the point: app.init()Joshua Book

1 Answers

1
votes

Your ormconfig.json need to look like this:

  "entities": [
    "src/**/*.entity.js"
  ],
  "migrations": [
    "src/migration/*.js"
  ],
  "cli": {
    "migrationsDir": "src/migration"
  }

I.e you need to specify the entities being in the src, not dist folder. If not TypeGraphQL will generate the schema for each resolver twice. To get the generate and run migration commands to work you would have to setup a different ormconfig.json for your development environment.