From c8300bf6d67ecad4140aa77e8104193c8608842e Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 13 Aug 2023 15:37:59 +0900 Subject: [PATCH] Create AnnouncementService.ts --- .../backend/test/unit/AnnouncementService.ts | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 packages/backend/test/unit/AnnouncementService.ts diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts new file mode 100644 index 0000000000..c97e081ba5 --- /dev/null +++ b/packages/backend/test/unit/AnnouncementService.ts @@ -0,0 +1,194 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +process.env.NODE_ENV = 'test'; + +import { jest } from '@jest/globals'; +import { ModuleMocker } from 'jest-mock'; +import { Test } from '@nestjs/testing'; +import { GlobalModule } from '@/GlobalModule.js'; +import { AnnouncementService } from '@/core/AnnouncementService.js'; +import type { Announcement, AnnouncementsRepository, AnnouncementReadsRepository, UsersRepository, User } from '@/models/index.js'; +import { DI } from '@/di-symbols.js'; +import { genAid } from '@/misc/id/aid.js'; +import { CacheService } from '@/core/CacheService.js'; +import { IdService } from '@/core/IdService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; +import { secureRndstr } from '@/misc/secure-rndstr.js'; +import type { TestingModule } from '@nestjs/testing'; +import type { MockFunctionMetadata } from 'jest-mock'; + +const moduleMocker = new ModuleMocker(global); + +describe('AnnouncementService', () => { + let app: TestingModule; + let announcementService: AnnouncementService; + let usersRepository: UsersRepository; + let announcementsRepository: AnnouncementsRepository; + let announcementReadsRepository: AnnouncementReadsRepository; + let globalEventService: jest.Mocked; + + function createUser(data: Partial = {}) { + const un = secureRndstr(16); + return usersRepository.insert({ + id: genAid(new Date()), + createdAt: new Date(), + username: un, + usernameLower: un, + ...data, + }) + .then(x => usersRepository.findOneByOrFail(x.identifiers[0])); + } + + function createAnnouncement(data: Partial = {}) { + return announcementsRepository.insert({ + id: genAid(new Date()), + createdAt: new Date(), + updatedAt: null, + title: 'Title', + text: 'Text', + ...data, + }) + .then(x => announcementsRepository.findOneByOrFail(x.identifiers[0])); + } + + beforeEach(async () => { + app = await Test.createTestingModule({ + imports: [ + GlobalModule, + ], + providers: [ + AnnouncementService, + CacheService, + IdService, + ], + }) + .useMocker((token) => { + if (token === GlobalEventService) { + return { + publishMainStream: jest.fn(), + publishBroadcastStream: jest.fn(), + }; + } + if (typeof token === 'function') { + const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata; + const Mock = moduleMocker.generateFromMetadata(mockMetadata); + return new Mock(); + } + }) + .compile(); + + app.enableShutdownHooks(); + + announcementService = app.get(AnnouncementService); + usersRepository = app.get(DI.usersRepository); + announcementsRepository = app.get(DI.announcementsRepository); + announcementReadsRepository = app.get(DI.announcementReadsRepository); + globalEventService = app.get(GlobalEventService) as jest.Mocked; + }); + + afterEach(async () => { + await Promise.all([ + app.get(DI.metasRepository).delete({}), + usersRepository.delete({}), + announcementsRepository.delete({}), + announcementReadsRepository.delete({}), + ]); + + await app.close(); + }); + + describe('getUnreadAnnouncements', () => { + test('通常', async () => { + const user = await createUser(); + const announcement = await createAnnouncement({ + title: '1', + }); + + const result = await announcementService.getUnreadAnnouncements(user); + + expect(result.length).toBe(1); + expect(result[0].title).toBe(announcement.title); + }); + + test('isActiveがfalseは除外', async () => { + const user = await createUser(); + await createAnnouncement({ + isActive: false, + }); + + const result = await announcementService.getUnreadAnnouncements(user); + + expect(result.length).toBe(0); + }); + + test('forExistingUsers', async () => { + const user = await createUser(); + const [announcementAfter, announcementBefore, announcementBefore2] = await Promise.all([ + createAnnouncement({ + title: 'after', + createdAt: new Date(), + forExistingUsers: true, + }), + createAnnouncement({ + title: 'before', + createdAt: new Date(Date.now() - 1000), + forExistingUsers: true, + }), + createAnnouncement({ + title: 'before2', + createdAt: new Date(Date.now() - 1000), + forExistingUsers: false, + }), + ]); + + const result = await announcementService.getUnreadAnnouncements(user); + + expect(result.length).toBe(2); + expect(result.some(a => a.title === announcementAfter.title)).toBe(true); + expect(result.some(a => a.title === announcementBefore.title)).toBe(false); + expect(result.some(a => a.title === announcementBefore2.title)).toBe(true); + }); + }); + + describe('create', () => { + test('通常', async () => { + const result = await announcementService.create({ + title: 'Title', + text: 'Text', + }); + + expect(result.raw.title).toBe('Title'); + expect(result.packed.title).toBe('Title'); + + expect(globalEventService.publishBroadcastStream).toHaveBeenCalled(); + expect(globalEventService.publishBroadcastStream.mock.lastCall![0]).toBe('announcementCreated'); + expect((globalEventService.publishBroadcastStream.mock.lastCall![1] as any).announcement).toBe(result.packed); + }); + + test('ユーザー指定', async () => { + const user = await createUser(); + const result = await announcementService.create({ + title: 'Title', + text: 'Text', + userId: user.id, + }); + + expect(result.raw.title).toBe('Title'); + expect(result.packed.title).toBe('Title'); + + expect(globalEventService.publishBroadcastStream).not.toHaveBeenCalled(); + expect(globalEventService.publishMainStream).toHaveBeenCalled(); + expect(globalEventService.publishMainStream.mock.lastCall![0]).toBe(user.id); + expect(globalEventService.publishMainStream.mock.lastCall![1]).toBe('announcementCreated'); + expect((globalEventService.publishMainStream.mock.lastCall![2] as any).announcement).toBe(result.packed); + }); + }); + + describe('read', () => { + // TODO + }); +}); +