-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: break up monolithic jobs into smaller pieces
- Loading branch information
Showing
11 changed files
with
421 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { getDiscoveryMovies } from '@/actions/movie/get-discovery-movies.js'; | ||
import { ENDPOINTS } from '@/test/msw/handlers.js'; | ||
import { server } from '@/test/msw/server.js'; | ||
import { http, HttpResponse } from 'msw'; | ||
|
||
describe('getDiscoveryMovies', () => { | ||
server.listen(); | ||
|
||
it('returns a list of movies with the expected properties', async () => { | ||
const movies = await getDiscoveryMovies(); | ||
|
||
const movie = movies[0]; | ||
expect(movie).toHaveProperty('id'); | ||
expect(movie).toHaveProperty('title'); | ||
expect(movie).toHaveProperty('overview'); | ||
expect(movie).toHaveProperty('release_date'); | ||
expect(movie).toHaveProperty('poster_path'); | ||
}); | ||
|
||
it('throws an error if any of the requests fail', async () => { | ||
server.use( | ||
http.get( | ||
ENDPOINTS.movieDb.discover, | ||
() => { | ||
return HttpResponse.error(); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
await expect(getDiscoveryMovies()) | ||
.rejects | ||
.toThrow(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { getDiscoverMovie } from '@/api/moviedb.js'; | ||
import { type Movie } from '@/types/moviedb.js'; | ||
import { appLogger } from '@/utils/logger.js'; | ||
import { getAdjacentDayInYear } from './get-adjacent-year-date.js'; | ||
import { getYearsRange } from './get-years-range.js'; | ||
|
||
export async function getDiscoveryMovies(): Promise<Movie[]> { | ||
let allMovies: Movie[] = []; | ||
const years = getYearsRange(); | ||
|
||
const promises = years | ||
.map(async (releaseYear) => { | ||
/** | ||
* The Movie Database API does not have a method to request movies | ||
* released on a particular day so we have to specify a range. | ||
* If we're interested in movies released on a specific day, we need | ||
* to specify the day before and after. | ||
*/ | ||
const dayBefore = getAdjacentDayInYear({ | ||
date: new Date(), | ||
direction: 'previous', | ||
year: releaseYear, | ||
}); | ||
const dayAfter = getAdjacentDayInYear({ | ||
date: new Date(), | ||
direction: 'next', | ||
year: releaseYear, | ||
}); | ||
|
||
/** | ||
* Get an array of movies released on today's month and day for the | ||
* current release year. | ||
*/ | ||
const discoverResponse = await getDiscoverMovie({ | ||
'primary_release_date.gte': dayBefore, | ||
'primary_release_date.lte': dayAfter, | ||
'sort_by': 'popularity.desc', | ||
'with_runtime.gte': '80', | ||
'without_genres': '99,10402', // Exclude and musicals | ||
}); | ||
|
||
appLogger.info({ | ||
message: `Got ${discoverResponse.results.length} movies for ${releaseYear}.`, | ||
service: 'tmdb', | ||
}); | ||
|
||
return discoverResponse.results; | ||
}); | ||
|
||
try { | ||
const movies = await Promise.all(promises); | ||
|
||
movies.forEach((yearMovies) => { | ||
allMovies = [...allMovies, ...yearMovies]; | ||
}); | ||
} catch (error) { | ||
appLogger.error({ | ||
error, | ||
message: `Failed to get movies for one or more years`, | ||
service: 'tmdb', | ||
}); | ||
throw error; | ||
} | ||
|
||
return allMovies; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { getMoviePoster } from '@/actions/movie/get-movie-poster.js'; | ||
import { ENDPOINTS } from '@/test/msw/handlers.js'; | ||
import { server } from '@/test/msw/server.js'; | ||
import { http, HttpResponse } from 'msw'; | ||
|
||
describe('getMoviePoster', () => { | ||
server.listen(); | ||
|
||
it('fetches a movie poster', async () => { | ||
const url = 'https://image.test/image.jpg'; | ||
const poster = await getMoviePoster(url); | ||
|
||
expect(poster).toBeInstanceOf(Response); | ||
}); | ||
|
||
it('throws an error if the request fails', async () => { | ||
server.use( | ||
http.get( | ||
ENDPOINTS.image, | ||
() => { | ||
return HttpResponse.error(); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
await expect(getMoviePoster('https://image.test/image.jpg')) | ||
.rejects | ||
.toThrow(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { appLogger } from '@/utils/logger.js'; | ||
|
||
export async function getMoviePoster(url: string) { | ||
try { | ||
const posterFile = await fetch(url); | ||
|
||
appLogger.info({ | ||
message: `Fetched movie poster ${url}.`, | ||
service: 'tmdb', | ||
}); | ||
|
||
return posterFile; | ||
} catch (error) { | ||
appLogger.error({ | ||
error, | ||
message: `Failed to fetch movie poster ${url} .`, | ||
service: 'tmdb', | ||
}); | ||
|
||
throw error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { createPostMedia } from '@/actions/post/create-post-media.js'; | ||
import { generateMediaAttachment } from '@/test/fakers/mastodon.js'; | ||
import { ENDPOINTS } from '@/test/msw/handlers.js'; | ||
import { server } from '@/test/msw/server.js'; | ||
import { http, HttpResponse } from 'msw'; | ||
|
||
describe('createPostMedia', () => { | ||
server.listen(); | ||
|
||
test('it should create post media', async () => { | ||
const file = new File([''], 'image.png', { type: 'image/png' }); | ||
const media = generateMediaAttachment(); | ||
|
||
server.use( | ||
http.post( | ||
ENDPOINTS.mastodon.media, | ||
() => { | ||
return HttpResponse.json(media); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
const response = await createPostMedia({ file, description: media.description }); | ||
|
||
expect(response).toEqual(media); | ||
}); | ||
|
||
test('it should throw an error if the request fails', async () => { | ||
const file = new File([''], 'image.png', { type: 'image/png' }); | ||
|
||
server.use( | ||
http.post( | ||
ENDPOINTS.mastodon.media, | ||
() => { | ||
return HttpResponse.error(); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
await expect(createPostMedia({ file })) | ||
.rejects | ||
.toThrow(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { createMedia } from '@/api/mastodon.js'; | ||
import { CreateMediaAttachmentParams } from '@/types/mastodon.js'; | ||
import { appLogger } from '@/utils/logger.js'; | ||
|
||
export async function createPostMedia({ | ||
file, | ||
description, | ||
}: CreateMediaAttachmentParams) { | ||
try { | ||
const media = await createMedia({ file, description }); | ||
return media; | ||
} catch (error) { | ||
appLogger.error({ | ||
error, | ||
message: 'Failed to create post media on Mastodon.', | ||
service: 'mastodon', | ||
}); | ||
|
||
throw error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { createPost } from '@/actions/post/create-post.js'; | ||
import { generateMediaAttachment, generateStatus } from '@/test/fakers/mastodon.js'; | ||
import { ENDPOINTS } from '@/test/msw/handlers.js'; | ||
import { server } from '@/test/msw/server.js'; | ||
import { http, HttpResponse } from 'msw'; | ||
|
||
describe('createPost', () => { | ||
server.listen(); | ||
|
||
test('it should create post without attachment', async () => { | ||
const newStatus = generateStatus(); | ||
|
||
server.use( | ||
http.post( | ||
ENDPOINTS.mastodon.statuses, | ||
() => { | ||
return HttpResponse.json(newStatus); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
const createdStatus = await createPost({ status: 'In the mood for love' }); | ||
expect(createdStatus).toEqual(newStatus); | ||
expect(createdStatus.mediaAttachments).toHaveLength(0); | ||
}); | ||
|
||
test('it should create post with attachment', async () => { | ||
const newStatus = generateStatus(); | ||
const media = generateMediaAttachment(); | ||
|
||
server.use( | ||
http.post( | ||
ENDPOINTS.mastodon.statuses, | ||
() => { | ||
return HttpResponse.json({ | ||
...newStatus, | ||
media_attachments: [media], | ||
}); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
const createdStatus = await createPost({ | ||
status: 'In the mood for love', | ||
statusAttachment: media, | ||
}); | ||
|
||
expect(createdStatus).toEqual({ | ||
...newStatus, | ||
mediaAttachments: [media], | ||
}); | ||
}); | ||
|
||
test('it should throw an error if the request fails', async () => { | ||
server.use( | ||
http.post( | ||
ENDPOINTS.mastodon.statuses, | ||
() => { | ||
return HttpResponse.error(); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
await expect(createPost({ status: 'In the mood for love' })) | ||
.rejects | ||
.toThrow(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { createStatus } from '@/api/mastodon.js'; | ||
import { MediaAttachment } from '@/types/mastodon.js'; | ||
import { appLogger } from '@/utils/logger.js'; | ||
|
||
export async function createPost({ | ||
status, | ||
statusAttachment, | ||
}: { | ||
status: string; | ||
statusAttachment?: MediaAttachment; | ||
}) { | ||
try { | ||
const newStatus = await createStatus({ | ||
status, | ||
mediaIds: statusAttachment ? [statusAttachment.id] : undefined, | ||
visibility: 'public', | ||
}); | ||
|
||
appLogger.info({ | ||
message: `Posted movie status\n${status}`, | ||
service: 'mastodon', | ||
}); | ||
|
||
return newStatus; | ||
} catch (error) { | ||
appLogger.error({ | ||
error, | ||
message: 'Failed to post movie status', | ||
service: 'mastodon', | ||
}); | ||
|
||
throw error; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { getLastPost } from '@/actions/post/get-last-post.js'; | ||
import { generateStatus } from '@/test/fakers/mastodon.js'; | ||
import { ENDPOINTS } from '@/test/msw/handlers.js'; | ||
import { server } from '@/test/msw/server.js'; | ||
import { http, HttpResponse } from 'msw'; | ||
|
||
describe('getLastPost', () => { | ||
server.listen(); | ||
|
||
test('it should return the last post', async () => { | ||
const statuses = [ | ||
generateStatus(), | ||
generateStatus(), | ||
generateStatus(), | ||
].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()); | ||
|
||
server.use( | ||
http.get( | ||
ENDPOINTS.mastodon.homeTimeline, | ||
() => { | ||
return HttpResponse.json(statuses); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
const response = await getLastPost(); | ||
expect(response).toEqual(statuses[0]); | ||
}); | ||
|
||
test('it should throw an error if the request fails', async () => { | ||
server.use( | ||
http.post( | ||
ENDPOINTS.mastodon.homeTimeline, | ||
() => { | ||
return HttpResponse.error(); | ||
}, | ||
{ once: true }, | ||
), | ||
); | ||
|
||
await expect(getLastPost()).rejects.toThrow(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { getTimeline } from '@/api/mastodon.js'; | ||
import { appLogger } from '@/utils/logger.js'; | ||
|
||
export async function getLastPost() { | ||
try { | ||
const posts = await getTimeline({ limit: 1 }); | ||
return posts[0]; | ||
} catch (error) { | ||
appLogger.error({ | ||
error, | ||
message: 'Failed to get last post from Mastodon.', | ||
service: 'mastodon', | ||
}); | ||
|
||
throw error; | ||
} | ||
} |
Oops, something went wrong.