@lenne.tech/nest-server 8.6.3 → 8.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.env.js +4 -2
- package/dist/config.env.js.map +1 -1
- package/dist/core/common/decorators/restricted.decorator.js +4 -4
- package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
- package/dist/core/common/helpers/file.helper.js +4 -7
- package/dist/core/common/helpers/file.helper.js.map +1 -1
- package/dist/core/common/helpers/filter.helper.d.ts +7 -0
- package/dist/core/common/helpers/filter.helper.js +38 -1
- package/dist/core/common/helpers/filter.helper.js.map +1 -1
- package/dist/core/common/helpers/input.helper.d.ts +6 -0
- package/dist/core/common/helpers/input.helper.js +28 -6
- package/dist/core/common/helpers/input.helper.js.map +1 -1
- package/dist/core/common/helpers/service.helper.js +3 -5
- package/dist/core/common/helpers/service.helper.js.map +1 -1
- package/dist/core/common/inputs/filter.input.js.map +1 -1
- package/dist/core/common/interfaces/server-options.interface.d.ts +16 -13
- package/dist/core/common/models/core-model.model.js +4 -1
- package/dist/core/common/models/core-model.model.js.map +1 -1
- package/dist/core/common/services/crud.service.js +9 -4
- package/dist/core/common/services/crud.service.js.map +1 -1
- package/dist/core/common/services/module.service.js +1 -1
- package/dist/core/common/services/module.service.js.map +1 -1
- package/dist/core/modules/auth/guards/roles.guard.js +2 -1
- package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
- package/dist/core/modules/user/core-user.service.js +9 -13
- package/dist/core/modules/user/core-user.service.js.map +1 -1
- package/dist/core.module.d.ts +3 -2
- package/dist/core.module.js +26 -4
- package/dist/core.module.js.map +1 -1
- package/dist/main.js +13 -0
- package/dist/main.js.map +1 -1
- package/dist/server/modules/auth/auth.module.js +1 -2
- package/dist/server/modules/auth/auth.module.js.map +1 -1
- package/dist/server/modules/file/file.controller.js +1 -1
- package/dist/server/modules/file/file.controller.js.map +1 -1
- package/dist/server/modules/file/file.resolver.d.ts +5 -0
- package/dist/server/modules/file/file.resolver.js +51 -0
- package/dist/server/modules/file/file.resolver.js.map +1 -0
- package/dist/server/modules/user/user.model.d.ts +1 -1
- package/dist/server/modules/user/user.resolver.js +2 -1
- package/dist/server/modules/user/user.resolver.js.map +1 -1
- package/dist/server/modules/user/user.service.js +1 -1
- package/dist/server/modules/user/user.service.js.map +1 -1
- package/dist/server/server.module.js +3 -1
- package/dist/server/server.module.js.map +1 -1
- package/dist/test/test.helper.d.ts +4 -1
- package/dist/test/test.helper.js +51 -25
- package/dist/test/test.helper.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +33 -28
- package/src/config.env.ts +4 -2
- package/src/core/common/decorators/restricted.decorator.ts +1 -2
- package/src/core/common/helpers/file.helper.ts +9 -11
- package/src/core/common/helpers/filter.helper.ts +66 -1
- package/src/core/common/helpers/input.helper.ts +61 -2
- package/src/core/common/helpers/service.helper.ts +2 -6
- package/src/core/common/inputs/filter.input.ts +0 -1
- package/src/core/common/interfaces/server-options.interface.ts +68 -52
- package/src/core/common/models/core-model.model.ts +4 -1
- package/src/core/common/services/crud.service.ts +7 -4
- package/src/core/common/services/module.service.ts +0 -1
- package/src/core/modules/auth/guards/roles.guard.ts +1 -1
- package/src/core/modules/user/core-user.service.ts +13 -22
- package/src/core.module.ts +38 -6
- package/src/main.ts +16 -0
- package/src/server/modules/auth/auth.module.ts +1 -2
- package/src/server/modules/file/file.controller.ts +1 -1
- package/src/server/modules/file/file.resolver.ts +55 -0
- package/src/server/modules/user/user.resolver.ts +1 -1
- package/src/server/modules/user/user.service.ts +1 -1
- package/src/server/server.module.ts +5 -1
- package/src/test/test.helper.ts +92 -34
|
@@ -3,6 +3,7 @@ import * as bcrypt from 'bcrypt';
|
|
|
3
3
|
import * as crypto from 'crypto';
|
|
4
4
|
import { Document, Model } from 'mongoose';
|
|
5
5
|
import { merge } from '../../common/helpers/config.helper';
|
|
6
|
+
import { assignPlain } from '../../common/helpers/input.helper';
|
|
6
7
|
import { ServiceOptions } from '../../common/interfaces/service-options.interface';
|
|
7
8
|
import { CrudService } from '../../common/services/crud.service';
|
|
8
9
|
import { EmailService } from '../../common/services/email.service';
|
|
@@ -39,9 +40,12 @@ export abstract class CoreUserService<
|
|
|
39
40
|
return this.process(
|
|
40
41
|
async (data) => {
|
|
41
42
|
// Create user with verification token
|
|
43
|
+
const currentUserId = serviceOptions?.currentUser?._id;
|
|
42
44
|
const createdUser = new this.mainDbModel({
|
|
43
45
|
...data.input,
|
|
44
46
|
verificationToken: crypto.randomBytes(32).toString('hex'),
|
|
47
|
+
createdBy: currentUserId,
|
|
48
|
+
updatedBy: currentUserId,
|
|
45
49
|
});
|
|
46
50
|
|
|
47
51
|
// Distinguish between different error messages when saving
|
|
@@ -105,21 +109,15 @@ export abstract class CoreUserService<
|
|
|
105
109
|
}
|
|
106
110
|
return this.process(
|
|
107
111
|
async () => {
|
|
108
|
-
// Update user
|
|
109
|
-
await
|
|
110
|
-
verified: true,
|
|
111
|
-
verificationToken: null,
|
|
112
|
-
}).save();
|
|
113
|
-
|
|
114
|
-
// Return prepared user
|
|
115
|
-
return dbObject;
|
|
112
|
+
// Update and return user
|
|
113
|
+
return await assignPlain(dbObject, { verified: true, verificationToken: null }).save();
|
|
116
114
|
},
|
|
117
115
|
{ dbObject, serviceOptions }
|
|
118
116
|
);
|
|
119
117
|
}
|
|
120
118
|
|
|
121
119
|
/**
|
|
122
|
-
* Set
|
|
120
|
+
* Set new password for user with token
|
|
123
121
|
*/
|
|
124
122
|
async resetPassword(token: string, newPassword: string, serviceOptions?: ServiceOptions): Promise<TUser> {
|
|
125
123
|
// Get user
|
|
@@ -130,14 +128,11 @@ export abstract class CoreUserService<
|
|
|
130
128
|
|
|
131
129
|
return this.process(
|
|
132
130
|
async () => {
|
|
133
|
-
// Update user
|
|
134
|
-
await
|
|
131
|
+
// Update and return user
|
|
132
|
+
return await assignPlain(dbObject, {
|
|
135
133
|
password: await bcrypt.hash(newPassword, 10),
|
|
136
134
|
passwordResetToken: null,
|
|
137
135
|
}).save();
|
|
138
|
-
|
|
139
|
-
// Return user
|
|
140
|
-
return dbObject;
|
|
141
136
|
},
|
|
142
137
|
{ dbObject, serviceOptions }
|
|
143
138
|
);
|
|
@@ -154,13 +149,9 @@ export abstract class CoreUserService<
|
|
|
154
149
|
}
|
|
155
150
|
return this.process(
|
|
156
151
|
async () => {
|
|
157
|
-
// Set reset token
|
|
158
|
-
|
|
159
|
-
dbObject.
|
|
160
|
-
await dbObject.save();
|
|
161
|
-
|
|
162
|
-
// Return user
|
|
163
|
-
return dbObject;
|
|
152
|
+
// Set reset token and return
|
|
153
|
+
dbObject.passwordResetToken = crypto.randomBytes(32).toString('hex');
|
|
154
|
+
return await dbObject.save();
|
|
164
155
|
},
|
|
165
156
|
{ dbObject, serviceOptions }
|
|
166
157
|
);
|
|
@@ -182,7 +173,7 @@ export abstract class CoreUserService<
|
|
|
182
173
|
|
|
183
174
|
// Update and return user
|
|
184
175
|
return this.process(
|
|
185
|
-
async (
|
|
176
|
+
async () => {
|
|
186
177
|
return await this.mainDbModel.findByIdAndUpdate(userId, { roles }).exec();
|
|
187
178
|
},
|
|
188
179
|
{ serviceOptions }
|
package/src/core.module.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
|
2
|
+
import { DynamicModule, Global, MiddlewareConsumer, Module, NestModule, UnauthorizedException } from '@nestjs/common';
|
|
2
3
|
import { APP_PIPE } from '@nestjs/core';
|
|
3
4
|
import { GraphQLModule } from '@nestjs/graphql';
|
|
5
|
+
import { MongooseModule } from '@nestjs/mongoose';
|
|
6
|
+
import { Context } from 'apollo-server-core';
|
|
7
|
+
import { graphqlUploadExpress } from 'graphql-upload';
|
|
4
8
|
import { merge } from './core/common/helpers/config.helper';
|
|
5
9
|
import { IServerOptions } from './core/common/interfaces/server-options.interface';
|
|
6
10
|
import { MapAndValidatePipe } from './core/common/pipes/map-and-validate.pipe';
|
|
7
11
|
import { ConfigService } from './core/common/services/config.service';
|
|
8
12
|
import { EmailService } from './core/common/services/email.service';
|
|
9
|
-
import { TemplateService } from './core/common/services/template.service';
|
|
10
|
-
import { MongooseModule } from '@nestjs/mongoose';
|
|
11
13
|
import { MailjetService } from './core/common/services/mailjet.service';
|
|
12
|
-
import {
|
|
14
|
+
import { TemplateService } from './core/common/services/template.service';
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* Core module (dynamic)
|
|
@@ -26,7 +28,13 @@ import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
|
|
26
28
|
*/
|
|
27
29
|
@Global()
|
|
28
30
|
@Module({})
|
|
29
|
-
export class CoreModule {
|
|
31
|
+
export class CoreModule implements NestModule {
|
|
32
|
+
/**
|
|
33
|
+
* Integrate middleware, e.g. GraphQL upload handing for express
|
|
34
|
+
*/
|
|
35
|
+
configure(consumer: MiddlewareConsumer) {
|
|
36
|
+
consumer.apply(graphqlUploadExpress()).forRoutes('graphql');
|
|
37
|
+
}
|
|
30
38
|
/**
|
|
31
39
|
* Dynamic module
|
|
32
40
|
* see https://docs.nestjs.com/modules#dynamic-modules
|
|
@@ -66,6 +74,28 @@ export class CoreModule {
|
|
|
66
74
|
}
|
|
67
75
|
},
|
|
68
76
|
},
|
|
77
|
+
'graphql-ws': {
|
|
78
|
+
onConnect: async (context: Context<any>) => {
|
|
79
|
+
const { connectionParams, extra } = context;
|
|
80
|
+
if (config.graphQl.enableSubscriptionAuth) {
|
|
81
|
+
// get authToken from authorization header
|
|
82
|
+
const authToken: string =
|
|
83
|
+
'Authorization' in connectionParams && connectionParams?.Authorization?.split(' ')[1];
|
|
84
|
+
if (authToken) {
|
|
85
|
+
// verify authToken/getJwtPayLoad
|
|
86
|
+
const payload = authService.decodeJwt(authToken);
|
|
87
|
+
const user = await authService.validateUser(payload);
|
|
88
|
+
// the user/jwtPayload object found will be available as context.currentUser/jwtPayload in your GraphQL resolvers
|
|
89
|
+
extra.user = user;
|
|
90
|
+
extra.header = connectionParams;
|
|
91
|
+
return extra;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
throw new UnauthorizedException();
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
context: ({ extra }) => extra,
|
|
98
|
+
},
|
|
69
99
|
},
|
|
70
100
|
},
|
|
71
101
|
options?.graphQl?.driver
|
|
@@ -113,7 +143,9 @@ export class CoreModule {
|
|
|
113
143
|
module: CoreModule,
|
|
114
144
|
imports: [
|
|
115
145
|
MongooseModule.forRoot(config.mongoose.uri, config.mongoose.options),
|
|
116
|
-
GraphQLModule.forRootAsync<ApolloDriverConfig>(
|
|
146
|
+
GraphQLModule.forRootAsync<ApolloDriverConfig>(
|
|
147
|
+
Object.assign({ driver: ApolloDriver }, config.graphQl.driver, config.graphQl.options)
|
|
148
|
+
),
|
|
117
149
|
],
|
|
118
150
|
providers,
|
|
119
151
|
exports: [ConfigService, EmailService, TemplateService, MailjetService],
|
package/src/main.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NestFactory } from '@nestjs/core';
|
|
2
2
|
import { NestExpressApplication } from '@nestjs/platform-express';
|
|
3
|
+
import { exec } from 'child_process';
|
|
3
4
|
import envConfig from './config.env';
|
|
4
5
|
import { ServerModule } from './server/server.module';
|
|
5
6
|
|
|
@@ -25,6 +26,21 @@ async function bootstrap() {
|
|
|
25
26
|
|
|
26
27
|
// Start server on configured port
|
|
27
28
|
await server.listen(envConfig.port);
|
|
29
|
+
|
|
30
|
+
// Run command after server init
|
|
31
|
+
if (envConfig.execAfterInit) {
|
|
32
|
+
exec(envConfig.execAfterInit, (error, stdout, stderr) => {
|
|
33
|
+
if (error) {
|
|
34
|
+
console.error(`error: ${error.message}`);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (stderr) {
|
|
39
|
+
console.error(`stderr: ${stderr}`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
28
44
|
}
|
|
29
45
|
|
|
30
46
|
// Start server
|
|
@@ -27,9 +27,8 @@ export class AuthModule {
|
|
|
27
27
|
// providers: [] // Integrate additional Providers here to resolve dependencies
|
|
28
28
|
},
|
|
29
29
|
}),
|
|
30
|
-
EmailService,
|
|
31
30
|
],
|
|
32
|
-
providers: [AuthResolver, AuthService],
|
|
31
|
+
providers: [AuthResolver, AuthService, EmailService],
|
|
33
32
|
exports: [AuthResolver, CoreAuthModule],
|
|
34
33
|
};
|
|
35
34
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
|
2
|
+
import { createWriteStream } from 'fs';
|
|
3
|
+
import { FileUpload, GraphQLUpload } from 'graphql-upload';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* File resolver
|
|
7
|
+
*/
|
|
8
|
+
@Resolver()
|
|
9
|
+
export class FileResolver {
|
|
10
|
+
/**
|
|
11
|
+
* Upload file
|
|
12
|
+
*/
|
|
13
|
+
@Mutation(() => Boolean)
|
|
14
|
+
async uploadFile(
|
|
15
|
+
@Args({ name: 'file', type: () => GraphQLUpload })
|
|
16
|
+
file: FileUpload
|
|
17
|
+
) {
|
|
18
|
+
console.log(JSON.stringify(file, null, 2));
|
|
19
|
+
/*
|
|
20
|
+
const {filename, mimetype, encoding, createReadStream} = file;
|
|
21
|
+
await new Promise((resolve, reject) =>
|
|
22
|
+
createReadStream()
|
|
23
|
+
.pipe(createWriteStream(`./uploads/${filename}`))
|
|
24
|
+
.on('finish', () => resolve(true))
|
|
25
|
+
.on('error', (error) => reject(error))
|
|
26
|
+
);
|
|
27
|
+
*/
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Upload files
|
|
33
|
+
*/
|
|
34
|
+
@Mutation(() => Boolean)
|
|
35
|
+
async uploadFiles(
|
|
36
|
+
@Args({ name: 'files', type: () => [GraphQLUpload] })
|
|
37
|
+
files: FileUpload[]
|
|
38
|
+
) {
|
|
39
|
+
const promises: Promise<any>[] = [];
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
console.log(JSON.stringify(await file, null, 2));
|
|
42
|
+
/*
|
|
43
|
+
const {filename, mimetype, encoding, createReadStream} = await file
|
|
44
|
+
promises.push(new Promise((resolve, reject) =>
|
|
45
|
+
createReadStream()
|
|
46
|
+
.pipe(createWriteStream(`./uploads/${filename}`))
|
|
47
|
+
.on('finish', () => resolve(true))
|
|
48
|
+
.on('error', (error) => reject(error))
|
|
49
|
+
));
|
|
50
|
+
*/
|
|
51
|
+
}
|
|
52
|
+
await Promise.all(promises);
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -145,7 +145,7 @@ export class UserResolver {
|
|
|
145
145
|
*/
|
|
146
146
|
@Subscription(() => User, {
|
|
147
147
|
filter(this: UserResolver, payload, variables, context) {
|
|
148
|
-
return context
|
|
148
|
+
return context?.user?.hasRole?.(RoleEnum.ADMIN);
|
|
149
149
|
},
|
|
150
150
|
resolve: (user) => user,
|
|
151
151
|
})
|
|
@@ -50,7 +50,7 @@ export class UserService extends CoreUserService<User, UserInput, UserCreateInpu
|
|
|
50
50
|
// and could not exist as currentUser before
|
|
51
51
|
if (!user.createdBy) {
|
|
52
52
|
await this.mainDbModel.findByIdAndUpdate(user.id, { createdBy: user.id });
|
|
53
|
-
user = await this.get(user.id, { ...serviceOptions, currentUser: serviceOptions
|
|
53
|
+
user = await this.get(user.id, { ...serviceOptions, currentUser: serviceOptions?.currentUser || user });
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// Publish action
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { Module } from '@nestjs/common';
|
|
2
2
|
import envConfig from '../config.env';
|
|
3
3
|
import { CoreModule } from '../core.module';
|
|
4
|
+
import { CoreAuthService } from '../core/modules/auth/services/core-auth.service';
|
|
4
5
|
import { AuthModule } from './modules/auth/auth.module';
|
|
5
6
|
import { FileController } from './modules/file/file.controller';
|
|
7
|
+
import { FileResolver } from './modules/file/file.resolver';
|
|
6
8
|
import { ServerController } from './server.controller';
|
|
7
|
-
import { CoreAuthService } from '../core/modules/auth/services/core-auth.service';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Server module (dynamic)
|
|
@@ -26,6 +27,9 @@ import { CoreAuthService } from '../core/modules/auth/services/core-auth.service
|
|
|
26
27
|
// Include REST controllers
|
|
27
28
|
controllers: [FileController, ServerController],
|
|
28
29
|
|
|
30
|
+
// Include resolvers, services and other providers
|
|
31
|
+
providers: [FileResolver],
|
|
32
|
+
|
|
29
33
|
// Export modules for reuse in other modules
|
|
30
34
|
exports: [CoreModule, AuthModule],
|
|
31
35
|
})
|
package/src/test/test.helper.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { INestApplication } from '@nestjs/common';
|
|
2
|
-
|
|
2
|
+
import { createClient } from 'graphql-ws';
|
|
3
3
|
import { jsonToGraphQLQuery } from 'json-to-graphql-query';
|
|
4
4
|
import * as LightMyRequest from 'light-my-request';
|
|
5
5
|
import * as supertest from 'supertest';
|
|
6
6
|
import * as util from 'util';
|
|
7
|
+
import * as ws from 'ws';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* GraphQL request type
|
|
@@ -64,6 +65,11 @@ export interface TestGraphQLOptions {
|
|
|
64
65
|
*/
|
|
65
66
|
convertEnums?: boolean | string[];
|
|
66
67
|
|
|
68
|
+
/**
|
|
69
|
+
* Count of subscription messages, specifies how many messages are to be received on subscription
|
|
70
|
+
*/
|
|
71
|
+
countOfSubscriptionMessages?: number;
|
|
72
|
+
|
|
67
73
|
/**
|
|
68
74
|
* Print console logs
|
|
69
75
|
*/
|
|
@@ -104,33 +110,35 @@ export class TestHelper {
|
|
|
104
110
|
// app: FastifyInstance | INestApplication;
|
|
105
111
|
app: INestApplication;
|
|
106
112
|
|
|
113
|
+
// URL with port and directory to subscription endpoint
|
|
114
|
+
// e.g.: ws://localhost:3030/graphql
|
|
115
|
+
subscriptionUrl: string;
|
|
116
|
+
|
|
107
117
|
/**
|
|
108
118
|
* Constructor
|
|
109
119
|
*/
|
|
110
|
-
constructor(app: any) {
|
|
120
|
+
constructor(app: any, subscriptionUrl?: string) {
|
|
111
121
|
this.app = app;
|
|
122
|
+
this.subscriptionUrl = subscriptionUrl;
|
|
112
123
|
}
|
|
113
124
|
|
|
114
125
|
/**
|
|
115
126
|
* GraphQL request
|
|
116
|
-
* @param graphql
|
|
117
|
-
* @param options
|
|
118
127
|
*/
|
|
119
128
|
async graphQl(graphql: string | TestGraphQLConfig, options: TestGraphQLOptions = {}): Promise<any> {
|
|
120
129
|
// Default options
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
130
|
+
const config = {
|
|
131
|
+
convertEnums: true,
|
|
132
|
+
countOfSubscriptionMessages: 1,
|
|
133
|
+
token: null,
|
|
134
|
+
statusCode: 200,
|
|
135
|
+
log: false,
|
|
136
|
+
logError: false,
|
|
137
|
+
...options,
|
|
138
|
+
};
|
|
131
139
|
|
|
132
140
|
// Init vars
|
|
133
|
-
const { token, statusCode, log, logError } =
|
|
141
|
+
const { token, statusCode, log, logError } = config;
|
|
134
142
|
|
|
135
143
|
// Init
|
|
136
144
|
let query = '';
|
|
@@ -174,10 +182,14 @@ export class TestHelper {
|
|
|
174
182
|
query = jsonToGraphQLQuery(queryObj, { pretty: true });
|
|
175
183
|
}
|
|
176
184
|
|
|
185
|
+
if ((graphql as TestGraphQLConfig).type === TestGraphQLType.SUBSCRIPTION) {
|
|
186
|
+
return this.getSubscription(graphql as TestGraphQLConfig, query, config);
|
|
187
|
+
}
|
|
188
|
+
|
|
177
189
|
// Convert uppercase strings in arguments of query to enums
|
|
178
|
-
if (
|
|
179
|
-
if (Array.isArray(
|
|
180
|
-
for (const key of Object.values(
|
|
190
|
+
if (config.convertEnums) {
|
|
191
|
+
if (Array.isArray(config.convertEnums)) {
|
|
192
|
+
for (const key of Object.values(config.convertEnums)) {
|
|
181
193
|
const regExpStr = '(' + key + ': )\\"([_A-Z][_0-9A-Z]*)\\"';
|
|
182
194
|
const regExp = new RegExp(regExpStr, 'g');
|
|
183
195
|
query = query.replace(regExp, '$1$2');
|
|
@@ -225,28 +237,26 @@ export class TestHelper {
|
|
|
225
237
|
*/
|
|
226
238
|
async rest(url: string, options: TestRestOptions = {}): Promise<any> {
|
|
227
239
|
// Default options
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
options
|
|
238
|
-
);
|
|
240
|
+
const config: TestRestOptions = {
|
|
241
|
+
token: null,
|
|
242
|
+
statusCode: 200,
|
|
243
|
+
log: false,
|
|
244
|
+
logError: false,
|
|
245
|
+
payload: null,
|
|
246
|
+
method: 'GET',
|
|
247
|
+
...options,
|
|
248
|
+
};
|
|
239
249
|
|
|
240
250
|
// Init vars
|
|
241
|
-
const { token, statusCode, log, logError } =
|
|
251
|
+
const { token, statusCode, log, logError } = config;
|
|
242
252
|
|
|
243
253
|
// Request configuration
|
|
244
254
|
const requestConfig: LightMyRequest.InjectOptions = {
|
|
245
|
-
method:
|
|
255
|
+
method: config.method,
|
|
246
256
|
url,
|
|
247
257
|
};
|
|
248
|
-
if (
|
|
249
|
-
requestConfig.payload =
|
|
258
|
+
if (config.payload) {
|
|
259
|
+
requestConfig.payload = config.payload;
|
|
250
260
|
}
|
|
251
261
|
|
|
252
262
|
// Process response
|
|
@@ -354,7 +364,7 @@ export class TestHelper {
|
|
|
354
364
|
|
|
355
365
|
// Log response
|
|
356
366
|
if (log) {
|
|
357
|
-
console.log(response);
|
|
367
|
+
console.log(JSON.stringify(response, null, 2));
|
|
358
368
|
}
|
|
359
369
|
|
|
360
370
|
// Log error
|
|
@@ -373,4 +383,52 @@ export class TestHelper {
|
|
|
373
383
|
// Return response
|
|
374
384
|
return response;
|
|
375
385
|
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Get subscription
|
|
389
|
+
*/
|
|
390
|
+
async getSubscription(graphql: TestGraphQLConfig, query: string, options?: TestGraphQLOptions) {
|
|
391
|
+
// Check url
|
|
392
|
+
if (!this.subscriptionUrl) {
|
|
393
|
+
throw new Error("Missing subscriptionUrl in TestHelper: new TestHelper(app, 'ws://localhost:3030/graphql')");
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Prepare subscription
|
|
397
|
+
let connectionParams;
|
|
398
|
+
if (options?.token) {
|
|
399
|
+
connectionParams = { Authorization: `Bearer ${options?.token}` };
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Init client
|
|
403
|
+
if (options.log) {
|
|
404
|
+
console.log('Subscription query', JSON.stringify(query, null, 2));
|
|
405
|
+
}
|
|
406
|
+
const client = createClient({ url: this.subscriptionUrl, connectionParams, webSocketImpl: ws });
|
|
407
|
+
const messages: any[] = [];
|
|
408
|
+
let unsubscribe: () => void;
|
|
409
|
+
const onNext = (message) => {
|
|
410
|
+
if (options.log) {
|
|
411
|
+
console.log('Subscription message', JSON.stringify(message, null, 2));
|
|
412
|
+
}
|
|
413
|
+
messages.push(message?.data?.[graphql.name]);
|
|
414
|
+
if (messages.length <= options.countOfSubscriptionMessages) {
|
|
415
|
+
unsubscribe();
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
// Subscribe
|
|
420
|
+
await new Promise((resolve, reject) => {
|
|
421
|
+
unsubscribe = client.subscribe(
|
|
422
|
+
{ query },
|
|
423
|
+
{
|
|
424
|
+
next: onNext,
|
|
425
|
+
error: reject,
|
|
426
|
+
complete: resolve as any,
|
|
427
|
+
}
|
|
428
|
+
);
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
// Return subscribed messages
|
|
432
|
+
return messages;
|
|
433
|
+
}
|
|
376
434
|
}
|