feat: revamp portfolio with case studies, curriculo page, and local SEO
Adds dynamic case study and curriculo routes, project health monitoring for live demo status, and strengthens local SEO (structured data, service-area targeting for Garuva/Joinville/Curitiba, a dedicated "criação de sites" service page) so search results better match the professional title (Engenheiro da Computação) and experience (5 anos). Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
1 parent
9236fdd685
commit
d76bbf5974
41 files changed
+1359
-492
No files matched your search
@@ -0,0 +1,87 @@
|
||||
import {
|
||||
createProjectHealthSnapshot,
|
||||
filterLiveProjects,
|
||||
isCurrentLiveCheck,
|
||||
type ProjectHealthSnapshot,
|
||||
} from "./project-health";
|
||||
|
||||
describe("project health snapshot", () => {
|
||||
const now = new Date("2026-07-10T12:00:00.000Z");
|
||||
const snapshot: ProjectHealthSnapshot = {
|
||||
checkedAt: "2026-07-10T11:55:00.000Z",
|
||||
projects: {
|
||||
online: {
|
||||
status: 200,
|
||||
contentType: "text/html; charset=utf-8",
|
||||
checkedAt: "2026-07-10T11:55:00.000Z",
|
||||
},
|
||||
redirect: {
|
||||
status: 301,
|
||||
contentType: "text/html",
|
||||
checkedAt: "2026-07-10T11:55:00.000Z",
|
||||
},
|
||||
stale: {
|
||||
status: 200,
|
||||
contentType: "text/html",
|
||||
checkedAt: "2026-07-10T10:30:00.000Z",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it("accepts only fresh final HTTP 200 HTML projects", () => {
|
||||
expect(isCurrentLiveCheck(snapshot.projects.online, now)).toBe(true);
|
||||
expect(isCurrentLiveCheck(snapshot.projects.redirect, now)).toBe(false);
|
||||
expect(isCurrentLiveCheck(snapshot.projects.stale, now)).toBe(false);
|
||||
|
||||
expect(
|
||||
filterLiveProjects(
|
||||
[
|
||||
{ id: "online", featured: true },
|
||||
{ id: "redirect", featured: true },
|
||||
{ id: "stale", featured: true },
|
||||
{ id: "hidden", featured: false },
|
||||
],
|
||||
snapshot,
|
||||
now,
|
||||
).map((project) => project.id),
|
||||
).toEqual(["online"]);
|
||||
});
|
||||
|
||||
it("fails closed when the snapshot is absent or expired", () => {
|
||||
expect(
|
||||
filterLiveProjects([{ id: "online", featured: true }], null, now),
|
||||
).toEqual([]);
|
||||
expect(
|
||||
filterLiveProjects(
|
||||
[{ id: "online", featured: true }],
|
||||
{ ...snapshot, checkedAt: "2026-07-10T10:00:00.000Z" },
|
||||
now,
|
||||
),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("creates a fresh health snapshot when the stored result is unavailable", async () => {
|
||||
const fetcher = jest.fn(async (url: string) => ({
|
||||
status: url.includes("online") ? 200 : 503,
|
||||
url,
|
||||
headers: new Headers({
|
||||
"content-type": url.includes("online") ? "text/html" : "text/plain",
|
||||
}),
|
||||
body: { cancel: jest.fn() },
|
||||
}));
|
||||
|
||||
const result = await createProjectHealthSnapshot(
|
||||
[
|
||||
{ id: "online", demoUrl: "https://online.example" },
|
||||
{ id: "offline", demoUrl: "https://offline.example" },
|
||||
],
|
||||
fetcher,
|
||||
new Date("2026-07-10T12:00:00.000Z"),
|
||||
);
|
||||
|
||||
expect(result.projects.online.status).toBe(200);
|
||||
expect(result.projects.online.contentType).toBe("text/html");
|
||||
expect(result.projects.offline.status).toBe(503);
|
||||
expect(fetcher).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user