Add Prettier for TypeScript formatting

- Install prettier
- Configure .prettierrc.json and .prettierignore
- Add npm scripts: format, format:check
- Add Makefile target: format-frontend
- Format all frontend files
This commit is contained in:
counterweight 2025-12-21 21:59:26 +01:00
parent 4b394b0698
commit 37de6f70e0
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
44 changed files with 906 additions and 856 deletions

View file

@ -162,12 +162,13 @@ describe("ProfilePage - Display", () => {
test("displays empty fields when profile has null values", async () => {
vi.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: () => Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response);
render(<ProfilePage />);
@ -291,7 +292,7 @@ describe("ProfilePage - Form Behavior", () => {
} as Response);
render(<ProfilePage />);
await waitFor(() => {
expect(screen.getByDisplayValue("@testuser")).toBeDefined();
});
@ -308,78 +309,83 @@ describe("ProfilePage - Form Behavior", () => {
test("auto-prepends @ to telegram when user starts with letter", async () => {
vi.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: () => Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response);
render(<ProfilePage />);
await waitFor(() => {
expect(screen.getByRole("heading", { name: "My Profile" })).toBeDefined();
});
const telegramInput = document.getElementById("telegram") as HTMLInputElement;
// Type a letter without @ - should auto-prepend @
fireEvent.change(telegramInput, { target: { value: "myhandle" } });
expect(telegramInput.value).toBe("@myhandle");
});
test("does not auto-prepend @ if user types @ first", async () => {
vi.spyOn(global, "fetch").mockResolvedValue({
ok: true,
json: () => Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response);
render(<ProfilePage />);
await waitFor(() => {
expect(screen.getByRole("heading", { name: "My Profile" })).toBeDefined();
});
const telegramInput = document.getElementById("telegram") as HTMLInputElement;
// User types @ first - no auto-prepend
fireEvent.change(telegramInput, { target: { value: "@myhandle" } });
expect(telegramInput.value).toBe("@myhandle");
});
});
describe("ProfilePage - Form Submission", () => {
test("shows success toast after successful save", async () => {
const fetchSpy = vi.spyOn(global, "fetch")
const fetchSpy = vi
.spyOn(global, "fetch")
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response)
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({
contact_email: "new@example.com",
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: "new@example.com",
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response);
render(<ProfilePage />);
await waitFor(() => {
expect(screen.getByRole("heading", { name: "My Profile" })).toBeDefined();
});
@ -410,27 +416,29 @@ describe("ProfilePage - Form Submission", () => {
vi.spyOn(global, "fetch")
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response)
.mockResolvedValueOnce({
ok: false,
status: 422,
json: () => Promise.resolve({
detail: {
field_errors: {
telegram: "Backend error: invalid handle",
json: () =>
Promise.resolve({
detail: {
field_errors: {
telegram: "Backend error: invalid handle",
},
},
},
}),
}),
} as Response);
render(<ProfilePage />);
await waitFor(() => {
expect(screen.getByRole("heading", { name: "My Profile" })).toBeDefined();
});
@ -452,17 +460,18 @@ describe("ProfilePage - Form Submission", () => {
vi.spyOn(global, "fetch")
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response)
.mockRejectedValueOnce(new Error("Network error"));
render(<ProfilePage />);
await waitFor(() => {
expect(screen.getByRole("heading", { name: "My Profile" })).toBeDefined();
});
@ -489,17 +498,18 @@ describe("ProfilePage - Form Submission", () => {
vi.spyOn(global, "fetch")
.mockResolvedValueOnce({
ok: true,
json: () => Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: null,
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response)
.mockReturnValueOnce(submitPromise as Promise<Response>);
render(<ProfilePage />);
await waitFor(() => {
expect(screen.getByRole("heading", { name: "My Profile" })).toBeDefined();
});
@ -519,12 +529,13 @@ describe("ProfilePage - Form Submission", () => {
// Resolve the promise
resolveSubmit!({
ok: true,
json: () => Promise.resolve({
contact_email: "new@example.com",
telegram: null,
signal: null,
nostr_npub: null,
}),
json: () =>
Promise.resolve({
contact_email: "new@example.com",
telegram: null,
signal: null,
nostr_npub: null,
}),
} as Response);
await waitFor(() => {
@ -532,4 +543,3 @@ describe("ProfilePage - Form Submission", () => {
});
});
});