2023-08-13 20:12:29 +09:00
|
|
|
/*
|
2024-02-14 00:59:27 +09:00
|
|
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
2023-08-13 20:12:29 +09:00
|
|
|
* 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';
|
2024-05-27 17:15:11 +09:00
|
|
|
import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
|
2024-01-08 17:43:52 +09:00
|
|
|
import type {
|
|
|
|
AnnouncementReadsRepository,
|
|
|
|
AnnouncementsRepository,
|
|
|
|
MiAnnouncement,
|
|
|
|
MiUser,
|
|
|
|
UsersRepository,
|
|
|
|
} from '@/models/_.js';
|
2023-08-13 20:12:29 +09:00
|
|
|
import { DI } from '@/di-symbols.js';
|
2023-09-06 18:33:51 +09:00
|
|
|
import { genAidx } from '@/misc/id/aidx.js';
|
2023-08-13 20:12:29 +09:00
|
|
|
import { CacheService } from '@/core/CacheService.js';
|
|
|
|
import { IdService } from '@/core/IdService.js';
|
|
|
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
2023-09-23 18:28:16 +09:00
|
|
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
2023-08-13 20:12:29 +09:00
|
|
|
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<GlobalEventService>;
|
2023-09-23 18:28:16 +09:00
|
|
|
let moderationLogService: jest.Mocked<ModerationLogService>;
|
2023-08-13 20:12:29 +09:00
|
|
|
|
2023-09-04 13:33:38 +09:00
|
|
|
function createUser(data: Partial<MiUser> = {}) {
|
2023-08-13 20:12:29 +09:00
|
|
|
const un = secureRndstr(16);
|
|
|
|
return usersRepository.insert({
|
2023-10-16 12:58:17 +09:00
|
|
|
id: genAidx(Date.now()),
|
2023-08-13 20:12:29 +09:00
|
|
|
username: un,
|
|
|
|
usernameLower: un,
|
|
|
|
...data,
|
|
|
|
})
|
|
|
|
.then(x => usersRepository.findOneByOrFail(x.identifiers[0]));
|
|
|
|
}
|
|
|
|
|
2023-10-16 10:45:22 +09:00
|
|
|
function createAnnouncement(data: Partial<MiAnnouncement & { createdAt: Date }> = {}) {
|
2023-08-13 20:12:29 +09:00
|
|
|
return announcementsRepository.insert({
|
2024-03-03 20:15:35 +09:00
|
|
|
id: genAidx(data.createdAt?.getTime() ?? Date.now()),
|
2023-08-13 20:12:29 +09:00
|
|
|
updatedAt: null,
|
|
|
|
title: 'Title',
|
|
|
|
text: 'Text',
|
|
|
|
...data,
|
|
|
|
})
|
|
|
|
.then(x => announcementsRepository.findOneByOrFail(x.identifiers[0]));
|
|
|
|
}
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
app = await Test.createTestingModule({
|
|
|
|
imports: [
|
|
|
|
GlobalModule,
|
|
|
|
],
|
|
|
|
providers: [
|
|
|
|
AnnouncementService,
|
2024-05-27 17:15:11 +09:00
|
|
|
AnnouncementEntityService,
|
2023-08-13 20:12:29 +09:00
|
|
|
CacheService,
|
|
|
|
IdService,
|
|
|
|
],
|
|
|
|
})
|
|
|
|
.useMocker((token) => {
|
|
|
|
if (token === GlobalEventService) {
|
|
|
|
return {
|
|
|
|
publishMainStream: jest.fn(),
|
|
|
|
publishBroadcastStream: jest.fn(),
|
|
|
|
};
|
2023-09-23 18:28:16 +09:00
|
|
|
} else if (token === ModerationLogService) {
|
|
|
|
return {
|
|
|
|
log: jest.fn(),
|
|
|
|
};
|
|
|
|
} else if (typeof token === 'function') {
|
2023-08-13 20:12:29 +09:00
|
|
|
const mockMetadata = moduleMocker.getMetadata(token) as MockFunctionMetadata<any, any>;
|
|
|
|
const Mock = moduleMocker.generateFromMetadata(mockMetadata);
|
|
|
|
return new Mock();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.compile();
|
|
|
|
|
|
|
|
app.enableShutdownHooks();
|
|
|
|
|
|
|
|
announcementService = app.get<AnnouncementService>(AnnouncementService);
|
|
|
|
usersRepository = app.get<UsersRepository>(DI.usersRepository);
|
|
|
|
announcementsRepository = app.get<AnnouncementsRepository>(DI.announcementsRepository);
|
|
|
|
announcementReadsRepository = app.get<AnnouncementReadsRepository>(DI.announcementReadsRepository);
|
|
|
|
globalEventService = app.get<GlobalEventService>(GlobalEventService) as jest.Mocked<GlobalEventService>;
|
2023-09-23 18:28:16 +09:00
|
|
|
moderationLogService = app.get<ModerationLogService>(ModerationLogService) as jest.Mocked<ModerationLogService>;
|
2023-08-13 20:12:29 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
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 () => {
|
2023-09-23 18:28:16 +09:00
|
|
|
const me = await createUser();
|
2023-08-13 20:12:29 +09:00
|
|
|
const result = await announcementService.create({
|
|
|
|
title: 'Title',
|
|
|
|
text: 'Text',
|
2023-09-23 18:28:16 +09:00
|
|
|
}, me);
|
2023-08-13 20:12:29 +09:00
|
|
|
|
|
|
|
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);
|
2023-09-23 18:28:16 +09:00
|
|
|
expect(moderationLogService.log).toHaveBeenCalled();
|
2023-08-13 20:12:29 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
test('ユーザー指定', async () => {
|
2023-09-23 18:28:16 +09:00
|
|
|
const me = await createUser();
|
2023-08-13 20:12:29 +09:00
|
|
|
const user = await createUser();
|
|
|
|
const result = await announcementService.create({
|
|
|
|
title: 'Title',
|
|
|
|
text: 'Text',
|
|
|
|
userId: user.id,
|
2023-09-23 18:28:16 +09:00
|
|
|
}, me);
|
2023-08-13 20:12:29 +09:00
|
|
|
|
|
|
|
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);
|
2023-09-23 18:28:16 +09:00
|
|
|
expect(moderationLogService.log).toHaveBeenCalled();
|
2023-08-13 20:12:29 +09:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('read', () => {
|
|
|
|
// TODO
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|