fix: display platform registration errors inside the creation modal

This commit is contained in:
2026-09-29 13:28:31 +09:00
parent 763ff22284
commit 7c3f7c8dc1
2 changed files with 63 additions and 4 deletions
+6 -4
View File
@@ -2178,9 +2178,7 @@ export class InstructorService {
organizationId, organizationId,
organizationName, organizationName,
), ),
displayName: { platformId: masterPlatform.id,
startsWith: baseName,
},
}, },
select: { select: {
displayName: true, displayName: true,
@@ -2227,7 +2225,11 @@ export class InstructorService {
}); });
} catch (error) { } catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') { if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') {
throw new ConflictException('Platform name already exists'); const target = error.meta?.target;
if (Array.isArray(target) && target.includes('instance_no')) {
throw new ConflictException('플랫폼 등록번호가 중복되었습니다. 다시 등록해 주세요.');
}
throw new ConflictException('이미 사용 중인 플랫폼 이름입니다. 다른 이름을 입력해 주세요.');
} }
throw error; throw error;
} }
@@ -0,0 +1,57 @@
import { Prisma } from '@prisma/client';
import { InstructorService } from './instructor.service';
describe('platform registration', () => {
const input = { platformId: 'yahboom', agentNodeId: 'node-2', agentHostname: 'car-2' };
function setup() {
const registered = [
{ platformId: 'yahboom', displayName: 'Custom car', instanceNo: 1 },
{ platformId: 'mkmini', displayName: 'Yahboom MicroROS-Car-Pi5 #02', instanceNo: 2 },
];
const prisma = {
platform: { findFirst: jest.fn().mockResolvedValue({ id: 'yahboom', displayName: 'Yahboom MicroROS-Car-Pi5' }) },
instructorPlatform: {
findMany: jest.fn(async ({ where }) => registered.filter(row =>
(!where.platformId || row.platformId === where.platformId)
&& (!where.displayName?.startsWith || row.displayName.startsWith(where.displayName.startsWith)))),
create: jest.fn().mockResolvedValue({}),
},
};
const service = new InstructorService({} as never, {} as never, prisma as never, {} as never, {} as never, {} as never);
jest.spyOn(service as any, 'getInstructor').mockResolvedValue({
authUser: { primaryAffiliation: { organizationId: 'org-id', organizationName: 'org' } },
});
jest.spyOn(service, 'listPlatforms').mockResolvedValue({ platforms: [] } as never);
return { service, prisma };
}
it('counts renamed vehicles by platform ID, ignoring names of other types', async () => {
const { service, prisma } = setup();
await service.createPlatform('token', input);
expect(prisma.instructorPlatform.findMany).toHaveBeenCalledWith(expect.objectContaining({
where: expect.objectContaining({ platformId: 'yahboom', OR: expect.any(Array) }),
}));
expect(prisma.instructorPlatform.create).toHaveBeenCalledWith({
data: expect.objectContaining({ instanceNo: 2, displayName: 'Yahboom MicroROS-Car-Pi5 #02' }),
});
});
it('keeps a user-provided name while assigning the next internal number', async () => {
const { service, prisma } = setup();
await service.createPlatform('token', { ...input, displayName: 'Second car' });
expect(prisma.instructorPlatform.create).toHaveBeenCalledWith({
data: expect.objectContaining({ instanceNo: 2, displayName: 'Second car' }),
});
});
it.each([
[['organization_name', 'display_name'], '이미 사용 중인 플랫폼 이름'],
[['organization_name', 'platform_id', 'instance_no'], '플랫폼 등록번호가 중복'],
])('distinguishes unique constraint failures for %j', async (target, message) => {
const { service, prisma } = setup();
prisma.instructorPlatform.create.mockRejectedValue(new Prisma.PrismaClientKnownRequestError('duplicate', {
code: 'P2002', clientVersion: '6', meta: { target },
}));
await expect(service.createPlatform('token', input)).rejects.toThrow(message);
});
});