2023-09-05 11:01:45 +03:00
|
|
|
import { ok } from 'node:assert';
|
|
|
|
import { randomUUID } from 'node:crypto';
|
2023-04-19 02:14:25 +03:00
|
|
|
|
2023-06-21 09:08:32 +03:00
|
|
|
import { Transformer } from '@napi-rs/image';
|
2023-06-08 20:42:58 +03:00
|
|
|
import type { INestApplication } from '@nestjs/common';
|
2023-09-05 11:01:45 +03:00
|
|
|
import { hashSync } from '@node-rs/argon2';
|
2023-09-29 06:02:26 +03:00
|
|
|
import { type User } from '@prisma/client';
|
|
|
|
import ava, { type TestFn } from 'ava';
|
|
|
|
import type { Express } from 'express';
|
2023-04-19 02:14:25 +03:00
|
|
|
import request from 'supertest';
|
|
|
|
|
2023-09-15 10:34:14 +03:00
|
|
|
import { AppModule } from '../src/app';
|
2023-12-14 12:50:51 +03:00
|
|
|
import { FeatureManagementService } from '../src/modules/features';
|
2023-09-15 10:34:14 +03:00
|
|
|
import { PrismaService } from '../src/prisma/service';
|
2024-01-11 09:40:55 +03:00
|
|
|
import { createTestingApp } from './utils';
|
2023-04-19 02:14:25 +03:00
|
|
|
|
|
|
|
const gql = '/graphql';
|
|
|
|
|
2023-09-08 08:15:33 +03:00
|
|
|
const test = ava as TestFn<{
|
|
|
|
app: INestApplication;
|
|
|
|
}>;
|
2023-04-19 02:14:25 +03:00
|
|
|
|
2023-09-05 11:01:45 +03:00
|
|
|
class FakePrisma {
|
|
|
|
fakeUser: User = {
|
|
|
|
id: randomUUID(),
|
|
|
|
name: 'Alex Yang',
|
|
|
|
avatarUrl: '',
|
|
|
|
email: 'alex.yang@example.org',
|
|
|
|
password: hashSync('123456'),
|
|
|
|
emailVerified: new Date(),
|
|
|
|
createdAt: new Date(),
|
|
|
|
};
|
|
|
|
get user() {
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
|
|
const prisma = this;
|
|
|
|
return {
|
|
|
|
async findFirst() {
|
|
|
|
return prisma.fakeUser;
|
|
|
|
},
|
|
|
|
async findUnique() {
|
|
|
|
return this.findFirst();
|
|
|
|
},
|
|
|
|
async update() {
|
|
|
|
return this.findFirst();
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2023-04-28 06:49:44 +03:00
|
|
|
|
2023-09-08 08:15:33 +03:00
|
|
|
test.beforeEach(async t => {
|
2024-01-11 09:40:55 +03:00
|
|
|
const { app } = await createTestingApp({
|
2023-09-01 22:41:29 +03:00
|
|
|
imports: [AppModule],
|
2024-01-11 09:40:55 +03:00
|
|
|
tapModule(builder) {
|
|
|
|
builder
|
|
|
|
.overrideProvider(PrismaService)
|
|
|
|
.useClass(FakePrisma)
|
|
|
|
.overrideProvider(FeatureManagementService)
|
|
|
|
.useValue({ canEarlyAccess: () => true });
|
|
|
|
},
|
2023-04-19 02:14:25 +03:00
|
|
|
});
|
2024-01-11 09:40:55 +03:00
|
|
|
|
|
|
|
t.context.app = app;
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
2023-04-19 02:14:25 +03:00
|
|
|
|
2023-09-11 12:30:39 +03:00
|
|
|
test.afterEach.always(async t => {
|
2023-09-08 08:15:33 +03:00
|
|
|
await t.context.app.close();
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
2023-04-19 02:14:25 +03:00
|
|
|
|
2023-09-05 11:01:45 +03:00
|
|
|
test('should init app', async t => {
|
2023-09-08 08:15:33 +03:00
|
|
|
t.is(typeof t.context.app, 'object');
|
|
|
|
await request(t.context.app.getHttpServer())
|
2023-09-01 22:41:29 +03:00
|
|
|
.post(gql)
|
|
|
|
.send({
|
|
|
|
query: `
|
2023-04-28 02:02:05 +03:00
|
|
|
query {
|
|
|
|
error
|
|
|
|
}
|
|
|
|
`,
|
2023-09-01 22:41:29 +03:00
|
|
|
})
|
|
|
|
.expect(400);
|
2023-04-28 02:02:05 +03:00
|
|
|
|
2023-09-08 08:15:33 +03:00
|
|
|
const { token } = await createToken(t.context.app);
|
2023-04-28 02:02:05 +03:00
|
|
|
|
2023-09-08 08:15:33 +03:00
|
|
|
await request(t.context.app.getHttpServer())
|
2023-09-01 22:41:29 +03:00
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
|
|
|
.send({
|
|
|
|
query: `
|
2023-06-29 04:45:45 +03:00
|
|
|
query {
|
|
|
|
__typename
|
2023-04-19 02:14:25 +03:00
|
|
|
}
|
|
|
|
`,
|
2023-09-01 22:41:29 +03:00
|
|
|
})
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(res.body.data.__typename, 'Query');
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
});
|
2023-04-19 02:14:25 +03:00
|
|
|
|
2023-09-05 11:01:45 +03:00
|
|
|
test('should find default user', async t => {
|
2023-09-08 08:15:33 +03:00
|
|
|
const { token } = await createToken(t.context.app);
|
|
|
|
await request(t.context.app.getHttpServer())
|
2023-09-01 22:41:29 +03:00
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
|
|
|
.send({
|
|
|
|
query: `
|
2023-04-19 02:14:25 +03:00
|
|
|
query {
|
|
|
|
user(email: "alex.yang@example.org") {
|
2024-01-06 14:04:49 +03:00
|
|
|
... on UserType {
|
|
|
|
email
|
|
|
|
}
|
|
|
|
... on LimitedUserType {
|
|
|
|
email
|
|
|
|
}
|
2023-04-19 02:14:25 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
2023-09-01 22:41:29 +03:00
|
|
|
})
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(res.body.data.user.email, 'alex.yang@example.org');
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
|
|
|
});
|
2023-06-21 09:08:32 +03:00
|
|
|
|
2023-09-14 17:35:05 +03:00
|
|
|
test('should be able to upload avatar and remove it', async t => {
|
2023-09-08 08:15:33 +03:00
|
|
|
const { token, id } = await createToken(t.context.app);
|
2023-09-01 22:41:29 +03:00
|
|
|
const png = await Transformer.fromRgbaPixels(
|
|
|
|
Buffer.alloc(400 * 400 * 4).fill(255),
|
|
|
|
400,
|
|
|
|
400
|
|
|
|
).png();
|
2023-06-21 09:08:32 +03:00
|
|
|
|
2023-09-08 08:15:33 +03:00
|
|
|
await request(t.context.app.getHttpServer())
|
2023-09-01 22:41:29 +03:00
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
|
|
|
.field(
|
|
|
|
'operations',
|
|
|
|
JSON.stringify({
|
|
|
|
name: 'uploadAvatar',
|
2023-09-15 10:34:14 +03:00
|
|
|
query: `mutation uploadAvatar($avatar: Upload!) {
|
|
|
|
uploadAvatar(avatar: $avatar) {
|
2023-06-21 09:08:32 +03:00
|
|
|
id
|
|
|
|
name
|
|
|
|
avatarUrl
|
|
|
|
email
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
2023-09-01 22:41:29 +03:00
|
|
|
variables: { id, avatar: null },
|
|
|
|
})
|
|
|
|
)
|
|
|
|
.field('map', JSON.stringify({ '0': ['variables.avatar'] }))
|
|
|
|
.attach('0', png, 'avatar.png')
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
2023-09-05 11:01:45 +03:00
|
|
|
t.is(res.body.data.uploadAvatar.id, id);
|
2023-09-01 22:41:29 +03:00
|
|
|
});
|
2023-09-14 17:35:05 +03:00
|
|
|
|
|
|
|
await request(t.context.app.getHttpServer())
|
|
|
|
.post(gql)
|
|
|
|
.auth(token, { type: 'bearer' })
|
|
|
|
.set({ 'x-request-id': 'test', 'x-operation-name': 'test' })
|
|
|
|
.send({
|
|
|
|
query: `
|
|
|
|
mutation removeAvatar {
|
|
|
|
removeAvatar {
|
2023-09-15 10:34:14 +03:00
|
|
|
success
|
2023-09-14 17:35:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
2023-09-15 10:34:14 +03:00
|
|
|
t.is(res.body.data.removeAvatar.success, true);
|
2023-09-14 17:35:05 +03:00
|
|
|
});
|
2023-04-19 02:14:25 +03:00
|
|
|
});
|
2023-06-21 09:08:32 +03:00
|
|
|
|
|
|
|
async function createToken(app: INestApplication<Express>): Promise<{
|
|
|
|
id: string;
|
|
|
|
token: string;
|
|
|
|
}> {
|
|
|
|
let token;
|
|
|
|
let id;
|
|
|
|
await request(app.getHttpServer())
|
|
|
|
.post(gql)
|
|
|
|
.send({
|
|
|
|
query: `
|
|
|
|
mutation {
|
|
|
|
signIn(email: "alex.yang@example.org", password: "123456") {
|
|
|
|
id
|
|
|
|
token {
|
|
|
|
token
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
.expect(200)
|
|
|
|
.expect(res => {
|
|
|
|
id = res.body.data.signIn.id;
|
|
|
|
ok(
|
|
|
|
typeof res.body.data.signIn.token.token === 'string',
|
|
|
|
'res.body.data.signIn.token.token is not a string'
|
|
|
|
);
|
|
|
|
token = res.body.data.signIn.token.token;
|
|
|
|
});
|
|
|
|
return { token: token!, id: id! };
|
|
|
|
}
|