NestJS - GraphQL 在我开玩笑的 E2E 中不起作用 "is not a function"
NestJS - GraphQL not working in my jest E2E "is not a function"
我已经用 NestJS + Apollo / Express 在我的 GraphQL 应用程序上解决 E2E 测试问题 3 天了。
当我 运行 我的应用程序使用 无服务器离线 或直接使用我的 主文件 时,它运行完美。我有我的图表和我需要的所有东西:)
但是,当我 运行 使用 Jest 进行 E2E 测试时,我从 beforeEach
中的 await app.init()
收到错误。
使用 package.json 和依赖项后,抛出的错误是 TypeError: (0 , schema_1.makeExecutableSchema) is not a function
。
有人知道吗?我完全被封锁了......:(
FAIL src/__tests/graphql/common.e2e-spec.ts
GraphQL - CommonModule (e2e)
Query - Test
✕ should return the test query with typename TestSuccess (code: 200) (385 ms)
● GraphQL - CommonModule (e2e) › Query - Test › should return the test query with typename TestSuccess (code: 200)
TypeError: (0 , schema_1.makeExecutableSchema) is not a function
15 | app = moduleFixture.createNestApplication();
16 | app.useGlobalPipes(new ValidationPipe());
> 17 | await app.init();
| ^
18 |
19 | request = superRequest(app.getHttpServer());
20 | });
at GraphQLFactory.mergeWithSchema (node_modules/@nestjs/graphql/dist/graphql.factory.js:30:72)
at ApolloDriver.start (node_modules/@nestjs/apollo/dist/drivers/apollo.driver.js:19:25)
at GraphQLModule.onModuleInit (node_modules/@nestjs/graphql/dist/graphql.module.js:103:9)
at Object.callModuleInitHook (node_modules/@nestjs/core/hooks/on-module-init.hook.js:51:9)
at Proxy.callInitHook (node_modules/@nestjs/core/nest-application-context.js:179:13)
at Proxy.init (node_modules/@nestjs/core/nest-application.js:96:9)
at Object.<anonymous> (src/__tests/graphql/common.e2e-spec.ts:17:5)
package.json
"dependencies": {
"@nestjs/apollo": "^10.0.4",
"@nestjs/common": "^8.3.1",
"@nestjs/core": "^8.3.1",
"@nestjs/graphql": "^10.0.4",
"@nestjs/jwt": "^8.0.0",
"@nestjs/passport": "^8.2.1",
"@nestjs/platform-express": "^8.3.1",
"@prisma/client": "^3.9.2",
"@vendia/serverless-express": "^4.5.3",
"apollo-server-core": "^3.6.3",
"apollo-server-express": "^3.6.3",
"apollo-server-plugin-base": "^3.5.1",
"aws-lambda": "^1.0.7",
"bcryptjs": "^2.4.3",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"dotenv": "^16.0.0",
"env-var": "^7.1.1",
"express": "^4.17.1",
"graphql": "^16.3.0",
"graphql-query-complexity": "^0.11.0",
"nestjs-pino": "^2.5.0",
"passport": "^0.5.2",
"passport-jwt": "^4.0.0",
"pg": "^8.7.3",
"pino-http": "^6.6.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.5.3"
},
"devDependencies": {
"@faker-js/faker": "^6.0.0-alpha.5",
"@nestjs/cli": "^8.2.0",
"@nestjs/schematics": "^8.0.0",
"@nestjs/testing": "^8.0.0",
"@serverless/typescript": "^3.2.0",
"@types/aws-lambda": "^8.10.92",
"@types/bcryptjs": "^2.4.2",
"@types/express": "^4.17.13",
"@types/jest": "27.4.0",
"@types/node": "^16.0.0",
"@types/passport-local": "^1.0.34",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"apollo-server-testing": "^2.25.3",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.5.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.5.1",
"prisma": "^3.9.2",
"prisma-nestjs-graphql": "^14.6.1",
"serverless": "^3.2.1",
"serverless-offline": "^8.4.0",
"serverless-plugin-optimize": "^4.2.1-rc.1",
"serverless-plugin-warmup": "^7.0.2",
"source-map-support": "^0.5.21",
"supertest": "^6.2.2",
"ts-jest": "^27.1.3",
"ts-loader": "^9.2.3",
"ts-morph": "^13.0.3",
"ts-node": "^10.5.0",
"tsc-alias": "^1.5.0",
"tsconfig-paths": "^3.12.0",
"typescript": "^4.5.5",
"webpack": "^5.0.0"
}
jest.config.ts
module.exports = {
moduleFileExtensions: ['js', 'json', 'ts'],
testEnvironment: 'node',
transform: {
'^.+\.(t|j)s$': 'ts-jest',
},
testRegex: '.(spec|e2e-spec).ts$',
moduleNameMapper: {
'^@features/(.*)': '<rootDir>/src/features/',
'^@tests/(.*)': '<rootDir>/src/__tests/',
'^@graphql': '<rootDir>/src/@graphql/generated',
'^@types': '<rootDir>/src/@types',
'^@utils': '<rootDir>/src/utils',
'^@config': '<rootDir>/src/config',
},
testPathIgnorePatterns: [
'<rootDir>/dist/',
'<rootDir>/prisma/',
'<rootDir>/bin/',
'<rootDir>/node_modules/',
'<rootDir>/.github/',
],
};
graphql.e2e-spec.ts
import { GraphQLModule } from '@features/graphql/graphql.module';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import superRequest, { SuperTest, Test as TestItem } from 'supertest';
describe('GraphQL - CommonModule (e2e)', () => {
let app: INestApplication;
let request: SuperTest<TestItem>;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [GraphQLModule],
}).compile();
app = moduleFixture.createNestApplication();
app.useGlobalPipes(new ValidationPipe());
await app.init();
request = superRequest(app.getHttpServer());
});
describe('Query - Test', () => {
it('should return the test query with typename TestSuccess (code: 200)', async () => {
return request
.post('/graphql')
.send({
query: `
query {
test {
__typename
}
}`,
})
.then((res) => {
expect(res.status).toBe(200);
expect(res.body.data.test.__typename).toBe('TestSuccess');
});
});
});
});
graphql.module.ts
import { config } from '@config';
import { AppService } from '@features/app.service';
import { GraphQLAuthModule } from '@features/graphql/auth/auth.module';
import { CommonModule } from '@features/graphql/common/common.module';
import { UserModule } from '@features/graphql/user/user.module';
import { GraphQLComplexityPlugin } from '@features/graphql/_plugins';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule as NESTJSGraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
@Module({
imports: [
GraphQLAuthModule,
NESTJSGraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/@graphql/schema.gql'),
sortSchema: true,
debug: config.graphql.isDebugEnabled,
introspection: true,
playground: config.graphql.isPlaygroundEnabled
? {
settings: { 'schema.polling.enable': false },
}
: false,
}),
UserModule,
CommonModule,
],
providers: [AppService, GraphQLComplexityPlugin],
})
export class GraphQLModule {
constructor(private readonly appService: AppService) {
if (!this.appService.checkEnv()) process.exit();
}
}
经过数小时的紧张编程...
终于找到问题了
如果您对导入使用某些“别名”,请小心,因为它可能会覆盖某些已使用的包。
在这里,我使用了 @graphql
别名,它破坏了我所有的测试。
当我删除它时,问题就消失了。
moduleNameMapper: {
'^@features/(.*)': '<rootDir>/src/features/',
'^@tests/(.*)': '<rootDir>/__tests/',
'^@utils': '<rootDir>/src/utils',
'^@config': '<rootDir>/src/config',
'^@types': '<rootDir>/src/@types',
'^@graphql': '<rootDir>/src/@graphql/generated', // to remove
},
至
moduleNameMapper: {
'^@features/(.*)': '<rootDir>/src/features/',
'^@tests/(.*)': '<rootDir>/__tests/',
'^@utils': '<rootDir>/src/utils',
'^@config': '<rootDir>/src/config',
'^@types': '<rootDir>/src/@types',
},
我已经用 NestJS + Apollo / Express 在我的 GraphQL 应用程序上解决 E2E 测试问题 3 天了。
当我 运行 我的应用程序使用 无服务器离线 或直接使用我的 主文件 时,它运行完美。我有我的图表和我需要的所有东西:)
但是,当我 运行 使用 Jest 进行 E2E 测试时,我从 beforeEach
中的 await app.init()
收到错误。
使用 package.json 和依赖项后,抛出的错误是 TypeError: (0 , schema_1.makeExecutableSchema) is not a function
。
有人知道吗?我完全被封锁了......:(
FAIL src/__tests/graphql/common.e2e-spec.ts
GraphQL - CommonModule (e2e)
Query - Test
✕ should return the test query with typename TestSuccess (code: 200) (385 ms)
● GraphQL - CommonModule (e2e) › Query - Test › should return the test query with typename TestSuccess (code: 200)
TypeError: (0 , schema_1.makeExecutableSchema) is not a function
15 | app = moduleFixture.createNestApplication();
16 | app.useGlobalPipes(new ValidationPipe());
> 17 | await app.init();
| ^
18 |
19 | request = superRequest(app.getHttpServer());
20 | });
at GraphQLFactory.mergeWithSchema (node_modules/@nestjs/graphql/dist/graphql.factory.js:30:72)
at ApolloDriver.start (node_modules/@nestjs/apollo/dist/drivers/apollo.driver.js:19:25)
at GraphQLModule.onModuleInit (node_modules/@nestjs/graphql/dist/graphql.module.js:103:9)
at Object.callModuleInitHook (node_modules/@nestjs/core/hooks/on-module-init.hook.js:51:9)
at Proxy.callInitHook (node_modules/@nestjs/core/nest-application-context.js:179:13)
at Proxy.init (node_modules/@nestjs/core/nest-application.js:96:9)
at Object.<anonymous> (src/__tests/graphql/common.e2e-spec.ts:17:5)
package.json
"dependencies": {
"@nestjs/apollo": "^10.0.4",
"@nestjs/common": "^8.3.1",
"@nestjs/core": "^8.3.1",
"@nestjs/graphql": "^10.0.4",
"@nestjs/jwt": "^8.0.0",
"@nestjs/passport": "^8.2.1",
"@nestjs/platform-express": "^8.3.1",
"@prisma/client": "^3.9.2",
"@vendia/serverless-express": "^4.5.3",
"apollo-server-core": "^3.6.3",
"apollo-server-express": "^3.6.3",
"apollo-server-plugin-base": "^3.5.1",
"aws-lambda": "^1.0.7",
"bcryptjs": "^2.4.3",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
"dotenv": "^16.0.0",
"env-var": "^7.1.1",
"express": "^4.17.1",
"graphql": "^16.3.0",
"graphql-query-complexity": "^0.11.0",
"nestjs-pino": "^2.5.0",
"passport": "^0.5.2",
"passport-jwt": "^4.0.0",
"pg": "^8.7.3",
"pino-http": "^6.6.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.5.3"
},
"devDependencies": {
"@faker-js/faker": "^6.0.0-alpha.5",
"@nestjs/cli": "^8.2.0",
"@nestjs/schematics": "^8.0.0",
"@nestjs/testing": "^8.0.0",
"@serverless/typescript": "^3.2.0",
"@types/aws-lambda": "^8.10.92",
"@types/bcryptjs": "^2.4.2",
"@types/express": "^4.17.13",
"@types/jest": "27.4.0",
"@types/node": "^16.0.0",
"@types/passport-local": "^1.0.34",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"apollo-server-testing": "^2.25.3",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.5.1",
"npm-run-all": "^4.1.5",
"prettier": "^2.5.1",
"prisma": "^3.9.2",
"prisma-nestjs-graphql": "^14.6.1",
"serverless": "^3.2.1",
"serverless-offline": "^8.4.0",
"serverless-plugin-optimize": "^4.2.1-rc.1",
"serverless-plugin-warmup": "^7.0.2",
"source-map-support": "^0.5.21",
"supertest": "^6.2.2",
"ts-jest": "^27.1.3",
"ts-loader": "^9.2.3",
"ts-morph": "^13.0.3",
"ts-node": "^10.5.0",
"tsc-alias": "^1.5.0",
"tsconfig-paths": "^3.12.0",
"typescript": "^4.5.5",
"webpack": "^5.0.0"
}
jest.config.ts
module.exports = {
moduleFileExtensions: ['js', 'json', 'ts'],
testEnvironment: 'node',
transform: {
'^.+\.(t|j)s$': 'ts-jest',
},
testRegex: '.(spec|e2e-spec).ts$',
moduleNameMapper: {
'^@features/(.*)': '<rootDir>/src/features/',
'^@tests/(.*)': '<rootDir>/src/__tests/',
'^@graphql': '<rootDir>/src/@graphql/generated',
'^@types': '<rootDir>/src/@types',
'^@utils': '<rootDir>/src/utils',
'^@config': '<rootDir>/src/config',
},
testPathIgnorePatterns: [
'<rootDir>/dist/',
'<rootDir>/prisma/',
'<rootDir>/bin/',
'<rootDir>/node_modules/',
'<rootDir>/.github/',
],
};
graphql.e2e-spec.ts
import { GraphQLModule } from '@features/graphql/graphql.module';
import { INestApplication, ValidationPipe } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import superRequest, { SuperTest, Test as TestItem } from 'supertest';
describe('GraphQL - CommonModule (e2e)', () => {
let app: INestApplication;
let request: SuperTest<TestItem>;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [GraphQLModule],
}).compile();
app = moduleFixture.createNestApplication();
app.useGlobalPipes(new ValidationPipe());
await app.init();
request = superRequest(app.getHttpServer());
});
describe('Query - Test', () => {
it('should return the test query with typename TestSuccess (code: 200)', async () => {
return request
.post('/graphql')
.send({
query: `
query {
test {
__typename
}
}`,
})
.then((res) => {
expect(res.status).toBe(200);
expect(res.body.data.test.__typename).toBe('TestSuccess');
});
});
});
});
graphql.module.ts
import { config } from '@config';
import { AppService } from '@features/app.service';
import { GraphQLAuthModule } from '@features/graphql/auth/auth.module';
import { CommonModule } from '@features/graphql/common/common.module';
import { UserModule } from '@features/graphql/user/user.module';
import { GraphQLComplexityPlugin } from '@features/graphql/_plugins';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { Module } from '@nestjs/common';
import { GraphQLModule as NESTJSGraphQLModule } from '@nestjs/graphql';
import { join } from 'path';
@Module({
imports: [
GraphQLAuthModule,
NESTJSGraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
autoSchemaFile: join(process.cwd(), 'src/@graphql/schema.gql'),
sortSchema: true,
debug: config.graphql.isDebugEnabled,
introspection: true,
playground: config.graphql.isPlaygroundEnabled
? {
settings: { 'schema.polling.enable': false },
}
: false,
}),
UserModule,
CommonModule,
],
providers: [AppService, GraphQLComplexityPlugin],
})
export class GraphQLModule {
constructor(private readonly appService: AppService) {
if (!this.appService.checkEnv()) process.exit();
}
}
经过数小时的紧张编程... 终于找到问题了
如果您对导入使用某些“别名”,请小心,因为它可能会覆盖某些已使用的包。
在这里,我使用了 @graphql
别名,它破坏了我所有的测试。
当我删除它时,问题就消失了。
moduleNameMapper: {
'^@features/(.*)': '<rootDir>/src/features/',
'^@tests/(.*)': '<rootDir>/__tests/',
'^@utils': '<rootDir>/src/utils',
'^@config': '<rootDir>/src/config',
'^@types': '<rootDir>/src/@types',
'^@graphql': '<rootDir>/src/@graphql/generated', // to remove
},
至
moduleNameMapper: {
'^@features/(.*)': '<rootDir>/src/features/',
'^@tests/(.*)': '<rootDir>/__tests/',
'^@utils': '<rootDir>/src/utils',
'^@config': '<rootDir>/src/config',
'^@types': '<rootDir>/src/@types',
},