2023-05-13 03:11:41 +00:00
|
|
|
|
process.env.NODE_ENV = "test";
|
|
|
|
|
|
|
|
|
|
import * as assert from "assert";
|
|
|
|
|
import { inspect } from "node:util";
|
|
|
|
|
import { DEFAULT_POLICIES } from "@/core/RoleService.js";
|
|
|
|
|
import type { Packed } from "@/misc/json-schema.js";
|
|
|
|
|
import {
|
|
|
|
|
signup,
|
|
|
|
|
post,
|
2023-05-10 01:52:41 +00:00
|
|
|
|
page,
|
|
|
|
|
role,
|
2023-05-13 03:11:41 +00:00
|
|
|
|
startServer,
|
2023-05-10 01:52:41 +00:00
|
|
|
|
api,
|
2023-05-13 03:11:41 +00:00
|
|
|
|
successfulApiCall,
|
2023-05-10 01:52:41 +00:00
|
|
|
|
failedApiCall,
|
|
|
|
|
uploadFile,
|
2023-05-13 03:11:41 +00:00
|
|
|
|
} from "../utils.js";
|
|
|
|
|
import type * as misskey from "misskey-js";
|
|
|
|
|
import type { INestApplicationContext } from "@nestjs/common";
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
describe("ユーザー", () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
// エンティティとしてのユーザーを主眼においたテストを記述する
|
|
|
|
|
// (Userを返すエンドポイントとUserエンティティを書き換えるエンドポイントをテストする)
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const stripUndefined = <T extends { [key: string]: any },>(
|
|
|
|
|
orig: T,
|
|
|
|
|
): Partial<T> => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
return Object.entries({ ...orig })
|
|
|
|
|
.filter(([, value]) => value !== undefined)
|
|
|
|
|
.reduce((obj: Partial<T>, [key, value]) => {
|
|
|
|
|
obj[key as keyof T] = value;
|
|
|
|
|
return obj;
|
|
|
|
|
}, {});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// BUG misskey-jsとjson-schemaと実際に返ってくるデータが全部違う
|
|
|
|
|
type UserLite = misskey.entities.UserLite & {
|
2023-05-13 03:11:41 +00:00
|
|
|
|
badgeRoles: any[];
|
2023-05-10 01:52:41 +00:00
|
|
|
|
};
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
type UserDetailedNotMe = UserLite &
|
|
|
|
|
misskey.entities.UserDetailed & {
|
|
|
|
|
roles: any[];
|
|
|
|
|
};
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
type MeDetailed = UserDetailedNotMe &
|
2023-05-10 01:52:41 +00:00
|
|
|
|
misskey.entities.MeDetailed & {
|
2023-05-13 03:11:41 +00:00
|
|
|
|
showTimelineReplies: boolean;
|
|
|
|
|
achievements: object[];
|
|
|
|
|
loggedInDays: number;
|
|
|
|
|
policies: object;
|
|
|
|
|
};
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
type User = MeDetailed & { token: string };
|
|
|
|
|
|
|
|
|
|
const show = async (
|
|
|
|
|
id: string,
|
|
|
|
|
me = root,
|
|
|
|
|
): Promise<MeDetailed | UserDetailedNotMe> => {
|
|
|
|
|
return successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters: { userId: id },
|
|
|
|
|
user: me,
|
|
|
|
|
}) as any;
|
2023-05-10 01:52:41 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// UserLiteのキーが過不足なく入っている?
|
|
|
|
|
const userLite = (user: User): Partial<UserLite> => {
|
|
|
|
|
return stripUndefined({
|
|
|
|
|
id: user.id,
|
|
|
|
|
name: user.name,
|
|
|
|
|
username: user.username,
|
|
|
|
|
host: user.host,
|
|
|
|
|
avatarUrl: user.avatarUrl,
|
|
|
|
|
avatarBlurhash: user.avatarBlurhash,
|
|
|
|
|
isBot: user.isBot,
|
|
|
|
|
isCat: user.isCat,
|
|
|
|
|
instance: user.instance,
|
|
|
|
|
emojis: user.emojis,
|
|
|
|
|
onlineStatus: user.onlineStatus,
|
|
|
|
|
badgeRoles: user.badgeRoles,
|
|
|
|
|
|
|
|
|
|
// BUG isAdmin/isModeratorはUserLiteではなくMeDetailedOnlyに含まれる。
|
|
|
|
|
isAdmin: undefined,
|
|
|
|
|
isModerator: undefined,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// UserDetailedNotMeのキーが過不足なく入っている?
|
|
|
|
|
const userDetailedNotMe = (user: User): Partial<UserDetailedNotMe> => {
|
|
|
|
|
return stripUndefined({
|
|
|
|
|
...userLite(user),
|
|
|
|
|
url: user.url,
|
|
|
|
|
uri: user.uri,
|
|
|
|
|
movedTo: user.movedTo,
|
|
|
|
|
alsoKnownAs: user.alsoKnownAs,
|
|
|
|
|
createdAt: user.createdAt,
|
|
|
|
|
updatedAt: user.updatedAt,
|
|
|
|
|
lastFetchedAt: user.lastFetchedAt,
|
|
|
|
|
bannerUrl: user.bannerUrl,
|
|
|
|
|
bannerBlurhash: user.bannerBlurhash,
|
|
|
|
|
isLocked: user.isLocked,
|
|
|
|
|
isSilenced: user.isSilenced,
|
|
|
|
|
isSuspended: user.isSuspended,
|
|
|
|
|
description: user.description,
|
|
|
|
|
location: user.location,
|
|
|
|
|
birthday: user.birthday,
|
|
|
|
|
lang: user.lang,
|
|
|
|
|
fields: user.fields,
|
|
|
|
|
followersCount: user.followersCount,
|
|
|
|
|
followingCount: user.followingCount,
|
|
|
|
|
notesCount: user.notesCount,
|
|
|
|
|
pinnedNoteIds: user.pinnedNoteIds,
|
|
|
|
|
pinnedNotes: user.pinnedNotes,
|
|
|
|
|
pinnedPageId: user.pinnedPageId,
|
|
|
|
|
pinnedPage: user.pinnedPage,
|
|
|
|
|
publicReactions: user.publicReactions,
|
|
|
|
|
ffVisibility: user.ffVisibility,
|
|
|
|
|
twoFactorEnabled: user.twoFactorEnabled,
|
|
|
|
|
usePasswordLessLogin: user.usePasswordLessLogin,
|
|
|
|
|
securityKeys: user.securityKeys,
|
|
|
|
|
roles: user.roles,
|
|
|
|
|
memo: user.memo,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Relations関連のキーが過不足なく入っている?
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const userDetailedNotMeWithRelations = (
|
|
|
|
|
user: User,
|
|
|
|
|
): Partial<UserDetailedNotMe> => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
return stripUndefined({
|
|
|
|
|
...userDetailedNotMe(user),
|
|
|
|
|
isFollowing: user.isFollowing ?? false,
|
|
|
|
|
isFollowed: user.isFollowed ?? false,
|
2023-05-13 03:11:41 +00:00
|
|
|
|
hasPendingFollowRequestFromYou:
|
|
|
|
|
user.hasPendingFollowRequestFromYou ?? false,
|
2023-05-10 01:52:41 +00:00
|
|
|
|
hasPendingFollowRequestToYou: user.hasPendingFollowRequestToYou ?? false,
|
|
|
|
|
isBlocking: user.isBlocking ?? false,
|
|
|
|
|
isBlocked: user.isBlocked ?? false,
|
|
|
|
|
isMuted: user.isMuted ?? false,
|
|
|
|
|
isRenoteMuted: user.isRenoteMuted ?? false,
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// MeDetailedのキーが過不足なく入っている?
|
|
|
|
|
const meDetailed = (user: User, security = false): Partial<MeDetailed> => {
|
|
|
|
|
return stripUndefined({
|
|
|
|
|
...userDetailedNotMe(user),
|
|
|
|
|
avatarId: user.avatarId,
|
|
|
|
|
bannerId: user.bannerId,
|
|
|
|
|
isModerator: user.isModerator,
|
|
|
|
|
isAdmin: user.isAdmin,
|
|
|
|
|
injectFeaturedNote: user.injectFeaturedNote,
|
|
|
|
|
receiveAnnouncementEmail: user.receiveAnnouncementEmail,
|
|
|
|
|
alwaysMarkNsfw: user.alwaysMarkNsfw,
|
|
|
|
|
autoSensitive: user.autoSensitive,
|
|
|
|
|
carefulBot: user.carefulBot,
|
|
|
|
|
autoAcceptFollowed: user.autoAcceptFollowed,
|
|
|
|
|
noCrawle: user.noCrawle,
|
|
|
|
|
preventAiLearning: user.preventAiLearning,
|
|
|
|
|
isExplorable: user.isExplorable,
|
|
|
|
|
isDeleted: user.isDeleted,
|
|
|
|
|
hideOnlineStatus: user.hideOnlineStatus,
|
|
|
|
|
hasUnreadSpecifiedNotes: user.hasUnreadSpecifiedNotes,
|
|
|
|
|
hasUnreadMentions: user.hasUnreadMentions,
|
|
|
|
|
hasUnreadAnnouncement: user.hasUnreadAnnouncement,
|
|
|
|
|
hasUnreadAntenna: user.hasUnreadAntenna,
|
|
|
|
|
hasUnreadChannel: user.hasUnreadChannel,
|
|
|
|
|
hasUnreadNotification: user.hasUnreadNotification,
|
|
|
|
|
hasPendingReceivedFollowRequest: user.hasPendingReceivedFollowRequest,
|
|
|
|
|
mutedWords: user.mutedWords,
|
|
|
|
|
mutedInstances: user.mutedInstances,
|
|
|
|
|
mutingNotificationTypes: user.mutingNotificationTypes,
|
|
|
|
|
emailNotificationTypes: user.emailNotificationTypes,
|
|
|
|
|
showTimelineReplies: user.showTimelineReplies,
|
|
|
|
|
achievements: user.achievements,
|
|
|
|
|
loggedInDays: user.loggedInDays,
|
|
|
|
|
policies: user.policies,
|
2023-05-13 03:11:41 +00:00
|
|
|
|
...(security
|
|
|
|
|
? {
|
|
|
|
|
email: user.email,
|
|
|
|
|
emailVerified: user.emailVerified,
|
|
|
|
|
securityKeysList: user.securityKeysList,
|
|
|
|
|
}
|
|
|
|
|
: {}),
|
2023-05-10 01:52:41 +00:00
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let app: INestApplicationContext;
|
|
|
|
|
|
|
|
|
|
let root: User;
|
|
|
|
|
let alice: User;
|
|
|
|
|
let aliceNote: misskey.entities.Note;
|
|
|
|
|
let alicePage: misskey.entities.Page;
|
|
|
|
|
let aliceList: misskey.entities.UserList;
|
|
|
|
|
|
|
|
|
|
let bob: User;
|
|
|
|
|
let bobNote: misskey.entities.Note;
|
|
|
|
|
|
|
|
|
|
let carol: User;
|
|
|
|
|
let dave: User;
|
|
|
|
|
let ellen: User;
|
|
|
|
|
let frank: User;
|
|
|
|
|
|
|
|
|
|
let usersReplying: User[];
|
|
|
|
|
|
|
|
|
|
let userNoNote: User;
|
|
|
|
|
let userNotExplorable: User;
|
|
|
|
|
let userLocking: User;
|
|
|
|
|
let userAdmin: User;
|
|
|
|
|
let roleAdmin: any;
|
|
|
|
|
let userModerator: User;
|
|
|
|
|
let roleModerator: any;
|
|
|
|
|
let userRolePublic: User;
|
|
|
|
|
let rolePublic: any;
|
|
|
|
|
let userRoleBadge: User;
|
|
|
|
|
let roleBadge: any;
|
|
|
|
|
let userSilenced: User;
|
|
|
|
|
let roleSilenced: any;
|
|
|
|
|
let userSuspended: User;
|
|
|
|
|
let userDeletedBySelf: User;
|
|
|
|
|
let userDeletedByAdmin: User;
|
|
|
|
|
let userFollowingAlice: User;
|
|
|
|
|
let userFollowedByAlice: User;
|
|
|
|
|
let userBlockingAlice: User;
|
|
|
|
|
let userBlockedByAlice: User;
|
|
|
|
|
let userMutingAlice: User;
|
|
|
|
|
let userMutedByAlice: User;
|
|
|
|
|
let userRnMutingAlice: User;
|
|
|
|
|
let userRnMutedByAlice: User;
|
|
|
|
|
let userFollowRequesting: User;
|
|
|
|
|
let userFollowRequested: User;
|
|
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
|
|
|
|
app = await startServer();
|
|
|
|
|
}, 1000 * 60 * 2);
|
|
|
|
|
|
|
|
|
|
beforeAll(async () => {
|
2023-05-13 03:11:41 +00:00
|
|
|
|
root = await signup({ username: "root" });
|
|
|
|
|
alice = await signup({ username: "alice" });
|
|
|
|
|
aliceNote = (await post(alice, { text: "test" })) as any;
|
2023-05-10 01:52:41 +00:00
|
|
|
|
alicePage = await page(alice);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
aliceList = (await api("users/list/create", { name: "aliceList" }, alice))
|
|
|
|
|
.body;
|
|
|
|
|
bob = await signup({ username: "bob" });
|
|
|
|
|
bobNote = (await post(bob, { text: "test" })) as any;
|
|
|
|
|
carol = await signup({ username: "carol" });
|
|
|
|
|
dave = await signup({ username: "dave" });
|
|
|
|
|
ellen = await signup({ username: "ellen" });
|
|
|
|
|
frank = await signup({ username: "frank" });
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
|
|
|
|
// @alice -> @replyingへのリプライ。Promise.allで一気に作るとtimeoutしてしまうのでreduceで一つ一つawaitする
|
2023-05-13 03:11:41 +00:00
|
|
|
|
usersReplying = await [...Array(10)]
|
|
|
|
|
.map((_, i) => i)
|
|
|
|
|
.reduce(async (acc, i) => {
|
|
|
|
|
const u = await signup({ username: `replying${i}` });
|
|
|
|
|
for (let j = 0; j < 10 - i; j++) {
|
|
|
|
|
const p = await post(u, { text: `test${j}` });
|
|
|
|
|
await post(alice, { text: `@${u.username} test${j}`, replyId: p.id });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (await acc).concat(u);
|
|
|
|
|
}, Promise.resolve([] as User[]));
|
|
|
|
|
|
|
|
|
|
userNoNote = await signup({ username: "userNoNote" });
|
|
|
|
|
userNotExplorable = await signup({ username: "userNotExplorable" });
|
|
|
|
|
await post(userNotExplorable, { text: "test" });
|
|
|
|
|
await api("i/update", { isExplorable: false }, userNotExplorable);
|
|
|
|
|
userLocking = await signup({ username: "userLocking" });
|
|
|
|
|
await post(userLocking, { text: "test" });
|
|
|
|
|
await api("i/update", { isLocked: true }, userLocking);
|
|
|
|
|
userAdmin = await signup({ username: "userAdmin" });
|
|
|
|
|
roleAdmin = await role(root, { isAdministrator: true, name: "Admin Role" });
|
|
|
|
|
await api(
|
|
|
|
|
"admin/roles/assign",
|
|
|
|
|
{ userId: userAdmin.id, roleId: roleAdmin.id },
|
|
|
|
|
root,
|
|
|
|
|
);
|
|
|
|
|
userModerator = await signup({ username: "userModerator" });
|
|
|
|
|
roleModerator = await role(root, {
|
|
|
|
|
isModerator: true,
|
|
|
|
|
name: "Moderator Role",
|
|
|
|
|
});
|
|
|
|
|
await api(
|
|
|
|
|
"admin/roles/assign",
|
|
|
|
|
{ userId: userModerator.id, roleId: roleModerator.id },
|
|
|
|
|
root,
|
|
|
|
|
);
|
|
|
|
|
userRolePublic = await signup({ username: "userRolePublic" });
|
|
|
|
|
rolePublic = await role(root, { isPublic: true, name: "Public Role" });
|
|
|
|
|
await api(
|
|
|
|
|
"admin/roles/assign",
|
|
|
|
|
{ userId: userRolePublic.id, roleId: rolePublic.id },
|
|
|
|
|
root,
|
|
|
|
|
);
|
|
|
|
|
userRoleBadge = await signup({ username: "userRoleBadge" });
|
|
|
|
|
roleBadge = await role(root, { asBadge: true, name: "Badge Role" });
|
|
|
|
|
await api(
|
|
|
|
|
"admin/roles/assign",
|
|
|
|
|
{ userId: userRoleBadge.id, roleId: roleBadge.id },
|
|
|
|
|
root,
|
|
|
|
|
);
|
|
|
|
|
userSilenced = await signup({ username: "userSilenced" });
|
|
|
|
|
await post(userSilenced, { text: "test" });
|
|
|
|
|
roleSilenced = await role(
|
|
|
|
|
root,
|
|
|
|
|
{},
|
|
|
|
|
{ canPublicNote: { priority: 0, useDefault: false, value: false } },
|
|
|
|
|
);
|
|
|
|
|
await api(
|
|
|
|
|
"admin/roles/assign",
|
|
|
|
|
{ userId: userSilenced.id, roleId: roleSilenced.id },
|
|
|
|
|
root,
|
|
|
|
|
);
|
|
|
|
|
userSuspended = await signup({ username: "userSuspended" });
|
|
|
|
|
await post(userSuspended, { text: "test" });
|
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "i/update",
|
|
|
|
|
parameters: { description: "#user_testuserSuspended" },
|
|
|
|
|
user: userSuspended,
|
|
|
|
|
});
|
|
|
|
|
await api("admin/suspend-user", { userId: userSuspended.id }, root);
|
|
|
|
|
userDeletedBySelf = await signup({
|
|
|
|
|
username: "userDeletedBySelf",
|
|
|
|
|
password: "userDeletedBySelf",
|
|
|
|
|
});
|
|
|
|
|
await post(userDeletedBySelf, { text: "test" });
|
|
|
|
|
await api(
|
|
|
|
|
"i/delete-account",
|
|
|
|
|
{ password: "userDeletedBySelf" },
|
|
|
|
|
userDeletedBySelf,
|
|
|
|
|
);
|
|
|
|
|
userDeletedByAdmin = await signup({ username: "userDeletedByAdmin" });
|
|
|
|
|
await post(userDeletedByAdmin, { text: "test" });
|
|
|
|
|
await api("admin/delete-account", { userId: userDeletedByAdmin.id }, root);
|
|
|
|
|
userFollowingAlice = await signup({ username: "userFollowingAlice" });
|
|
|
|
|
await post(userFollowingAlice, { text: "test" });
|
|
|
|
|
await api("following/create", { userId: alice.id }, userFollowingAlice);
|
|
|
|
|
userFollowedByAlice = await signup({ username: "userFollowedByAlice" });
|
|
|
|
|
await post(userFollowedByAlice, { text: "test" });
|
|
|
|
|
await api("following/create", { userId: userFollowedByAlice.id }, alice);
|
|
|
|
|
userBlockingAlice = await signup({ username: "userBlockingAlice" });
|
|
|
|
|
await post(userBlockingAlice, { text: "test" });
|
|
|
|
|
await api("blocking/create", { userId: alice.id }, userBlockingAlice);
|
|
|
|
|
userBlockedByAlice = await signup({ username: "userBlockedByAlice" });
|
|
|
|
|
await post(userBlockedByAlice, { text: "test" });
|
|
|
|
|
await api("blocking/create", { userId: userBlockedByAlice.id }, alice);
|
|
|
|
|
userMutingAlice = await signup({ username: "userMutingAlice" });
|
|
|
|
|
await post(userMutingAlice, { text: "test" });
|
|
|
|
|
await api("mute/create", { userId: alice.id }, userMutingAlice);
|
|
|
|
|
userMutedByAlice = await signup({ username: "userMutedByAlice" });
|
|
|
|
|
await post(userMutedByAlice, { text: "test" });
|
|
|
|
|
await api("mute/create", { userId: userMutedByAlice.id }, alice);
|
|
|
|
|
userRnMutingAlice = await signup({ username: "userRnMutingAlice" });
|
|
|
|
|
await post(userRnMutingAlice, { text: "test" });
|
|
|
|
|
await api("renote-mute/create", { userId: alice.id }, userRnMutingAlice);
|
|
|
|
|
userRnMutedByAlice = await signup({ username: "userRnMutedByAlice" });
|
|
|
|
|
await post(userRnMutedByAlice, { text: "test" });
|
|
|
|
|
await api("renote-mute/create", { userId: userRnMutedByAlice.id }, alice);
|
|
|
|
|
userFollowRequesting = await signup({ username: "userFollowRequesting" });
|
|
|
|
|
await post(userFollowRequesting, { text: "test" });
|
2023-05-10 01:52:41 +00:00
|
|
|
|
userFollowRequested = userLocking;
|
2023-05-13 03:11:41 +00:00
|
|
|
|
await api(
|
|
|
|
|
"following/create",
|
|
|
|
|
{ userId: userFollowRequested.id },
|
|
|
|
|
userFollowRequesting,
|
|
|
|
|
);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
}, 1000 * 60 * 10);
|
|
|
|
|
|
|
|
|
|
afterAll(async () => {
|
|
|
|
|
await app.close();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
|
alice = {
|
|
|
|
|
...alice,
|
2023-05-13 03:11:41 +00:00
|
|
|
|
...((await successfulApiCall({
|
|
|
|
|
endpoint: "i",
|
|
|
|
|
parameters: {},
|
|
|
|
|
user: alice,
|
|
|
|
|
})) as any),
|
2023-05-10 01:52:41 +00:00
|
|
|
|
};
|
2023-05-13 03:11:41 +00:00
|
|
|
|
aliceNote = await successfulApiCall({
|
|
|
|
|
endpoint: "notes/show",
|
|
|
|
|
parameters: { noteId: aliceNote.id },
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//#region サインアップ(signup)
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("が作れる。(作りたての状態で自分のユーザー情報が取れる)", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
// SignupApiService.ts
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = (await successfulApiCall({
|
|
|
|
|
endpoint: "signup",
|
|
|
|
|
parameters: { username: "zoe", password: "password" },
|
2023-05-10 01:52:41 +00:00
|
|
|
|
user: undefined,
|
2023-05-13 03:11:41 +00:00
|
|
|
|
})) as unknown as User; // BUG MeDetailedに足りないキーがある
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
|
|
|
|
// signupの時はtokenが含まれる特別なMeDetailedが返ってくる
|
|
|
|
|
assert.match(response.token, /[a-zA-Z0-9]{16}/);
|
|
|
|
|
|
|
|
|
|
// UserLite
|
|
|
|
|
assert.match(response.id, /[0-9a-z]{10}/);
|
|
|
|
|
assert.strictEqual(response.name, null);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
assert.strictEqual(response.username, "zoe");
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.strictEqual(response.host, null);
|
|
|
|
|
assert.match(response.avatarUrl, /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
|
|
|
|
assert.strictEqual(response.avatarBlurhash, null);
|
|
|
|
|
assert.strictEqual(response.isBot, false);
|
|
|
|
|
assert.strictEqual(response.isCat, false);
|
|
|
|
|
assert.strictEqual(response.instance, undefined);
|
|
|
|
|
assert.deepStrictEqual(response.emojis, {});
|
2023-05-13 03:11:41 +00:00
|
|
|
|
assert.strictEqual(response.onlineStatus, "unknown");
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.deepStrictEqual(response.badgeRoles, []);
|
|
|
|
|
// UserDetailedNotMeOnly
|
|
|
|
|
assert.strictEqual(response.url, null);
|
|
|
|
|
assert.strictEqual(response.uri, null);
|
|
|
|
|
assert.strictEqual(response.movedTo, null);
|
|
|
|
|
assert.strictEqual(response.alsoKnownAs, null);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
assert.strictEqual(
|
|
|
|
|
response.createdAt,
|
|
|
|
|
new Date(response.createdAt).toISOString(),
|
|
|
|
|
);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.strictEqual(response.updatedAt, null);
|
|
|
|
|
assert.strictEqual(response.lastFetchedAt, null);
|
|
|
|
|
assert.strictEqual(response.bannerUrl, null);
|
|
|
|
|
assert.strictEqual(response.bannerBlurhash, null);
|
|
|
|
|
assert.strictEqual(response.isLocked, false);
|
|
|
|
|
assert.strictEqual(response.isSilenced, false);
|
|
|
|
|
assert.strictEqual(response.isSuspended, false);
|
|
|
|
|
assert.strictEqual(response.description, null);
|
|
|
|
|
assert.strictEqual(response.location, null);
|
|
|
|
|
assert.strictEqual(response.birthday, null);
|
|
|
|
|
assert.strictEqual(response.lang, null);
|
|
|
|
|
assert.deepStrictEqual(response.fields, []);
|
|
|
|
|
assert.strictEqual(response.followersCount, 0);
|
|
|
|
|
assert.strictEqual(response.followingCount, 0);
|
|
|
|
|
assert.strictEqual(response.notesCount, 0);
|
|
|
|
|
assert.deepStrictEqual(response.pinnedNoteIds, []);
|
|
|
|
|
assert.deepStrictEqual(response.pinnedNotes, []);
|
|
|
|
|
assert.strictEqual(response.pinnedPageId, null);
|
|
|
|
|
assert.strictEqual(response.pinnedPage, null);
|
|
|
|
|
assert.strictEqual(response.publicReactions, false);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
assert.strictEqual(response.ffVisibility, "public");
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.strictEqual(response.twoFactorEnabled, false);
|
|
|
|
|
assert.strictEqual(response.usePasswordLessLogin, false);
|
|
|
|
|
assert.strictEqual(response.securityKeys, false);
|
|
|
|
|
assert.deepStrictEqual(response.roles, []);
|
|
|
|
|
assert.strictEqual(response.memo, null);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
|
2023-05-10 01:52:41 +00:00
|
|
|
|
// MeDetailedOnly
|
|
|
|
|
assert.strictEqual(response.avatarId, null);
|
|
|
|
|
assert.strictEqual(response.bannerId, null);
|
|
|
|
|
assert.strictEqual(response.isModerator, false);
|
|
|
|
|
assert.strictEqual(response.isAdmin, false);
|
|
|
|
|
assert.strictEqual(response.injectFeaturedNote, true);
|
|
|
|
|
assert.strictEqual(response.receiveAnnouncementEmail, true);
|
|
|
|
|
assert.strictEqual(response.alwaysMarkNsfw, false);
|
|
|
|
|
assert.strictEqual(response.autoSensitive, false);
|
|
|
|
|
assert.strictEqual(response.carefulBot, false);
|
|
|
|
|
assert.strictEqual(response.autoAcceptFollowed, true);
|
|
|
|
|
assert.strictEqual(response.noCrawle, false);
|
|
|
|
|
assert.strictEqual(response.preventAiLearning, true);
|
|
|
|
|
assert.strictEqual(response.isExplorable, true);
|
|
|
|
|
assert.strictEqual(response.isDeleted, false);
|
|
|
|
|
assert.strictEqual(response.hideOnlineStatus, false);
|
|
|
|
|
assert.strictEqual(response.hasUnreadSpecifiedNotes, false);
|
|
|
|
|
assert.strictEqual(response.hasUnreadMentions, false);
|
|
|
|
|
assert.strictEqual(response.hasUnreadAnnouncement, false);
|
|
|
|
|
assert.strictEqual(response.hasUnreadAntenna, false);
|
|
|
|
|
assert.strictEqual(response.hasUnreadChannel, false);
|
|
|
|
|
assert.strictEqual(response.hasUnreadNotification, false);
|
|
|
|
|
assert.strictEqual(response.hasPendingReceivedFollowRequest, false);
|
|
|
|
|
assert.deepStrictEqual(response.mutedWords, []);
|
|
|
|
|
assert.deepStrictEqual(response.mutedInstances, []);
|
|
|
|
|
assert.deepStrictEqual(response.mutingNotificationTypes, []);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
assert.deepStrictEqual(response.emailNotificationTypes, [
|
|
|
|
|
"follow",
|
|
|
|
|
"receiveFollowRequest",
|
|
|
|
|
]);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.strictEqual(response.showTimelineReplies, false);
|
|
|
|
|
assert.deepStrictEqual(response.achievements, []);
|
|
|
|
|
assert.deepStrictEqual(response.loggedInDays, 0);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
assert.deepStrictEqual(response.policies, DEFAULT_POLICIES);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.notStrictEqual(response.email, undefined);
|
|
|
|
|
assert.strictEqual(response.emailVerified, false);
|
|
|
|
|
assert.deepStrictEqual(response.securityKeysList, []);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region 自分の情報(i)
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("を読み取ることができること(自分)、キーが過不足なく入っていること。", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
2023-05-13 03:11:41 +00:00
|
|
|
|
endpoint: "i",
|
2023-05-10 01:52:41 +00:00
|
|
|
|
parameters: {},
|
|
|
|
|
user: userNoNote,
|
|
|
|
|
});
|
|
|
|
|
const expected = meDetailed(userNoNote, true);
|
|
|
|
|
expected.loggedInDays = 1; // iはloggedInDaysを更新する
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region 自分の情報の更新(i/update)
|
|
|
|
|
|
|
|
|
|
test.each([
|
|
|
|
|
{ parameters: (): object => ({ name: null }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ parameters: (): object => ({ name: "x".repeat(50) }) },
|
|
|
|
|
{ parameters: (): object => ({ name: "x" }) },
|
|
|
|
|
{ parameters: (): object => ({ name: "My name" }) },
|
2023-05-10 01:52:41 +00:00
|
|
|
|
{ parameters: (): object => ({ description: null }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ parameters: (): object => ({ description: "x".repeat(1500) }) },
|
|
|
|
|
{ parameters: (): object => ({ description: "x" }) },
|
|
|
|
|
{ parameters: (): object => ({ description: "My description" }) },
|
2023-05-10 01:52:41 +00:00
|
|
|
|
{ parameters: (): object => ({ location: null }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ parameters: (): object => ({ location: "x".repeat(50) }) },
|
|
|
|
|
{ parameters: (): object => ({ location: "x" }) },
|
|
|
|
|
{ parameters: (): object => ({ location: "My location" }) },
|
|
|
|
|
{ parameters: (): object => ({ birthday: "0000-00-00" }) },
|
|
|
|
|
{ parameters: (): object => ({ birthday: "9999-99-99" }) },
|
|
|
|
|
{ parameters: (): object => ({ lang: "en-US" }) },
|
2023-05-10 01:52:41 +00:00
|
|
|
|
{ parameters: (): object => ({ fields: [] }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ parameters: (): object => ({ fields: [{ name: "x", value: "x" }] }) },
|
|
|
|
|
{
|
|
|
|
|
parameters: (): object => ({
|
|
|
|
|
fields: [{ name: "x".repeat(3000), value: "x".repeat(3000) }],
|
|
|
|
|
}),
|
|
|
|
|
}, // BUG? fieldには制限がない
|
|
|
|
|
{
|
|
|
|
|
parameters: (): object => ({
|
|
|
|
|
fields: Array(16).fill({ name: "x", value: "y" }),
|
|
|
|
|
}),
|
|
|
|
|
},
|
2023-05-10 01:52:41 +00:00
|
|
|
|
{ parameters: (): object => ({ isLocked: true }) },
|
|
|
|
|
{ parameters: (): object => ({ isLocked: false }) },
|
|
|
|
|
{ parameters: (): object => ({ isExplorable: false }) },
|
|
|
|
|
{ parameters: (): object => ({ isExplorable: true }) },
|
|
|
|
|
{ parameters: (): object => ({ hideOnlineStatus: true }) },
|
|
|
|
|
{ parameters: (): object => ({ hideOnlineStatus: false }) },
|
|
|
|
|
{ parameters: (): object => ({ publicReactions: false }) },
|
|
|
|
|
{ parameters: (): object => ({ publicReactions: true }) },
|
|
|
|
|
{ parameters: (): object => ({ autoAcceptFollowed: true }) },
|
|
|
|
|
{ parameters: (): object => ({ autoAcceptFollowed: false }) },
|
|
|
|
|
{ parameters: (): object => ({ noCrawle: true }) },
|
|
|
|
|
{ parameters: (): object => ({ noCrawle: false }) },
|
|
|
|
|
{ parameters: (): object => ({ preventAiLearning: false }) },
|
|
|
|
|
{ parameters: (): object => ({ preventAiLearning: true }) },
|
|
|
|
|
{ parameters: (): object => ({ isBot: true }) },
|
|
|
|
|
{ parameters: (): object => ({ isBot: false }) },
|
|
|
|
|
{ parameters: (): object => ({ isCat: true }) },
|
|
|
|
|
{ parameters: (): object => ({ isCat: false }) },
|
|
|
|
|
{ parameters: (): object => ({ showTimelineReplies: true }) },
|
|
|
|
|
{ parameters: (): object => ({ showTimelineReplies: false }) },
|
|
|
|
|
{ parameters: (): object => ({ injectFeaturedNote: true }) },
|
|
|
|
|
{ parameters: (): object => ({ injectFeaturedNote: false }) },
|
|
|
|
|
{ parameters: (): object => ({ receiveAnnouncementEmail: true }) },
|
|
|
|
|
{ parameters: (): object => ({ receiveAnnouncementEmail: false }) },
|
|
|
|
|
{ parameters: (): object => ({ alwaysMarkNsfw: true }) },
|
|
|
|
|
{ parameters: (): object => ({ alwaysMarkNsfw: false }) },
|
|
|
|
|
{ parameters: (): object => ({ autoSensitive: true }) },
|
|
|
|
|
{ parameters: (): object => ({ autoSensitive: false }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ parameters: (): object => ({ ffVisibility: "private" }) },
|
|
|
|
|
{ parameters: (): object => ({ ffVisibility: "followers" }) },
|
|
|
|
|
{ parameters: (): object => ({ ffVisibility: "public" }) },
|
|
|
|
|
{ parameters: (): object => ({ mutedWords: Array(19).fill(["xxxxx"]) }) },
|
|
|
|
|
{ parameters: (): object => ({ mutedWords: [["x".repeat(194)]] }) },
|
2023-05-10 01:52:41 +00:00
|
|
|
|
{ parameters: (): object => ({ mutedWords: [] }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ parameters: (): object => ({ mutedInstances: ["xxxx.xxxxx"] }) },
|
2023-05-10 01:52:41 +00:00
|
|
|
|
{ parameters: (): object => ({ mutedInstances: [] }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
parameters: (): object => ({
|
|
|
|
|
mutingNotificationTypes: [
|
|
|
|
|
"follow",
|
|
|
|
|
"mention",
|
|
|
|
|
"reply",
|
|
|
|
|
"renote",
|
|
|
|
|
"quote",
|
|
|
|
|
"reaction",
|
|
|
|
|
"pollEnded",
|
|
|
|
|
"receiveFollowRequest",
|
|
|
|
|
"followRequestAccepted",
|
|
|
|
|
"achievementEarned",
|
|
|
|
|
"app",
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
},
|
2023-05-10 01:52:41 +00:00
|
|
|
|
{ parameters: (): object => ({ mutingNotificationTypes: [] }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
parameters: (): object => ({
|
|
|
|
|
emailNotificationTypes: [
|
|
|
|
|
"mention",
|
|
|
|
|
"reply",
|
|
|
|
|
"quote",
|
|
|
|
|
"follow",
|
|
|
|
|
"receiveFollowRequest",
|
|
|
|
|
],
|
|
|
|
|
}),
|
|
|
|
|
},
|
2023-05-10 01:52:41 +00:00
|
|
|
|
{ parameters: (): object => ({ emailNotificationTypes: [] }) },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
] as const)("を書き換えることができる($#)", async ({ parameters }) => {
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "i/update",
|
|
|
|
|
parameters: parameters(),
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const expected = { ...meDetailed(alice, true), ...parameters() };
|
|
|
|
|
assert.deepStrictEqual(response, expected, inspect(parameters()));
|
|
|
|
|
});
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("を書き換えることができる(Avatar)", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const aliceFile = (await uploadFile(alice)).body;
|
|
|
|
|
const parameters = { avatarId: aliceFile.id };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "i/update",
|
|
|
|
|
parameters: parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
assert.match(response.avatarUrl ?? ".", /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
|
|
|
|
assert.match(response.avatarBlurhash ?? ".", /[ -~]{54}/);
|
|
|
|
|
const expected = {
|
|
|
|
|
...meDetailed(alice, true),
|
2023-05-10 01:52:41 +00:00
|
|
|
|
avatarId: aliceFile.id,
|
|
|
|
|
avatarBlurhash: response.avatarBlurhash,
|
|
|
|
|
avatarUrl: response.avatarUrl,
|
|
|
|
|
};
|
|
|
|
|
assert.deepStrictEqual(response, expected, inspect(parameters));
|
|
|
|
|
|
|
|
|
|
const parameters2 = { avatarId: null };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response2 = await successfulApiCall({
|
|
|
|
|
endpoint: "i/update",
|
|
|
|
|
parameters: parameters2,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected2 = {
|
|
|
|
|
...meDetailed(alice, true),
|
2023-05-10 01:52:41 +00:00
|
|
|
|
avatarId: null,
|
|
|
|
|
avatarBlurhash: null,
|
|
|
|
|
avatarUrl: alice.avatarUrl, // 解除した場合、identiconになる
|
|
|
|
|
};
|
|
|
|
|
assert.deepStrictEqual(response2, expected2, inspect(parameters));
|
|
|
|
|
});
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("を書き換えることができる(Banner)", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const aliceFile = (await uploadFile(alice)).body;
|
|
|
|
|
const parameters = { bannerId: aliceFile.id };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "i/update",
|
|
|
|
|
parameters: parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
assert.match(response.bannerUrl ?? ".", /^[-a-zA-Z0-9@:%._\+~#&?=\/]+$/);
|
|
|
|
|
assert.match(response.bannerBlurhash ?? ".", /[ -~]{54}/);
|
|
|
|
|
const expected = {
|
|
|
|
|
...meDetailed(alice, true),
|
2023-05-10 01:52:41 +00:00
|
|
|
|
bannerId: aliceFile.id,
|
|
|
|
|
bannerBlurhash: response.bannerBlurhash,
|
|
|
|
|
bannerUrl: response.bannerUrl,
|
|
|
|
|
};
|
|
|
|
|
assert.deepStrictEqual(response, expected, inspect(parameters));
|
|
|
|
|
|
|
|
|
|
const parameters2 = { bannerId: null };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response2 = await successfulApiCall({
|
|
|
|
|
endpoint: "i/update",
|
|
|
|
|
parameters: parameters2,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected2 = {
|
|
|
|
|
...meDetailed(alice, true),
|
2023-05-10 01:52:41 +00:00
|
|
|
|
bannerId: null,
|
|
|
|
|
bannerBlurhash: null,
|
|
|
|
|
bannerUrl: null,
|
|
|
|
|
};
|
|
|
|
|
assert.deepStrictEqual(response2, expected2, inspect(parameters));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region 自分の情報の更新(i/pin, i/unpin)
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("を書き換えることができる(ピン止めノート)", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const parameters = { noteId: aliceNote.id };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "i/pin",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = {
|
|
|
|
|
...meDetailed(alice, false),
|
|
|
|
|
pinnedNoteIds: [aliceNote.id],
|
|
|
|
|
pinnedNotes: [aliceNote],
|
|
|
|
|
};
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.deepStrictEqual(response, expected);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
|
|
|
|
|
const response2 = await successfulApiCall({
|
|
|
|
|
endpoint: "i/unpin",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const expected2 = meDetailed(alice, false);
|
|
|
|
|
assert.deepStrictEqual(response2, expected2);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region メモの更新(users/update-memo)
|
|
|
|
|
|
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ label: "最大長", memo: "x".repeat(2048) },
|
|
|
|
|
{ label: "空文字", memo: "", expects: null },
|
|
|
|
|
{ label: "null", memo: null },
|
|
|
|
|
])("を書き換えることができる(メモを$labelに)", async ({ memo, expects }) => {
|
|
|
|
|
const expected = {
|
|
|
|
|
...(await show(bob.id, alice)),
|
|
|
|
|
memo: expects === undefined ? memo : expects,
|
|
|
|
|
};
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const parameters = { userId: bob.id, memo };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "users/update-memo",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const response = await show(bob.id, alice);
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region ユーザー(users)
|
|
|
|
|
|
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "ID昇順",
|
|
|
|
|
parameters: { limit: 5 },
|
|
|
|
|
selector: (u: UserLite): string => u.id,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "フォロワー昇順",
|
|
|
|
|
parameters: { sort: "+follower" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => String(u.followersCount),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "フォロワー降順",
|
|
|
|
|
parameters: { sort: "-follower" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => String(u.followersCount),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "登録日時昇順",
|
|
|
|
|
parameters: { sort: "+createdAt" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => u.createdAt,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "登録日時降順",
|
|
|
|
|
parameters: { sort: "-createdAt" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => u.createdAt,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "投稿日時昇順",
|
|
|
|
|
parameters: { sort: "+updatedAt" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => String(u.updatedAt),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "投稿日時降順",
|
|
|
|
|
parameters: { sort: "-updatedAt" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => String(u.updatedAt),
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"をリスト形式で取得することができる($label)",
|
|
|
|
|
async ({ parameters, selector }) => {
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 結果の並びを事前にアサートするのは困難なので返ってきたidに対応するユーザーが返っており、ソート順が正しいことだけを検証する
|
|
|
|
|
const users = await Promise.all(response.map((u) => show(u.id, alice)));
|
|
|
|
|
const expected = users.sort((x, y) => {
|
|
|
|
|
const index =
|
|
|
|
|
selector(x) < selector(y) ? -1 : selector(x) > selector(y) ? 1 : 0;
|
|
|
|
|
return index * (parameters.sort?.startsWith("+") ? -1 : 1);
|
|
|
|
|
});
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "「見つけやすくする」がOFFのユーザーが含まれない",
|
|
|
|
|
user: (): User => userNotExplorable,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ミュートユーザーが含まれない",
|
|
|
|
|
user: (): User => userMutedByAlice,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックされているユーザーが含まれない",
|
|
|
|
|
user: (): User => userBlockedByAlice,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックしてきているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockingAlice,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{ label: "承認制ユーザーが含まれる", user: (): User => userLocking },
|
|
|
|
|
{ label: "サイレンスユーザーが含まれる", user: (): User => userSilenced },
|
|
|
|
|
{
|
|
|
|
|
label: "サスペンドユーザーが含まれない",
|
|
|
|
|
user: (): User => userSuspended,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{ label: "削除済ユーザーが含まれる", user: (): User => userDeletedBySelf },
|
|
|
|
|
{
|
|
|
|
|
label: "削除済(byAdmin)ユーザーが含まれる",
|
|
|
|
|
user: (): User => userDeletedByAdmin,
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"をリスト形式で取得することができ、結果に$label",
|
|
|
|
|
async ({ user, excluded }) => {
|
|
|
|
|
const parameters = { limit: 100 };
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = excluded ?? false ? [] : [await show(user().id, alice)];
|
|
|
|
|
assert.deepStrictEqual(
|
|
|
|
|
response.filter((u) => u.id === user().id),
|
|
|
|
|
expected,
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
test.todo("をリスト形式で取得することができる(リモート, hostname指定)");
|
|
|
|
|
test.todo("をリスト形式で取得することができる(pagenation)");
|
|
|
|
|
|
2023-05-10 01:52:41 +00:00
|
|
|
|
//#endregion
|
|
|
|
|
//#region ユーザー情報(users/show)
|
|
|
|
|
|
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "ID指定で自分自身を",
|
|
|
|
|
parameters: (): object => ({ userId: alice.id }),
|
|
|
|
|
user: (): User => alice,
|
|
|
|
|
type: meDetailed,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ID指定で他人を",
|
|
|
|
|
parameters: (): object => ({ userId: alice.id }),
|
|
|
|
|
user: (): User => bob,
|
|
|
|
|
type: userDetailedNotMeWithRelations,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ID指定かつ未認証",
|
|
|
|
|
parameters: (): object => ({ userId: alice.id }),
|
|
|
|
|
user: undefined,
|
|
|
|
|
type: userDetailedNotMe,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "@指定で自分自身を",
|
|
|
|
|
parameters: (): object => ({ username: alice.username }),
|
|
|
|
|
user: (): User => alice,
|
|
|
|
|
type: meDetailed,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "@指定で他人を",
|
|
|
|
|
parameters: (): object => ({ username: alice.username }),
|
|
|
|
|
user: (): User => bob,
|
|
|
|
|
type: userDetailedNotMeWithRelations,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "@指定かつ未認証",
|
|
|
|
|
parameters: (): object => ({ username: alice.username }),
|
|
|
|
|
user: undefined,
|
|
|
|
|
type: userDetailedNotMe,
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"を取得することができる($label)",
|
|
|
|
|
async ({ parameters, user, type }) => {
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters: parameters(),
|
|
|
|
|
user: user?.(),
|
|
|
|
|
});
|
|
|
|
|
const expected = type(alice);
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "Administratorになっている",
|
|
|
|
|
user: (): User => userAdmin,
|
|
|
|
|
me: (): User => userAdmin,
|
|
|
|
|
selector: (user: User): unknown => user.isAdmin,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "自分以外から見たときはAdministratorか判定できない",
|
|
|
|
|
user: (): User => userAdmin,
|
|
|
|
|
selector: (user: User): unknown => user.isAdmin,
|
|
|
|
|
expected: (): undefined => undefined,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "Moderatorになっている",
|
|
|
|
|
user: (): User => userModerator,
|
|
|
|
|
me: (): User => userModerator,
|
|
|
|
|
selector: (user: User): unknown => user.isModerator,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "自分以外から見たときはModeratorか判定できない",
|
|
|
|
|
user: (): User => userModerator,
|
|
|
|
|
selector: (user: User): unknown => user.isModerator,
|
|
|
|
|
expected: (): undefined => undefined,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "サイレンスになっている",
|
|
|
|
|
user: (): User => userSilenced,
|
|
|
|
|
selector: (user: User): unknown => user.isSilenced,
|
|
|
|
|
},
|
2023-05-10 01:52:41 +00:00
|
|
|
|
//{ label: 'サスペンドになっている', user: (): User => userSuspended, selector: (user: User): unknown => user.isSuspended },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "削除済みになっている",
|
|
|
|
|
user: (): User => userDeletedBySelf,
|
|
|
|
|
me: (): User => userDeletedBySelf,
|
|
|
|
|
selector: (user: User): unknown => user.isDeleted,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "自分以外から見たときは削除済みか判定できない",
|
|
|
|
|
user: (): User => userDeletedBySelf,
|
|
|
|
|
selector: (user: User): unknown => user.isDeleted,
|
|
|
|
|
expected: (): undefined => undefined,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "削除済み(byAdmin)になっている",
|
|
|
|
|
user: (): User => userDeletedByAdmin,
|
|
|
|
|
me: (): User => userDeletedByAdmin,
|
|
|
|
|
selector: (user: User): unknown => user.isDeleted,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "自分以外から見たときは削除済み(byAdmin)か判定できない",
|
|
|
|
|
user: (): User => userDeletedByAdmin,
|
|
|
|
|
selector: (user: User): unknown => user.isDeleted,
|
|
|
|
|
expected: (): undefined => undefined,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "フォロー中になっている",
|
|
|
|
|
user: (): User => userFollowedByAlice,
|
|
|
|
|
selector: (user: User): unknown => user.isFollowing,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "フォローされている",
|
|
|
|
|
user: (): User => userFollowingAlice,
|
|
|
|
|
selector: (user: User): unknown => user.isFollowed,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロック中になっている",
|
|
|
|
|
user: (): User => userBlockedByAlice,
|
|
|
|
|
selector: (user: User): unknown => user.isBlocking,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックされている",
|
|
|
|
|
user: (): User => userBlockingAlice,
|
|
|
|
|
selector: (user: User): unknown => user.isBlocked,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ミュート中になっている",
|
|
|
|
|
user: (): User => userMutedByAlice,
|
|
|
|
|
selector: (user: User): unknown => user.isMuted,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "リノートミュート中になっている",
|
|
|
|
|
user: (): User => userRnMutedByAlice,
|
|
|
|
|
selector: (user: User): unknown => user.isRenoteMuted,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "フォローリクエスト中になっている",
|
|
|
|
|
user: (): User => userFollowRequested,
|
|
|
|
|
me: (): User => userFollowRequesting,
|
|
|
|
|
selector: (user: User): unknown => user.hasPendingFollowRequestFromYou,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "フォローリクエストされている",
|
|
|
|
|
user: (): User => userFollowRequesting,
|
|
|
|
|
me: (): User => userFollowRequested,
|
|
|
|
|
selector: (user: User): unknown => user.hasPendingFollowRequestToYou,
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"を取得することができ、$labelこと",
|
|
|
|
|
async ({ user, me, selector, expected }) => {
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters: { userId: user().id },
|
|
|
|
|
user: me?.() ?? alice,
|
|
|
|
|
});
|
|
|
|
|
assert.strictEqual(
|
|
|
|
|
selector(response),
|
|
|
|
|
(expected ?? ((): true => true))(),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
test("を取得することができ、Publicなロールがセットされていること", async () => {
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters: { userId: userRolePublic.id },
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.deepStrictEqual(response.badgeRoles, []);
|
2023-05-13 03:11:41 +00:00
|
|
|
|
assert.deepStrictEqual(response.roles, [
|
|
|
|
|
{
|
|
|
|
|
id: rolePublic.id,
|
|
|
|
|
name: rolePublic.name,
|
|
|
|
|
color: rolePublic.color,
|
|
|
|
|
iconUrl: rolePublic.iconUrl,
|
|
|
|
|
description: rolePublic.description,
|
|
|
|
|
isModerator: rolePublic.isModerator,
|
|
|
|
|
isAdministrator: rolePublic.isAdministrator,
|
|
|
|
|
displayOrder: rolePublic.displayOrder,
|
|
|
|
|
},
|
|
|
|
|
]);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
});
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("を取得することができ、バッヂロールがセットされていること", async () => {
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters: { userId: userRoleBadge.id },
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
assert.deepStrictEqual(response.badgeRoles, [
|
|
|
|
|
{
|
|
|
|
|
name: roleBadge.name,
|
|
|
|
|
iconUrl: roleBadge.iconUrl,
|
|
|
|
|
displayOrder: roleBadge.displayOrder,
|
|
|
|
|
},
|
|
|
|
|
]);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.deepStrictEqual(response.roles, []); // バッヂだからといってrolesが取れるとは限らない
|
|
|
|
|
});
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("をID指定のリスト形式で取得することができる(空)", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const parameters = { userIds: [] };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const expected: [] = [];
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("をID指定のリスト形式で取得することができる", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const parameters = { userIds: [bob.id, alice.id, carol.id] };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const expected = [
|
2023-05-13 03:11:41 +00:00
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters: { userId: bob.id },
|
|
|
|
|
user: alice,
|
|
|
|
|
}),
|
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters: { userId: alice.id },
|
|
|
|
|
user: alice,
|
|
|
|
|
}),
|
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters: { userId: carol.id },
|
|
|
|
|
user: alice,
|
|
|
|
|
}),
|
2023-05-10 01:52:41 +00:00
|
|
|
|
];
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "「見つけやすくする」がOFFのユーザーが含まれる",
|
|
|
|
|
user: (): User => userNotExplorable,
|
|
|
|
|
},
|
|
|
|
|
{ label: "ミュートユーザーが含まれる", user: (): User => userMutedByAlice },
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックされているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockedByAlice,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックしてきているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockingAlice,
|
|
|
|
|
},
|
|
|
|
|
{ label: "承認制ユーザーが含まれる", user: (): User => userLocking },
|
|
|
|
|
{ label: "サイレンスユーザーが含まれる", user: (): User => userSilenced },
|
|
|
|
|
{
|
|
|
|
|
label: "サスペンドユーザーが(モデレーターが見るときは)含まれる",
|
|
|
|
|
user: (): User => userSuspended,
|
|
|
|
|
me: (): User => root,
|
|
|
|
|
},
|
2023-05-10 01:52:41 +00:00
|
|
|
|
// BUG サスペンドユーザーを一般ユーザーから見るとrootユーザーが返ってくる
|
|
|
|
|
//{ label: 'サスペンドユーザーが(一般ユーザーが見るときは)含まれない', user: (): User => userSuspended, me: (): User => bob, excluded: true },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ label: "削除済ユーザーが含まれる", user: (): User => userDeletedBySelf },
|
|
|
|
|
{
|
|
|
|
|
label: "削除済(byAdmin)ユーザーが含まれる",
|
|
|
|
|
user: (): User => userDeletedByAdmin,
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"をID指定のリスト形式で取得することができ、結果に$label",
|
|
|
|
|
async ({ user, me, excluded }) => {
|
|
|
|
|
const parameters = { userIds: [user().id] };
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/show",
|
|
|
|
|
parameters,
|
|
|
|
|
user: me?.() ?? alice,
|
|
|
|
|
});
|
|
|
|
|
const expected =
|
|
|
|
|
excluded ?? false ? [] : [await show(user().id, me?.() ?? alice)];
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
test.todo("をID指定のリスト形式で取得することができる(リモート)");
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region 検索(users/search)
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("を検索することができる", async () => {
|
|
|
|
|
const parameters = { query: "carol", limit: 10 };
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/search",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const expected = [await show(carol.id, alice)];
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("を検索することができる(UserLite)", async () => {
|
|
|
|
|
const parameters = { query: "carol", detail: false, limit: 10 };
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/search",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const expected = [userLite(await show(carol.id, alice))];
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "「見つけやすくする」がOFFのユーザーが含まれる",
|
|
|
|
|
user: (): User => userNotExplorable,
|
|
|
|
|
},
|
|
|
|
|
{ label: "ミュートユーザーが含まれる", user: (): User => userMutedByAlice },
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックされているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockedByAlice,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックしてきているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockingAlice,
|
|
|
|
|
},
|
|
|
|
|
{ label: "承認制ユーザーが含まれる", user: (): User => userLocking },
|
|
|
|
|
{ label: "サイレンスユーザーが含まれる", user: (): User => userSilenced },
|
|
|
|
|
{
|
|
|
|
|
label: "サスペンドユーザーが含まれない",
|
|
|
|
|
user: (): User => userSuspended,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{ label: "削除済ユーザーが含まれる", user: (): User => userDeletedBySelf },
|
|
|
|
|
{
|
|
|
|
|
label: "削除済(byAdmin)ユーザーが含まれる",
|
|
|
|
|
user: (): User => userDeletedByAdmin,
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"を検索することができ、結果に$labelが含まれる",
|
|
|
|
|
async ({ user, excluded }) => {
|
|
|
|
|
const parameters = { query: user().username, limit: 1 };
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/search",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = excluded ?? false ? [] : [await show(user().id, alice)];
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
test.todo("を検索することができる(リモート)");
|
|
|
|
|
test.todo("を検索することができる(pagenation)");
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region ID指定検索(users/search-by-username-and-host)
|
|
|
|
|
|
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "自分",
|
|
|
|
|
parameters: { username: "alice" },
|
|
|
|
|
user: (): User[] => [alice],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "自分かつusernameが大文字",
|
|
|
|
|
parameters: { username: "ALICE" },
|
|
|
|
|
user: (): User[] => [alice],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ローカルのフォロイーでノートなし",
|
|
|
|
|
parameters: { username: "userFollowedByAlice" },
|
|
|
|
|
user: (): User[] => [userFollowedByAlice],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ローカルでノートなしは検索に載らない",
|
|
|
|
|
parameters: { username: "userNoNote" },
|
|
|
|
|
user: (): User[] => [],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ローカルの他人1",
|
|
|
|
|
parameters: { username: "bob" },
|
|
|
|
|
user: (): User[] => [bob],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ローカルの他人2",
|
|
|
|
|
parameters: { username: "bob", host: null },
|
|
|
|
|
user: (): User[] => [bob],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ローカルの他人3",
|
|
|
|
|
parameters: { username: "bob", host: "." },
|
|
|
|
|
user: (): User[] => [bob],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ローカル",
|
|
|
|
|
parameters: { host: null, limit: 1 },
|
|
|
|
|
user: (): User[] => [userFollowedByAlice],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ローカル",
|
|
|
|
|
parameters: { host: ".", limit: 1 },
|
|
|
|
|
user: (): User[] => [userFollowedByAlice],
|
|
|
|
|
},
|
|
|
|
|
])("をID&ホスト指定で検索できる($label)", async ({ parameters, user }) => {
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/search-by-username-and-host",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = await Promise.all(user().map((u) => show(u.id, alice)));
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test.each([
|
|
|
|
|
{
|
|
|
|
|
label: "「見つけやすくする」がOFFのユーザーが含まれる",
|
|
|
|
|
user: (): User => userNotExplorable,
|
|
|
|
|
},
|
|
|
|
|
{ label: "ミュートユーザーが含まれる", user: (): User => userMutedByAlice },
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックされているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockedByAlice,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックしてきているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockingAlice,
|
|
|
|
|
},
|
|
|
|
|
{ label: "承認制ユーザーが含まれる", user: (): User => userLocking },
|
|
|
|
|
{ label: "サイレンスユーザーが含まれる", user: (): User => userSilenced },
|
|
|
|
|
{
|
|
|
|
|
label: "サスペンドユーザーが含まれない",
|
|
|
|
|
user: (): User => userSuspended,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{ label: "削除済ユーザーが含まれる", user: (): User => userDeletedBySelf },
|
|
|
|
|
{
|
|
|
|
|
label: "削除済(byAdmin)ユーザーが含まれる",
|
|
|
|
|
user: (): User => userDeletedByAdmin,
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"をID&ホスト指定で検索でき、結果に$label",
|
|
|
|
|
async ({ user, excluded }) => {
|
|
|
|
|
const parameters = { username: user().username };
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/search-by-username-and-host",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = excluded ?? false ? [] : [await show(user().id, alice)];
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
test.todo("をID&ホスト指定で検索できる(リモート)");
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region ID指定検索(users/get-frequently-replied-users)
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("がよくリプライをするユーザーのリストを取得できる", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const parameters = { userId: alice.id, limit: 5 };
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/get-frequently-replied-users",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = await Promise.all(
|
|
|
|
|
usersReplying.slice(0, parameters.limit).map(async (s, i) => ({
|
|
|
|
|
user: await show(s.id, alice),
|
|
|
|
|
weight: (usersReplying.length - i) / usersReplying.length,
|
|
|
|
|
})),
|
|
|
|
|
);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "「見つけやすくする」がOFFのユーザーが含まれる",
|
|
|
|
|
user: (): User => userNotExplorable,
|
|
|
|
|
},
|
|
|
|
|
{ label: "ミュートユーザーが含まれる", user: (): User => userMutedByAlice },
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックされているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockedByAlice,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックしてきているユーザーが含まれない",
|
|
|
|
|
user: (): User => userBlockingAlice,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{ label: "承認制ユーザーが含まれる", user: (): User => userLocking },
|
|
|
|
|
{ label: "サイレンスユーザーが含まれる", user: (): User => userSilenced },
|
2023-05-10 01:52:41 +00:00
|
|
|
|
//{ label: 'サスペンドユーザーが含まれない', user: (): User => userSuspended, excluded: true },
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{ label: "削除済ユーザーが含まれる", user: (): User => userDeletedBySelf },
|
|
|
|
|
{
|
|
|
|
|
label: "削除済(byAdmin)ユーザーが含まれる",
|
|
|
|
|
user: (): User => userDeletedByAdmin,
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"がよくリプライをするユーザーのリストを取得でき、結果に$label",
|
|
|
|
|
async ({ user, excluded }) => {
|
|
|
|
|
const replyTo = (
|
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "users/notes",
|
|
|
|
|
parameters: { userId: user().id },
|
|
|
|
|
user: undefined,
|
|
|
|
|
})
|
|
|
|
|
)[0];
|
|
|
|
|
await post(alice, {
|
|
|
|
|
text: `@${user().username} test`,
|
|
|
|
|
replyId: replyTo.id,
|
|
|
|
|
});
|
|
|
|
|
const parameters = { userId: alice.id, limit: 100 };
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/get-frequently-replied-users",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = excluded ?? false ? [] : [await show(user().id, alice)];
|
|
|
|
|
assert.deepStrictEqual(
|
|
|
|
|
response.map((s) => s.user).filter((u) => u.id === user().id),
|
|
|
|
|
expected,
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region ハッシュタグ(hashtags/users)
|
|
|
|
|
|
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "フォロワー昇順",
|
|
|
|
|
sort: { sort: "+follower" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => String(u.followersCount),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "フォロワー降順",
|
|
|
|
|
sort: { sort: "-follower" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => String(u.followersCount),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "登録日時昇順",
|
|
|
|
|
sort: { sort: "+createdAt" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => u.createdAt,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "登録日時降順",
|
|
|
|
|
sort: { sort: "-createdAt" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => u.createdAt,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "投稿日時昇順",
|
|
|
|
|
sort: { sort: "+updatedAt" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => String(u.updatedAt),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "投稿日時降順",
|
|
|
|
|
sort: { sort: "-updatedAt" },
|
|
|
|
|
selector: (u: UserDetailedNotMe): string => String(u.updatedAt),
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"をハッシュタグ指定で取得することができる($label)",
|
|
|
|
|
async ({ sort, selector }) => {
|
|
|
|
|
const hashtag = "test_hashtag";
|
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "i/update",
|
|
|
|
|
parameters: { description: `#${hashtag}` },
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const parameters = { tag: hashtag, limit: 5, ...sort };
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "hashtags/users",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const users = await Promise.all(response.map((u) => show(u.id, alice)));
|
|
|
|
|
const expected = users.sort((x, y) => {
|
|
|
|
|
const index =
|
|
|
|
|
selector(x) < selector(y) ? -1 : selector(x) > selector(y) ? 1 : 0;
|
|
|
|
|
return index * (parameters.sort.startsWith("+") ? -1 : 1);
|
|
|
|
|
});
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
test.each([
|
2023-05-13 03:11:41 +00:00
|
|
|
|
{
|
|
|
|
|
label: "「見つけやすくする」がOFFのユーザーが含まれる",
|
|
|
|
|
user: (): User => userNotExplorable,
|
|
|
|
|
},
|
|
|
|
|
{ label: "ミュートユーザーが含まれる", user: (): User => userMutedByAlice },
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックされているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockedByAlice,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "ブロックしてきているユーザーが含まれる",
|
|
|
|
|
user: (): User => userBlockingAlice,
|
|
|
|
|
},
|
|
|
|
|
{ label: "承認制ユーザーが含まれる", user: (): User => userLocking },
|
|
|
|
|
{ label: "サイレンスユーザーが含まれる", user: (): User => userSilenced },
|
|
|
|
|
{
|
|
|
|
|
label: "サスペンドユーザーが含まれない",
|
|
|
|
|
user: (): User => userSuspended,
|
|
|
|
|
excluded: true,
|
|
|
|
|
},
|
|
|
|
|
{ label: "削除済ユーザーが含まれる", user: (): User => userDeletedBySelf },
|
|
|
|
|
{
|
|
|
|
|
label: "削除済(byAdmin)ユーザーが含まれる",
|
|
|
|
|
user: (): User => userDeletedByAdmin,
|
|
|
|
|
},
|
|
|
|
|
] as const)(
|
|
|
|
|
"をハッシュタグ指定で取得することができ、結果に$label",
|
|
|
|
|
async ({ user, excluded }) => {
|
|
|
|
|
const hashtag = `user_test${user().username}`;
|
|
|
|
|
if (user() !== userSuspended) {
|
|
|
|
|
// サスペンドユーザーはupdateできない。
|
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "i/update",
|
|
|
|
|
parameters: { description: `#${hashtag}` },
|
|
|
|
|
user: user(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
const parameters = {
|
|
|
|
|
tag: hashtag,
|
|
|
|
|
limit: 100,
|
|
|
|
|
sort: "-follower",
|
|
|
|
|
} as const;
|
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "hashtags/users",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = excluded ?? false ? [] : [await show(user().id, alice)];
|
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
test.todo("をハッシュタグ指定で取得することができる(リモート)");
|
2023-05-10 01:52:41 +00:00
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region オススメユーザー(users/recommendation)
|
|
|
|
|
|
|
|
|
|
// BUG users/recommendationは壊れている? > QueryFailedError: missing FROM-clause entry for table "note"
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test.skip("のオススメを取得することができる", async () => {
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const parameters = {};
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "users/recommendation",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = await Promise.all(response.map((u) => show(u.id)));
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
//#region ピン止めユーザー(pinned-users)
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test("のピン止めユーザーを取得することができる", async () => {
|
|
|
|
|
await successfulApiCall({
|
|
|
|
|
endpoint: "admin/update-meta",
|
|
|
|
|
parameters: { pinnedUsers: [bob.username, `@${carol.username}`] },
|
|
|
|
|
user: root,
|
|
|
|
|
});
|
2023-05-10 01:52:41 +00:00
|
|
|
|
const parameters = {} as const;
|
2023-05-13 03:11:41 +00:00
|
|
|
|
const response = await successfulApiCall({
|
|
|
|
|
endpoint: "pinned-users",
|
|
|
|
|
parameters,
|
|
|
|
|
user: alice,
|
|
|
|
|
});
|
|
|
|
|
const expected = await Promise.all(
|
|
|
|
|
[bob, carol].map((u) => show(u.id, alice)),
|
|
|
|
|
);
|
2023-05-10 01:52:41 +00:00
|
|
|
|
assert.deepStrictEqual(response, expected);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
//#endregion
|
|
|
|
|
|
2023-05-13 03:11:41 +00:00
|
|
|
|
test.todo("を管理人として確認することができる(admin/show-user)");
|
|
|
|
|
test.todo("を管理人として確認することができる(admin/show-users)");
|
|
|
|
|
test.todo("をサーバー向けに取得することができる(federation/users)");
|
2023-05-10 01:52:41 +00:00
|
|
|
|
});
|