More API tests, fixes

This commit is contained in:
Jesse Wierzbinski 2023-10-22 15:47:04 -10:00
parent 932fc3e4f5
commit d05b077df1
No known key found for this signature in database
GPG key ID: F9A1E418934E40B0
10 changed files with 90 additions and 28 deletions

View file

@ -88,6 +88,7 @@ Working endpoints are:
- `/api/v1/accounts/verify_credentials`
- `/api/v1/accounts/familiar_followers`
- `/api/v1/statuses/:id` (`GET`, `DELETE`)
- `/api/v1/statuses/:id/context`
- `/api/v1/statuses`
- `/api/v1/timelines/public`
- `/api/v1/apps`

View file

@ -21,6 +21,21 @@ import { Instance } from "./Instance";
const config = getConfig();
export const statusRelations = [
"account",
"reblog",
"object",
"in_reply_to_post",
"instance",
"in_reply_to_account",
"in_reply_to_post.account",
"application",
"emojis",
"mentions",
"likes",
"announces",
];
/**
* Represents a status (i.e. a post)
*/
@ -57,8 +72,9 @@ export class Status extends BaseEntity {
*/
@ManyToOne(() => Status, status => status.id, {
nullable: true,
onDelete: "SET NULL",
})
reblog?: Status;
reblog?: Status | null;
/**
* The raw object associated with this status.
@ -94,6 +110,7 @@ export class Status extends BaseEntity {
*/
@ManyToOne(() => Status, {
nullable: true,
onDelete: "SET NULL",
})
in_reply_to_post!: Status | null;
@ -229,9 +246,7 @@ export class Status extends BaseEntity {
where: {
id: id,
},
relations: {
in_reply_to_post: true,
},
relations: statusRelations,
});
if (currentStatus) {
@ -279,9 +294,7 @@ export class Status extends BaseEntity {
id: status.id,
},
},
relations: {
in_reply_to_post: true,
},
relations: statusRelations,
});
for (const status of currentStatus) {
@ -443,6 +456,8 @@ export class Status extends BaseEntity {
return {
...(await this.object.toAPI()),
id: this.id,
in_reply_to_id: this.in_reply_to_post?.id || null,
in_reply_to_account_id: this.in_reply_to_post?.account.id || null,
};
}
}

View file

@ -21,7 +21,7 @@ import {
} from "activitypub-types";
import { RawObject } from "./RawObject";
import { Token } from "./Token";
import { Status } from "./Status";
import { Status, statusRelations } from "./Status";
import { APISource } from "~types/entities/source";
import { Relationship } from "./Relationship";
import { Instance } from "./Instance";
@ -368,9 +368,7 @@ export class User extends BaseEntity {
id: this.id,
},
},
relations: {
object: true,
},
relations: statusRelations,
});
// Delete both

View file

@ -1,6 +1,6 @@
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import { Status } from "~database/entities/Status";
import { Status, statusRelations } from "~database/entities/Status";
import { User } from "~database/entities/User";
import { applyConfig } from "@api";
@ -60,7 +60,7 @@ export default async (
},
isReblog: exclude_reblogs ? true : undefined,
},
relations: ["account", "emojis", "announces", "likes", "object"],
relations: statusRelations,
order: {
created_at: "DESC",
},

View file

@ -1,7 +1,7 @@
import { applyConfig } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import { Status } from "~database/entities/Status";
import { Status, statusRelations } from "~database/entities/Status";
import { User } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
@ -32,8 +32,11 @@ export default async (
let foundStatus: Status | null;
try {
foundStatus = await Status.findOneBy({
foundStatus = await Status.findOne({
where: {
id,
},
relations: statusRelations,
});
} catch (e) {
return errorResponse("Invalid ID", 404);

View file

@ -1,7 +1,7 @@
import { applyConfig } from "@api";
import { errorResponse, jsonResponse } from "@response";
import { MatchedRoute } from "bun";
import { Status } from "~database/entities/Status";
import { Status, statusRelations } from "~database/entities/Status";
import { User } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
@ -35,7 +35,7 @@ export default async (
where: {
id,
},
relations: ["account", "object"],
relations: statusRelations,
});
} catch (e) {
return errorResponse("Invalid ID", 404);

View file

@ -11,7 +11,7 @@ import { sanitize } from "isomorphic-dompurify";
import { parse } from "marked";
import { Application } from "~database/entities/Application";
import { RawObject } from "~database/entities/RawObject";
import { Status } from "~database/entities/Status";
import { Status, statusRelations } from "~database/entities/Status";
import { User } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
@ -132,9 +132,7 @@ export default async (req: Request): Promise<Response> => {
where: {
id: in_reply_to_id,
},
relations: {
account: true,
},
relations: statusRelations,
});
replyUser = replyStatus?.account || null;

View file

@ -3,7 +3,7 @@ import { applyConfig } from "@api";
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { FindManyOptions } from "typeorm";
import { Status } from "~database/entities/Status";
import { Status, statusRelations } from "~database/entities/Status";
import { User } from "~database/entities/User";
import { APIRouteMeta } from "~types/api";
@ -60,7 +60,7 @@ export default async (req: Request): Promise<Response> => {
created_at: "DESC",
},
take: limit,
relations: ["object"],
relations: statusRelations,
};
if (max_id) {

View file

@ -3,7 +3,7 @@ import { applyConfig } from "@api";
import { parseRequest } from "@request";
import { errorResponse, jsonResponse } from "@response";
import { FindManyOptions, IsNull, Not } from "typeorm";
import { Status } from "~database/entities/Status";
import { Status, statusRelations } from "~database/entities/Status";
import { APIRouteMeta } from "~types/api";
export const meta: APIRouteMeta = applyConfig({
@ -56,7 +56,7 @@ export default async (req: Request): Promise<Response> => {
created_at: "DESC",
},
take: limit,
relations: ["object"],
relations: statusRelations,
};
if (max_id) {

View file

@ -20,6 +20,7 @@ let token: Token;
let user: User;
let user2: User;
let status: APIStatus | null = null;
let status2: APIStatus | null = null;
describe("API Tests", () => {
beforeAll(async () => {
@ -153,6 +154,52 @@ describe("API Tests", () => {
expect(status.in_reply_to_id).toBeNull();
expect(status.in_reply_to_account_id).toBeNull();
});
test("should create a new status in reply to the previous one", async () => {
const response = await fetch(
`${config.http.base_url}/api/v1/statuses`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token.access_token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
status: "This is a reply!",
visibility: "public",
in_reply_to_id: status?.id,
}),
}
);
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toBe(
"application/json"
);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
status2 = (await response.json()) as APIStatus;
expect(status2.content).toBe("This is a reply!");
expect(status2.visibility).toBe("public");
expect(status2.account.id).toBe(user.id);
expect(status2.replies_count).toBe(0);
expect(status2.favourites_count).toBe(0);
expect(status2.reblogged).toBe(false);
expect(status2.favourited).toBe(false);
expect(status2.media_attachments).toEqual([]);
expect(status2.mentions).toEqual([]);
expect(status2.tags).toEqual([]);
expect(status2.sensitive).toBe(false);
expect(status2.spoiler_text).toBe("");
expect(status2.language).toBeNull();
expect(status2.pinned).toBe(false);
expect(status2.visibility).toBe("public");
expect(status2.card).toBeNull();
expect(status2.poll).toBeNull();
expect(status2.emojis).toEqual([]);
expect(status2.in_reply_to_id).toEqual(status?.id);
expect(status2.in_reply_to_account_id).toEqual(user.id);
});
});
describe("GET /api/v1/timelines/public", () => {
@ -270,9 +317,9 @@ describe("API Tests", () => {
const statuses = (await response.json()) as APIStatus[];
expect(statuses.length).toBe(1);
expect(statuses.length).toBe(2);
const status1 = statuses[0];
const status1 = statuses[1];
// Basic validation
expect(status1.content).toBe("Hello, world!");