gphotos-scraper
Version:
A tool to extract public url and metadata from shared album
110 lines (96 loc) • 2.68 kB
text/typescript
import { beforeEach, describe, expect, it, vi } from "vitest";
import { AlbumNotFoundException } from "../exceptions";
import { apiClient } from "./axiosClient";
import { getAlbum } from "./getAlbum";
vi.mock("./axiosClient", () => ({
apiClient: {
get: vi.fn(),
post: vi.fn(),
},
}));
describe("getAlbum", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("should throw AlbumNotFoundException if canonical URL is missing", async () => {
(apiClient.get as any).mockResolvedValue({ data: "<html></html>" });
await expect(getAlbum("http://example.com")).rejects.toThrow(
AlbumNotFoundException,
);
});
it("should parse album metadata correctly", async () => {
const mockHtml = `
<html>
<head>
<link rel="canonical" href="https://photos.app.goo.gl/ALBUM_ID" />
</head>
<script>var x = "key=ALBUM_KEY";</script>
</html>
`;
(apiClient.get as any).mockResolvedValue({ data: mockHtml });
// Constructing the complex RPC response structure expected by getAlbum.ts
// parsedResponse indices:
// 1: albumItems (array)
// 2: nextToken (string)
// 3: albumDetails (array) -> [id, title, [dates...], downloadUrl, cover, owner...]
// albumDetails indices:
// 0: id
// 1: title
// 2: dates -> [,,,4:createdAt,,,,8:updatedAt]
// 3: downloadUrl (not used in destructuring directly, but index 32 is sharedUrl? No, let's check code)
// Code: const [albumId, albumTitle, albumDates, downloadUrl, albumCover, albumOwner] = albumDetails;
// Index 32: sharedUrl
const albumDates = [
null,
null,
null,
null,
1600000000,
null,
null,
null,
1600000000,
];
const albumCover = ["cover_url", 100, 100];
const albumOwner = [
null,
"OwnerID",
null,
"OwnerPhoto",
null,
null,
null,
null,
null,
null,
null,
["Owner Fullname", null, null, "Owner Name"],
];
const albumDetails: any[] = [
"ALBUM_ID",
"Album Title",
albumDates,
"DownloadUrl",
albumCover,
albumOwner,
];
// pad to index 32 for sharedUrl
for (let i = 6; i < 32; i++) albumDetails.push(null);
albumDetails[32] = "SharedUrl";
const parsedResponse = [
null,
[], // albumItems
"NextToken",
albumDetails,
];
const mockRpcResponse =
`)]}'` +
JSON.stringify([["w", "snAcKc", JSON.stringify(parsedResponse)]]);
(apiClient.post as any).mockResolvedValue({ data: mockRpcResponse });
const album = await getAlbum("http://example.com");
expect(album.id).toBe("ALBUM_ID");
expect(album.title).toBe("Album Title");
expect(album.key).toBe("ALBUM_KEY");
expect(album.owner?.fullname).toBe("Owner Fullname");
});
});