diff --git a/README.md b/README.md index 60c5a9d..f5954c3 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,12 @@ The application supports various types of Letterboxd URLs for the `LETTERBOXD_UR ### Currently Supported - **Watchlists**: `https://letterboxd.com/username/watchlist/` - **Regular Lists**: `https://letterboxd.com/username/list/list-name/` - -### Planned Support (Coming Soon) -- **Watched Movies**: `https://letterboxd.com/username/films/` - **Actor Filmography**: `https://letterboxd.com/actor/actor-name/` - **Director Filmography**: `https://letterboxd.com/director/director-name/` - **Writer Filmography**: `https://letterboxd.com/writer/writer-name/` + +### Planned Support (Coming Soon) +- **Watched Movies**: `https://letterboxd.com/username/films/` - **Collections**: `https://letterboxd.com/films/in/collection-name/` - **Popular Movies**: `https://letterboxd.com/films/popular/` @@ -32,6 +32,15 @@ LETTERBOXD_URL=https://letterboxd.com/dave/list/official-top-250-narrative-featu # Another user's list LETTERBOXD_URL=https://letterboxd.com/criterion/list/the-criterion-collection/ + +# Actor filmography (e.g., Tom Hanks) +LETTERBOXD_URL=https://letterboxd.com/actor/tom-hanks/ + +# Director filmography (e.g., Christopher Nolan) +LETTERBOXD_URL=https://letterboxd.com/director/christopher-nolan/ + +# Writer filmography (e.g., Aaron Sorkin) +LETTERBOXD_URL=https://letterboxd.com/writer/aaron-sorkin/ ``` **Note**: All Letterboxd lists must be public for the application to access them. diff --git a/src/scraper/index.itest.ts b/src/scraper/index.itest.ts index 44a1445..d8cd633 100644 --- a/src/scraper/index.itest.ts +++ b/src/scraper/index.itest.ts @@ -49,16 +49,48 @@ describe('scraper index integration tests', () => { ).rejects.toThrow('Watched movies scraping not implemented'); }); - it('should throw error for actor filmography (not implemented)', async () => { - await expect( - fetchMoviesFromUrl('https://letterboxd.com/actor/tom-hanks') - ).rejects.toThrow('Actor filmography scraping not implemented'); + it('should fetch movies from actor filmography', async () => { + // Using Tom Hanks' filmography + const movies = await fetchMoviesFromUrl('https://letterboxd.com/actor/tom-hanks'); + + expect(movies).toBeDefined(); + expect(Array.isArray(movies)).toBe(true); + expect(movies.length).toBeGreaterThan(0); + + // Verify structure of returned movies + const firstMovie = movies[0]; + expect(firstMovie).toHaveProperty('id'); + expect(firstMovie).toHaveProperty('name'); + expect(firstMovie).toHaveProperty('slug'); + expect(firstMovie).toHaveProperty('tmdbId'); }); - it('should throw error for director filmography (not implemented)', async () => { - await expect( - fetchMoviesFromUrl('https://letterboxd.com/director/christopher-nolan') - ).rejects.toThrow('Director filmography scraping not implemented'); + it('should fetch movies from director filmography', async () => { + // Using Christopher Nolan's filmography + const movies = await fetchMoviesFromUrl('https://letterboxd.com/director/christopher-nolan'); + + expect(movies).toBeDefined(); + expect(Array.isArray(movies)).toBe(true); + expect(movies.length).toBeGreaterThan(0); + + const firstMovie = movies[0]; + expect(firstMovie).toHaveProperty('id'); + expect(firstMovie).toHaveProperty('name'); + expect(firstMovie).toHaveProperty('slug'); + }); + + it('should fetch movies from writer filmography', async () => { + // Using Charlie Kaufman's filmography + const movies = await fetchMoviesFromUrl('https://letterboxd.com/writer/charlie-kaufman'); + + expect(movies).toBeDefined(); + expect(Array.isArray(movies)).toBe(true); + expect(movies.length).toBeGreaterThan(0); + + const firstMovie = movies[0]; + expect(firstMovie).toHaveProperty('id'); + expect(firstMovie).toHaveProperty('name'); + expect(firstMovie).toHaveProperty('slug'); }); it('should throw error for collections (not implemented)', async () => { diff --git a/src/scraper/index.test.ts b/src/scraper/index.test.ts index c4cb36e..b6dd682 100644 --- a/src/scraper/index.test.ts +++ b/src/scraper/index.test.ts @@ -157,22 +157,64 @@ describe('scraper index', () => { ); }); - it('should throw error for actor filmography (not implemented)', async () => { - await expect( - fetchMoviesFromUrl('https://letterboxd.com/actor/tom-hanks') - ).rejects.toThrow('Actor filmography scraping not implemented'); + it('should fetch movies from actor filmography URL', async () => { + const mockMovies = [ + { id: 1, name: 'Movie 1', slug: '/film/movie1/', tmdbId: '123', imdbId: null, publishedYear: null }, + ]; + + const mockGetMovies = jest.fn().mockResolvedValue(mockMovies); + (ListScraper as jest.Mock).mockImplementation(() => ({ + getMovies: mockGetMovies, + })); + + const result = await fetchMoviesFromUrl('https://letterboxd.com/actor/tom-hanks'); + + expect(result).toEqual(mockMovies); + expect(ListScraper).toHaveBeenCalledWith( + 'https://letterboxd.com/actor/tom-hanks', + undefined, + undefined + ); }); - it('should throw error for director filmography (not implemented)', async () => { - await expect( - fetchMoviesFromUrl('https://letterboxd.com/director/steven-spielberg') - ).rejects.toThrow('Director filmography scraping not implemented'); + it('should fetch movies from director filmography URL', async () => { + const mockMovies = [ + { id: 1, name: 'Movie 1', slug: '/film/movie1/', tmdbId: '123', imdbId: null, publishedYear: null }, + ]; + + const mockGetMovies = jest.fn().mockResolvedValue(mockMovies); + (ListScraper as jest.Mock).mockImplementation(() => ({ + getMovies: mockGetMovies, + })); + + const result = await fetchMoviesFromUrl('https://letterboxd.com/director/steven-spielberg'); + + expect(result).toEqual(mockMovies); + expect(ListScraper).toHaveBeenCalledWith( + 'https://letterboxd.com/director/steven-spielberg', + undefined, + undefined + ); }); - it('should throw error for writer filmography (not implemented)', async () => { - await expect( - fetchMoviesFromUrl('https://letterboxd.com/writer/aaron-sorkin') - ).rejects.toThrow('Writer filmography scraping not implemented'); + it('should fetch movies from writer filmography URL', async () => { + const mockMovies = [ + { id: 1, name: 'Movie 1', slug: '/film/movie1/', tmdbId: '123', imdbId: null, publishedYear: null }, + ]; + + const mockGetMovies = jest.fn().mockResolvedValue(mockMovies); + (ListScraper as jest.Mock).mockImplementation(() => ({ + getMovies: mockGetMovies, + })); + + const result = await fetchMoviesFromUrl('https://letterboxd.com/writer/aaron-sorkin'); + + expect(result).toEqual(mockMovies); + expect(ListScraper).toHaveBeenCalledWith( + 'https://letterboxd.com/writer/aaron-sorkin', + undefined, + undefined + ); }); it('should throw error for collections (not implemented)', async () => { diff --git a/src/scraper/index.ts b/src/scraper/index.ts index 978f7c6..f20fe71 100644 --- a/src/scraper/index.ts +++ b/src/scraper/index.ts @@ -51,36 +51,28 @@ export const fetchMoviesFromUrl = async (url: string): Promise