feat: refine announcement (#11497)
* wip * Update read-announcement.ts * wip * wip * wip * Update index.d.ts * wip * Create 1691649257651-refine-announcement.js * wip * wip * wip * wip * wip * wip * Update announcements.vue * wip * wip * Update announcements.vue * wip * Update announcements.vue * wip * Update misskey-js.api.md * Update users.ts * Create MkAnnouncementDialog.stories.impl.ts * wip * wip * Create AnnouncementService.ts
This commit is contained in:
parent
2896fc6cb4
commit
9487856495
38 changed files with 1226 additions and 223 deletions
194
packages/backend/test/unit/AnnouncementService.ts
Normal file
194
packages/backend/test/unit/AnnouncementService.ts
Normal file
|
@ -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<GlobalEventService>;
|
||||
|
||||
function createUser(data: Partial<User> = {}) {
|
||||
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<Announcement> = {}) {
|
||||
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<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>;
|
||||
});
|
||||
|
||||
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
|
||||
});
|
||||
});
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue