Skip to content

Commit

Permalink
Migrate to using config
Browse files Browse the repository at this point in the history
  • Loading branch information
JHWelch committed Aug 30, 2023
1 parent cb91d7b commit b773413
Show file tree
Hide file tree
Showing 16 changed files with 79 additions and 115 deletions.
8 changes: 0 additions & 8 deletions __tests__/config/config.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
/*
Authorization: `Bearer ${process.env.TMDB_READ_KEY}`,
src="<%= process.env.CALENDAR_URL %>"
*/

import { beforeEach, describe, expect, it, jest } from '@jest/globals'
import Config from '../../src/config/config'

Expand Down
3 changes: 2 additions & 1 deletion __tests__/config/firestore.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { initializeApp } from 'firebase/app'
import { applicationDefault } from 'firebase-admin/app'
import { getFirestore } from 'firebase/firestore'
import setupFirestore from '../../src/config/firestore'
import { mockConfig } from '../support/mockConfig'

describe('setupFirestore', () => {
it('initializes the firestore', () => {
const firestore = setupFirestore()
const firestore = setupFirestore(mockConfig())

expect (applicationDefault).toHaveBeenCalledTimes(1)
expect (initializeApp).toHaveBeenCalledTimes(1)
Expand Down
8 changes: 5 additions & 3 deletions __tests__/controllers/cacheController.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ import { TmdbMock } from '../support/tmdbMock'
import { mockFetch } from '../support/fetchMock'
import Movie from '../../src/models/movie'
import TmdbAdapter from '../../src/data/tmdb/tmdbAdapter'
import { mockConfig } from '../support/mockConfig'

let notionMock: NotionMock

const { res, mockClear } = getMockRes()

const newCacheController = () => {
const firestore = new FirestoreAdapter()
const notion = new NotionAdapter()
const tmdbAdapter = new TmdbAdapter()
const config = mockConfig()
const firestore = new FirestoreAdapter(config)
const notion = new NotionAdapter(config)
const tmdbAdapter = new TmdbAdapter(config)
return new CacheController(firestore, notion, tmdbAdapter)
}

Expand Down
6 changes: 3 additions & 3 deletions __tests__/controllers/rsvpController.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { getMockReq, getMockRes } from '@jest-mock/express'
import { Timestamp, addDoc } from 'firebase/firestore'
import { FirebaseMock } from '../support/firebaseMock'
import FirestoreAdapter from '../../src/data/firestore/firestoreAdapter'
import { mockConfig } from '../support/mockConfig'

const { res, mockClear } = getMockRes()

beforeEach(() => {
process.env.ADMIN_EMAIL = 'admin@example.com'
jest.clearAllMocks()
mockClear()
})
Expand All @@ -23,7 +23,7 @@ describe('store', () => {
let firestoreAdapter: FirestoreAdapter

beforeEach(() => {
firestoreAdapter = new FirestoreAdapter()
firestoreAdapter = new FirestoreAdapter(mockConfig())
})

describe('has correct week', () => {
Expand Down Expand Up @@ -69,7 +69,7 @@ describe('store', () => {
expect(addDoc).toHaveBeenCalledWith(
FirebaseMock.mockCollection('mail'),
{
to: 'admin@example.com',
to: 'ADMIN_EMAIL@example.com',
message: {
subject: 'TNMC RSVP: test name',
// eslint-disable-next-line max-len
Expand Down
5 changes: 3 additions & 2 deletions __tests__/controllers/weekController.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Request } from 'express'
import { getMockReq, getMockRes } from '@jest-mock/express'
import { FirebaseMock } from '../support/firebaseMock'
import FirestoreAdapter from '../../src/data/firestore/firestoreAdapter'
import { mockConfig } from '../support/mockConfig'

const { res, mockClear } = getMockRes()

Expand All @@ -31,7 +32,7 @@ describe('index', () => {
let req: Request

beforeEach(() => {
firestore = new FirestoreAdapter()
firestore = new FirestoreAdapter(mockConfig())
FirebaseMock.mockWeeks([
{
date: new Date('2021-01-01'),
Expand Down Expand Up @@ -88,7 +89,7 @@ describe('index', () => {
let req: Request

beforeEach(() => {
firestore = new FirestoreAdapter()
firestore = new FirestoreAdapter(mockConfig())
FirebaseMock.mockWeeks([
{
date: new Date('2021-01-01'),
Expand Down
5 changes: 3 additions & 2 deletions __tests__/data/firestore/firestoreAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import { transaction } from '../../../__mocks__/firebase/firestore'
import { FirebaseMock } from '../../support/firebaseMock'
import Week from '../../../src/models/week'
import { mockConfig } from '../../support/mockConfig'

let firestore: FirestoreAdapter

Expand All @@ -28,13 +29,13 @@ beforeAll(() => {
})

beforeEach(() => {
firestore = new FirestoreAdapter()
firestore = new FirestoreAdapter(mockConfig())
jest.clearAllMocks()
})

describe('constructor', () => {
it('initializes the firestore', () => {
firestore = new FirestoreAdapter()
firestore = new FirestoreAdapter(mockConfig())

expect (applicationDefault).toHaveBeenCalledTimes(1)
expect (initializeApp).toHaveBeenCalledTimes(1)
Expand Down
59 changes: 9 additions & 50 deletions __tests__/data/notion/notionAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import NotionAdapter from '../../../src/data/notion/notionAdapter'
import { NotionMock } from '../../support/notionMock'
import Movie from '../../../src/models/movie'
import { mockConfig } from '../../support/mockConfig'

let notionMock: NotionMock

Expand All @@ -21,48 +22,6 @@ beforeEach(() => {
jest.clearAllMocks()
})

describe('constructor', () => {
describe('when NOTION_TOKEN and DATABASE_ID are set', () => {
beforeEach(() => {
process.env = {
NOTION_TOKEN: 'NOTION_TOKEN',
DATABASE_ID: 'DATABASE_ID',
}
})

it('should be created successfully', () => {
expect(() => new NotionAdapter()).not.toThrow()
})
})


describe('when NOTION_TOKEN is not set', () => {
beforeEach(() => {
process.env = {
DATABASE_ID: 'DATABASE_ID',
}
})

it('should throw an error', () => {
expect(() => new NotionAdapter())
.toThrowError('Missing NOTION_TOKEN environment variable')
})
})

describe('when DATABASE_ID is not set', () => {
beforeEach(() => {
process.env = {
NOTION_TOKEN: 'NOTION_TOKEN',
}
})

it('should throw an error', () => {
expect(() => new NotionAdapter())
.toThrowError('Missing DATABASE_ID environment variable')
})
})
})

describe('getMovie', () => {
beforeEach(() => {
process.env = {
Expand All @@ -78,7 +37,7 @@ describe('getMovie', () => {
})

it('should return the movie', async () => {
const movie = await new NotionAdapter().getMovie('movieId')
const movie = await new NotionAdapter(mockConfig()).getMovie('movieId')

expect(movie).toEqual({
notionId: 'movieId',
Expand All @@ -95,7 +54,7 @@ describe('getMovie', () => {
})

it ('calls the retrieve method with page_id', async () => {
await new NotionAdapter().getMovie('movieId')
await new NotionAdapter(mockConfig()).getMovie('movieId')

expect(notionMock.retrieve).toHaveBeenCalledWith({ 'page_id': 'movieId' })
})
Expand All @@ -107,7 +66,7 @@ describe('getMovie', () => {
})

it('should throw an error', async () => {
await expect(new NotionAdapter().getMovie('movieId'))
await expect(new NotionAdapter(mockConfig()).getMovie('movieId'))
.rejects.toThrowError('Page was not successfully retrieved')
})
})
Expand All @@ -130,7 +89,7 @@ describe('getWeek', () => {
})

it('should return the week', async () => {
const notion = new NotionAdapter()
const notion = new NotionAdapter(mockConfig())
const week = await notion.getWeek('2021-01-01')

expect(week).toEqual({
Expand All @@ -149,7 +108,7 @@ describe('getWeek', () => {
})

it('should throw an error', async () => {
const notion = new NotionAdapter()
const notion = new NotionAdapter(mockConfig())

expect(notion.getWeek('2021-01-01'))
.rejects.toThrowError('Page was not successfully retrieved')
Expand All @@ -168,7 +127,7 @@ describe('getWeeks', () => {
})

it('should return the weeks', async () => {
const notion = new NotionAdapter()
const notion = new NotionAdapter(mockConfig())
const weeks = await notion.getWeeks()

expect(weeks).toEqual([
Expand All @@ -195,7 +154,7 @@ describe('getWeeks', () => {
})

it('should call query with the correct parameters', async () => {
const notion = new NotionAdapter()
const notion = new NotionAdapter(mockConfig())
await notion.getWeeks()

expect(notionMock.query).toHaveBeenCalledWith({
Expand Down Expand Up @@ -227,7 +186,7 @@ describe('setMovie', () => {
'Theater',
'Showing Url',
)
const notion = new NotionAdapter()
const notion = new NotionAdapter(mockConfig())
await notion.setMovie(movie)

expect(notionMock.update).toHaveBeenCalledWith(movie.toNotion())
Expand Down
3 changes: 2 additions & 1 deletion __tests__/data/tmdb/tmdbAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import TmdbAdapter from '../../../src/data/tmdb/tmdbAdapter'
import Movie from '../../../src/models/movie'
import { TmdbMock } from '../../support/tmdbMock'
import { mockFetch } from '../../support/fetchMock'
import { mockConfig } from '../../support/mockConfig'

let tmdbMock: TmdbMock

Expand All @@ -14,7 +15,7 @@ describe('getMovie', () => {
let tmdbAdapter: TmdbAdapter

beforeEach(() => {
tmdbAdapter = new TmdbAdapter()
tmdbAdapter = new TmdbAdapter(mockConfig())
})

it('should return a movie', async () => {
Expand Down
15 changes: 15 additions & 0 deletions __tests__/support/mockConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Config from '../../src/config/config.js'

export function mockConfig (): Config {
process.env = {
NOTION_TOKEN: 'NOTION_TOKEN',
DATABASE_ID: 'DATABASE_ID',
PORT: '3000',
GOOGLE_CLOUD_PROJECT: 'GOOGLE_CLOUD_PROJECT',
ADMIN_EMAIL: 'ADMIN_EMAIL@example.com',
TMDB_READ_KEY: 'TMDB_READ_KEY',
CALENDAR_URL: 'https://CALENDAR_URL',
}

return new Config()
}
5 changes: 3 additions & 2 deletions src/config/firestore.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { getFirestore, Firestore } from 'firebase/firestore'
import { initializeApp } from 'firebase/app'
import { applicationDefault } from 'firebase-admin/app'
import Config from './config'

export default function setupFirestore (): Firestore {
export default function setupFirestore (config: Config): Firestore {
const firebaseConfig = {
credential: applicationDefault(),
projectId: process.env.GOOGLE_CLOUD_PROJECT,
projectId: config.googleCloudProject,
}

const app = initializeApp(firebaseConfig)
Expand Down
9 changes: 0 additions & 9 deletions src/config/mail.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/controllers/rsvpController.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { type Request, type Response } from 'express'
import FirestoreAdapter from '../data/firestore/firestoreAdapter.js'
import { z } from 'zod'
import { adminEmail } from '../config/mail.js'

class RsvpController {
static PATHS = {
Expand Down Expand Up @@ -30,7 +29,7 @@ class RsvpController {

res.status(201).json({ message: 'Successfully RSVP\'d' })

await this.firestore.sendEmail(adminEmail(), {
await this.firestore.sendEmail(this.firestore.adminEmail, {
subject: `TNMC RSVP: ${name}`,
// eslint-disable-next-line max-len
text: `${name} has RSVPed for ${weekId}\n\nEmail: ${email}\nPlus one: ${plusOne}`,
Expand Down
23 changes: 15 additions & 8 deletions src/data/firestore/firestoreAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,25 @@ import {
} from 'firebase/firestore'
import Week from '../../models/week.js'
import setupFirestore from '../../config/firestore.js'
import Config from '../../config/config.js'

export default class FirestoreAdapter {
static readonly MAIL_COLLECTION_NAME = 'mail'
static readonly RSVPS_COLLECTION_NAME = 'rsvps'
static readonly WEEKS_COLLECTION_NAME = 'weeks'

#firestore: FirestoreType
private config: Config
private firestore: FirestoreType

constructor () {
this.#firestore = setupFirestore()
constructor (config: Config) {
this.config = config
this.firestore = setupFirestore(config)
}

async cacheWeeks (weeks: Week[]): Promise<void> {
await runTransaction(this.#firestore, async (transaction) => {
await runTransaction(this.firestore, async (transaction) => {
weeks.forEach((week: Week) => {
const ref = doc(this.#firestore, 'weeks', week.dateString)
const ref = doc(this.firestore, 'weeks', week.dateString)
transaction.set(ref, week.toFirebaseDTO())
})
})
Expand Down Expand Up @@ -103,16 +106,20 @@ export default class FirestoreAdapter {
return Timestamp.fromDate(today)
}

get adminEmail (): string {
return this.config.adminEmail
}

private get mailCollection (): Collection {
return collection(this.#firestore, FirestoreAdapter.MAIL_COLLECTION_NAME)
return collection(this.firestore, FirestoreAdapter.MAIL_COLLECTION_NAME)
}

private get rsvpCollection (): Collection {
return collection(this.#firestore, FirestoreAdapter.RSVPS_COLLECTION_NAME)
return collection(this.firestore, FirestoreAdapter.RSVPS_COLLECTION_NAME)
}

private get weekCollection (): Collection {
return collection(this.#firestore, FirestoreAdapter.WEEKS_COLLECTION_NAME)
return collection(this.firestore, FirestoreAdapter.WEEKS_COLLECTION_NAME)
}
}

Expand Down
Loading

0 comments on commit b773413

Please sign in to comment.