Fix tests

This commit is contained in:
Charles Bochet
2023-04-24 15:00:37 +02:00
parent 6d2c8bbdf9
commit 29b6109e54
13 changed files with 366 additions and 768 deletions

943
server/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@
"@nestjs/serve-static": "^3.0.0",
"@nestjs/terminus": "^9.2.2",
"@prisma/client": "^4.13.0",
"jest-mock-extended": "^3.0.4",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0"

View File

@ -13,4 +13,8 @@ describe('AppController', () => {
appController = app.get<AppController>(AppController);
});
it('should be defined', () => {
expect(appController).toBeDefined();
});
});

View File

@ -6,16 +6,17 @@ import { TerminusModule } from '@nestjs/terminus';
import { HasuraModule } from '@golevelup/nestjs-hasura';
import { UserService } from './user/user.service';
import { UserModule } from './user/user.module';
const path = require('path');
@Module({
imports: [UserModule, TerminusModule, HasuraModule.forRoot(HasuraModule, {
webhookConfig: {
secretFactory: process.env.HASURA_EVENT_HANDLER_SECRET_HEADER,
secretHeader: 'secret-header',
},
})
],
imports: [
UserModule,
TerminusModule,
HasuraModule.forRoot(HasuraModule, {
webhookConfig: {
secretFactory: process.env.HASURA_EVENT_HANDLER_SECRET_HEADER,
secretHeader: 'secret-header',
},
}),
],
controllers: [AppController, HealthController],
providers: [AppService, UserService],
})

View File

@ -0,0 +1,16 @@
import { PrismaClient } from '@prisma/client';
import { mockDeep, DeepMockProxy } from 'jest-mock-extended';
export type Context = {
prisma: PrismaClient;
};
export type MockContext = {
prisma: DeepMockProxy<PrismaClient>;
};
export const createMockContext = (): MockContext => {
return {
prisma: mockDeep<PrismaClient>(),
};
};

View File

@ -5,4 +5,4 @@ import { PrismaService } from './prisma.service';
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}
export class PrismaModule {}

View File

@ -12,4 +12,4 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
await app.close();
});
}
}
}

View File

@ -8,22 +8,22 @@ datasource db {
}
model WorkspaceMember {
id Int @id @default(autoincrement())
id Int @id @default(autoincrement())
created_at DateTime @default(now())
updated_at DateTime @updatedAt
deleted_at DateTime?
user_id String @unique
user_id String @unique
workspace_id Int
@@map("workspace_members")
}
model Workspace {
id Int @id @default(autoincrement())
id Int @id @default(autoincrement())
created_at DateTime @default(now())
updated_at DateTime @updatedAt
deleted_at DateTime?
domain_name String @unique
domain_name String @unique
display_name String
@@map("workspaces")

View File

@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import { Prisma, WorkspaceMember } from '@prisma/client';
import { PrismaService } from 'src/database/prisma.service';
import { PrismaService } from '../database/prisma.service';
@Injectable()
export class UserRepository {
@ -8,7 +8,8 @@ export class UserRepository {
async upsertWorkspaceMember(params: { data: Prisma.WorkspaceMemberCreateInput }): Promise<WorkspaceMember> {
const { data } = params;
return this.prisma.workspaceMember.upsert({
return await this.prisma.workspaceMember.upsert({
where: {
user_id: data.user_id,
},

View File

@ -1,18 +1,104 @@
import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';
import { UserRepository } from './user.repository';
import { WorkspaceRepository } from './workspace.repository';
import { PrismaService } from '../database/prisma.service';
import {
MockContext,
createMockContext,
} from '../database/client-mock/context';
import { DeepMockProxy } from 'jest-mock-extended';
describe('UserService', () => {
let mockCtx: MockContext;
let service: UserService;
let mockedPrismaService: DeepMockProxy<PrismaService>;
beforeEach(async () => {
mockCtx = createMockContext();
const module: TestingModule = await Test.createTestingModule({
providers: [UserService],
}).compile();
providers: [
UserService,
UserRepository,
WorkspaceRepository,
PrismaService,
],
})
.overrideProvider(PrismaService)
.useValue(mockCtx.prisma)
.compile();
service = module.get<UserService>(UserService);
mockedPrismaService =
module.get<DeepMockProxy<PrismaService>>(PrismaService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
it('upsertWorkspaceMember should not upsert if email is absent', () => {
service.handleUserCreated({
event: {
data: { new: { id: 1, email: ''}, old: null },
session_variables: {},
op: 'INSERT'
},
id: '1',
table: { schema: 'auth', name: 'users' },
trigger: { name: 'user-created' },
delivery_info: { current_retry: 0, max_retries: 0},
created_at: '2021-03-01T00:00:00.000Z',
});
expect(mockedPrismaService.workspace.findUnique).toHaveBeenCalledTimes(0);
});
it('upsertWorkspaceMember should upsert if domain name is found from email', async () => {
mockedPrismaService.workspace.findUnique.mockResolvedValue({
id: 2,
display_name: 'test',
domain_name: 'domain.namexxx',
created_at: new Date(),
updated_at: new Date(),
deleted_at: null,
});
mockedPrismaService.workspaceMember.upsert.mockResolvedValue({
id: 1,
user_id: '1',
workspace_id: 1,
created_at: new Date(),
updated_at: new Date(),
deleted_at: null,
});
await service.handleUserCreated({
event: {
data: { new: { id: 1, email: 'test@domain.name' }, old: null },
session_variables: {},
op: 'INSERT',
},
id: '1',
table: { schema: 'auth', name: 'users' },
trigger: { name: 'user-created' },
delivery_info: { current_retry: 0, max_retries: 0 },
created_at: '2021-03-01T00:00:00.000Z',
});
expect(mockedPrismaService.workspace.findUnique).toHaveBeenCalledWith({
where: { domain_name: 'domain.name' },
});
expect(mockedPrismaService.workspaceMember.upsert).toHaveBeenCalledWith(
{
where: {
user_id: '1',
},
create: {
user_id: '1',
workspace_id: 2,
},
update: {},
},
);
});
});

View File

@ -1,5 +1,8 @@
import { HasuraInsertEvent, TrackedHasuraEventHandler } from '@golevelup/nestjs-hasura';
import { UserRepository} from "./user.repository"
import {
HasuraInsertEvent,
TrackedHasuraEventHandler,
} from '@golevelup/nestjs-hasura';
import { UserRepository } from './user.repository';
import { Injectable, Response } from '@nestjs/common';
import { WorkspaceRepository } from './workspace.repository';
import { response } from 'express';
@ -11,7 +14,10 @@ interface User {
@Injectable()
export class UserService {
constructor(private repository: UserRepository, private workspaceRepository: WorkspaceRepository) {}
constructor(
private repository: UserRepository,
private workspaceRepository: WorkspaceRepository,
) {}
@TrackedHasuraEventHandler({
triggerName: 'user-created',
@ -20,11 +26,15 @@ export class UserService {
definition: { type: 'insert' },
})
async handleUserCreated(evt: HasuraInsertEvent<User>) {
const workspace = await this.workspaceRepository.findWorkspaceByDomainName(
{ where: { domain_name:evt.event.data.new.email.split('@')[1] }
});
const emailDomain = evt.event.data.new.email.split('@')[1];
console.log(workspace)
if (!emailDomain) {
return;
}
const workspace = await this.workspaceRepository.findWorkspaceByDomainName({
where: { domain_name: emailDomain },
});
if (!workspace) {
return;
@ -37,4 +47,4 @@ export class UserService {
},
});
}
}
}

View File

@ -1,12 +1,14 @@
import { Injectable } from '@nestjs/common';
import { Prisma, Workspace } from '@prisma/client';
import { PrismaService } from 'src/database/prisma.service';
import { PrismaService } from '../database/prisma.service';
@Injectable()
export class WorkspaceRepository {
constructor(private prisma: PrismaService) {}
constructor(private prisma: PrismaService) {}
async findWorkspaceByDomainName(data: Prisma.WorkspaceFindUniqueArgs): Promise<Workspace> {
return this.prisma.workspace.findUnique(data);
}
}
async findWorkspaceByDomainName(
data: Prisma.WorkspaceFindUniqueArgs,
): Promise<Workspace | null> {
return await this.prisma.workspace.findUnique(data);
}
}

View File

@ -12,10 +12,10 @@
"baseUrl": "./",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"strictNullChecks": true,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false
"noFallthroughCasesInSwitch": false,
}
}