Media upload for avatars and banners, more work, fix tests

This commit is contained in:
Jesse Wierzbinski 2023-10-19 09:53:59 -10:00
parent 16cfd5d900
commit 460b68c381
No known key found for this signature in database
GPG key ID: F9A1E418934E40B0
17 changed files with 360 additions and 139 deletions

View file

@ -23,27 +23,34 @@ beforeAll(async () => {
describe("POST /@test/actor", () => {
test("should return a valid ActivityPub Actor when querying an existing user", async () => {
const response = await fetch(`${config.http.base_url}/users/test/actor`, {
method: "GET",
headers: {
Accept: "application/activity+json",
},
});
const response = await fetch(
`${config.http.base_url}/users/test/actor`,
{
method: "GET",
headers: {
Accept: "application/activity+json",
},
}
);
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toBe(
"application/activity+json"
);
const actor: APActor = await response.json();
const actor = (await response.json()) as APActor;
expect(actor.type).toBe("Person");
expect(actor.id).toBe(`${config.http.base_url}/users/test`);
expect(actor.preferredUsername).toBe("test");
expect(actor.inbox).toBe(`${config.http.base_url}/users/test/inbox`);
expect(actor.outbox).toBe(`${config.http.base_url}/users/test/outbox`);
expect(actor.followers).toBe(`${config.http.base_url}/users/test/followers`);
expect(actor.following).toBe(`${config.http.base_url}/users/test/following`);
expect(actor.followers).toBe(
`${config.http.base_url}/users/test/followers`
);
expect(actor.following).toBe(
`${config.http.base_url}/users/test/following`
);
expect((actor as any).publicKey).toBeDefined();
expect((actor as any).publicKey.id).toBeDefined();
expect((actor as any).publicKey.owner).toBe(
@ -82,4 +89,6 @@ afterAll(async () => {
if (user) {
await user.remove();
}
await AppDataSource.destroy();
});

View file

@ -66,6 +66,28 @@ describe("API Tests", () => {
token = await token.save();
});
afterAll(async () => {
const activities = await RawActivity.createQueryBuilder("activity")
.where("activity.data->>'actor' = :actor", {
actor: `${config.http.base_url}/users/test`,
})
.leftJoinAndSelect("activity.objects", "objects")
.getMany();
// Delete all created objects and activities as part of testing
for (const activity of activities) {
for (const object of activity.objects) {
await object.remove();
}
await activity.remove();
}
await user.remove();
await user2.remove();
await AppDataSource.destroy();
});
describe("POST /api/v1/accounts/:id", () => {
test("should return a 404 error when trying to fetch a non-existent user", async () => {
const response = await fetch(
@ -150,7 +172,7 @@ describe("API Tests", () => {
"application/json"
);
const statuses: APIStatus[] = await response.json();
const statuses = (await response.json()) as APIStatus[];
expect(statuses.some(s => s.id === status?.id)).toBe(true);
});
@ -177,7 +199,7 @@ describe("API Tests", () => {
"application/json"
);
const user: APIAccount = await response.json();
const user = (await response.json()) as APIAccount;
expect(user.display_name).toBe("New Display Name");
});
@ -201,7 +223,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIAccount = await response.json();
const account = (await response.json()) as APIAccount;
expect(account.username).toBe(user.username);
expect(account.bot).toBe(false);
@ -246,7 +268,7 @@ describe("API Tests", () => {
"application/json"
);
const statuses: APIStatus[] = await response.json();
const statuses = (await response.json()) as APIStatus[];
expect(statuses.length).toBe(1);
@ -278,7 +300,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.following).toBe(true);
@ -304,7 +326,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.following).toBe(false);
@ -330,7 +352,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.followed_by).toBe(false);
@ -356,7 +378,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.blocking).toBe(true);
@ -382,7 +404,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.blocking).toBe(false);
@ -408,7 +430,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.muting).toBe(true);
@ -433,7 +455,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.muting).toBe(true);
@ -460,7 +482,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.muting).toBe(false);
@ -486,7 +508,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.endorsed).toBe(true);
@ -512,7 +534,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIRelationship = await response.json();
const account = (await response.json()) as APIRelationship;
expect(account.id).toBe(user2.id);
expect(account.endorsed).toBe(false);
@ -538,7 +560,7 @@ describe("API Tests", () => {
"application/json"
);
const account: APIAccount = await response.json();
const account = (await response.json()) as APIAccount;
expect(account.id).toBe(user2.id);
expect(account.note).toBe("This is a new note");
@ -562,7 +584,7 @@ describe("API Tests", () => {
"application/json"
);
const relationships: APIRelationship[] = await response.json();
const relationships = (await response.json()) as APIRelationship[];
expect(Array.isArray(relationships)).toBe(true);
expect(relationships.length).toBeGreaterThan(0);
@ -595,8 +617,10 @@ describe("API Tests", () => {
"application/json"
);
const familiarFollowers: { id: string; accounts: APIAccount[] }[] =
await response.json();
const familiarFollowers = (await response.json()) as {
id: string;
accounts: APIAccount[];
}[];
expect(Array.isArray(familiarFollowers)).toBe(true);
expect(familiarFollowers.length).toBeGreaterThan(0);
@ -657,7 +681,7 @@ describe("API Tests", () => {
"application/json"
);
const statusJson = await response.json();
const statusJson = (await response.json()) as APIStatus;
expect(statusJson.id).toBe(status?.id);
expect(statusJson.content).toBeDefined();
@ -718,7 +742,7 @@ describe("API Tests", () => {
"application/json"
);
const instance: APIInstance = await response.json();
const instance = (await response.json()) as APIInstance;
expect(instance.uri).toBe(new URL(config.http.base_url).hostname);
expect(instance.title).toBeDefined();
@ -764,7 +788,7 @@ describe("API Tests", () => {
"application/json"
);
const emojis: APIEmoji[] = await response.json();
const emojis = (await response.json()) as APIEmoji[];
expect(emojis.length).toBeGreaterThan(0);
expect(emojis[0].shortcode).toBe("test");
@ -774,26 +798,4 @@ describe("API Tests", () => {
await Emoji.delete({ shortcode: "test" });
});
});
afterAll(async () => {
const activities = await RawActivity.createQueryBuilder("activity")
.where("activity.data->>'actor' = :actor", {
actor: `${config.http.base_url}/users/test`,
})
.leftJoinAndSelect("activity.objects", "objects")
.getMany();
// Delete all created objects and activities as part of testing
await Promise.all(
activities.map(async activity => {
await Promise.all(
activity.objects.map(async object => await object.remove())
);
await activity.remove();
})
);
await user.remove();
await user2.remove();
});
});

View file

@ -37,4 +37,6 @@ describe("Instance", () => {
afterAll(async () => {
await instance.remove();
await AppDataSource.destroy();
});

View file

@ -1,17 +1,27 @@
import { getConfig } from "@config";
import { ConfigType, getConfig } from "@config";
import { afterAll, beforeAll, describe, expect, it } from "bun:test";
import { LocalBackend, S3Backend } from "~classes/media";
import { unlink } from "fs/promises";
import { DeleteObjectCommand } from "@aws-sdk/client-s3";
const config = getConfig();
const originalConfig = getConfig();
const modifiedConfig: ConfigType = {
...originalConfig,
media: {
...originalConfig.media,
conversion: {
...originalConfig.media.conversion,
convert_images: false,
},
},
};
describe("LocalBackend", () => {
let localBackend: LocalBackend;
let fileName: string;
beforeAll(() => {
localBackend = new LocalBackend();
localBackend = new LocalBackend(modifiedConfig);
});
afterAll(async () => {
@ -25,7 +35,7 @@ describe("LocalBackend", () => {
});
const hash = await localBackend.addMedia(media);
fileName = `${hash}`;
fileName = hash;
expect(hash).toBeDefined();
});
@ -33,16 +43,14 @@ describe("LocalBackend", () => {
describe("getMediaByHash", () => {
it("should retrieve the file from the local filesystem and return it as a File object", async () => {
const media = await localBackend.getMediaByHash(fileName, "txt");
const media = await localBackend.getMediaByHash(fileName);
expect(media).toBeInstanceOf(File);
});
it("should return null if the file does not exist", async () => {
const media = await localBackend.getMediaByHash(
"does-not-exist",
"txt"
);
const media =
await localBackend.getMediaByHash("does-not-exist.txt");
expect(media).toBeNull();
});
@ -50,12 +58,12 @@ describe("LocalBackend", () => {
});
describe("S3Backend", () => {
const s3Backend = new S3Backend(config);
const s3Backend = new S3Backend(modifiedConfig);
let fileName: string;
afterAll(async () => {
const command = new DeleteObjectCommand({
Bucket: config.s3.bucket_name,
Bucket: modifiedConfig.s3.bucket_name,
Key: fileName,
});
@ -69,7 +77,7 @@ describe("S3Backend", () => {
});
const hash = await s3Backend.addMedia(media);
fileName = `${hash}`;
fileName = hash;
expect(hash).toBeDefined();
});
@ -77,16 +85,13 @@ describe("S3Backend", () => {
describe("getMediaByHash", () => {
it("should retrieve the file from the S3 bucket and return it as a File object", async () => {
const media = await s3Backend.getMediaByHash(fileName, "txt");
const media = await s3Backend.getMediaByHash(fileName);
expect(media).toBeInstanceOf(File);
});
it("should return null if the file does not exist", async () => {
const media = await s3Backend.getMediaByHash(
"does-not-exist",
"txt"
);
const media = await s3Backend.getMediaByHash("does-not-exist.txt");
expect(media).toBeNull();
});

View file

@ -210,6 +210,7 @@ describe("POST /@test/inbox", () => {
manuallyApprovesFollowers: false,
followers: `${config.http.base_url}/users/test/followers`,
following: `${config.http.base_url}/users/test/following`,
published: expect.any(String),
name: "",
"@context": [
"https://www.w3.org/ns/activitystreams",
@ -217,11 +218,11 @@ describe("POST /@test/inbox", () => {
],
icon: {
type: "Image",
url: "",
url: expect.any(String),
},
image: {
type: "Image",
url: "",
url: expect.any(String),
},
inbox: `${config.http.base_url}/users/test/inbox`,
type: "Person",
@ -311,4 +312,6 @@ afterAll(async () => {
await Promise.all(tokens.map(async token => await token.remove()));
if (user) await user.remove();
await AppDataSource.destroy();
});

View file

@ -33,6 +33,7 @@ describe("POST /api/v1/apps/", () => {
formData.append("redirect_uris", "https://example.com");
formData.append("scopes", "read write");
// @ts-expect-error FormData works
const response = await fetch(`${config.http.base_url}/api/v1/apps/`, {
method: "POST",
body: formData,
@ -42,7 +43,7 @@ describe("POST /api/v1/apps/", () => {
expect(response.headers.get("content-type")).toBe("application/json");
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const json = await response.json();
const json = (await response.json()) as any;
expect(json).toEqual({
id: expect.any(String),
@ -67,6 +68,8 @@ describe("POST /auth/login/", () => {
formData.append("email", "test@test.com");
formData.append("password", "test");
// @ts-expect-error FormData works
const response = await fetch(
`${config.http.base_url}/auth/login/?client_id=${client_id}&redirect_uri=https://example.com&response_type=code&scope=read+write`,
{
@ -96,13 +99,17 @@ describe("POST /oauth/token/", () => {
formData.append("client_secret", client_secret);
formData.append("scope", "read+write");
// @ts-expect-error FormData works
const response = await fetch(`${config.http.base_url}/oauth/token/`, {
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
},
body: formData,
});
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const json = await response.json();
const json = (await response.json()) as any;
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toBe("application/json");
@ -134,7 +141,7 @@ describe("GET /api/v1/apps/verify_credentials", () => {
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toBe("application/json");
const credentials: Partial<Application> = await response.json();
const credentials = (await response.json()) as Partial<Application>;
expect(credentials.name).toBe("Test Application");
expect(credentials.website).toBe("https://example.com");
@ -167,4 +174,6 @@ afterAll(async () => {
);
if (user) await user.remove();
await AppDataSource.destroy();
});