diff --git a/fixtures/product.js b/fixtures/product.js index 4b6198d..686e32b 100644 --- a/fixtures/product.js +++ b/fixtures/product.js @@ -1,15 +1,21 @@ const product = { - title: '아이패드 4세대 팝니다.', - description: '신형 아이패드 4세대 12.9인치 팝니다. 사용한지 3개월도 안된 제품이에요.', - region: '서울 강남', - price: '990000', + id: 1, + category: '가구/인테리어', + createAt: '168828208635', + description: '해외 이민으로 인해 가전제품 팝니다!010-****-****로 연락주세요!', + price: 350000, productImages: [ - 'https://via.placeholder.com/600/810b14', - 'https://via.placeholder.com/600/24f355', - 'https://via.placeholder.com/600/f66b97', + { name: '가전1.jpeg', imageUrl: '가전1url' }, + { name: '가전2.jpeg', imageUrl: '가전2url' }, + { name: '가전3.jpeg', imageUrl: '가전3url' }, ], - createAt: '12341231242', - creatorId: 'abc123', + region: '서울시 강남구', + title: '해외 이사로 인한 가전제품 팔아요!', + user: { + displayName: '홍길동/연구과제팀/직원', + email: 'ghdrlfehd@test.com', + uid: 'ghdrlfehd1234', + }, }; export default product; diff --git a/fixtures/products.js b/fixtures/products.js index 6089416..6c142aa 100644 --- a/fixtures/products.js +++ b/fixtures/products.js @@ -1,95 +1,119 @@ const products = [ { - user: { - email: 'tester@example.com', - displayName: '홍 길동', - uid: '1234abcd', - }, id: 1, - title: '크리넥스 KF-AD 소형 마스크 팝니다.', - category: '기타 중고물품', + category: '가구/인테리어', + createAt: '1608828208635', + description: '해외 이민으로 인해 가전제품 팝니다!010-****-****로 연락주세요!', + price: 350000, productImages: [ - { name: 'test1', imageUrl: 'testImageUrl1' }, - { name: 'test2', imageUrl: 'testImageUrl2' }, - { name: 'test3', imageUrl: 'testImageUrl3' }, + { name: '가전1.jpeg', imageUrl: '가전1url' }, + { name: '가전2.jpeg', imageUrl: '가전2url' }, + { name: '가전3.jpeg', imageUrl: '가전3url' }, ], - region: '미추홀구 용현5동', - price: '25,000', - description: '저 크리넥스 스타일 마스크 대형 3개입\n님 크리넥스 데일리 입체형 황사마스크 KF80 소형 2개 교환 합니다... Or KF80 KFAD 소형 2개 가능합니다\n\n크리넥스 스타일 블랙 3매입 100장(75000) 판매도 해요\n', - }, - { + region: '서울시 강남구', + title: '해외 이사로 인한 가전제품 팔아요!', user: { - email: 'tester@example.com', - displayName: '홍 길동', - uid: '1234abcd', + displayName: '홍길동/연구과제팀/직원', + email: 'ghdrlfehd@test.com', + uid: 'ghdrlfehd1234', }, + }, + { id: 2, - title: '알레르망 범퍼침대', - category: '가구/인테리어', + category: '여성의류', + createAt: '1609754642862', + description: '팝니다.220 사이즈에요.', + price: 25000, productImages: [ - { name: 'test4', imageUrl: 'testImageUrl4' }, - { name: 'test5', imageUrl: 'testImageUrl5' }, - { name: 'test6', imageUrl: 'testImageUrl6' }, + { name: '신발1.jpeg', imageUrl: '신발1url' }, ], - region: '연수구 송도동', - price: '60,000', - description: '알레르망 범퍼 침대입니다\n18년도 구입했고 친정에서 주말에 방문할때만 사용해서 상태 좋습니다\n친정 이사로 인해\n처분합니다\n세탁해서 깨끗한 김장봉투에 넣어\n정리해 둔 상태입니다\n', - }, - { + region: '인천 남구', + title: '여성 운동화', user: { - email: 'tester@example.com', - displayName: '홍 길동', - uid: '1234abcd', + displayName: '김 철수', + email: 'rlacjftn@test.com', + uid: 'rlacjftn1234', }, + }, + { id: 3, - title: '청바지', category: '남성패션/잡화', + createAt: '1609763267254', + description: '청바지 팝니다.32 사이즈 청바지에요.', + price: 25000, productImages: [ - { name: 'test7', imageUrl: 'testImageUrl7' }, - { name: 'test8', imageUrl: 'testImageUrl8' }, - { name: 'test9', imageUrl: 'testImageUrl9' }, + { name: '청바지1.jpeg', imageUrl: '청바지1url' }, ], - region: '청학동', - price: '10,000', - description: '게스 청바지 사이즈 25입니다\n하자없습니다\n가격내림', - - }, - { + region: '서울 강남', + title: '청바지 팝니다.', user: { - email: 'tester@example.com', - displayName: '홍 길동', - uid: '1234abcd', + displayName: '김 철수', + email: 'rlacjftn@test.com', + uid: 'rlacjftn1234', }, + }, + { id: 4, - title: '아이패드 에어3', category: '디지털/가전', + createAt: '1608838040530', + description: '아이패드 에어 중고 팔아요64기가 와이파이 버전입니다.', + price: 250000, productImages: [ - { name: 'test10', imageUrl: 'testImageUrl10' }, - { name: 'test11', imageUrl: 'testImageUrl11' }, - { name: 'test12', imageUrl: 'testImageUrl12' }, + { name: '아이패드1.jpeg', imageUrl: '아이패드1url' }, + { name: '아이패드2.jpeg', imageUrl: '아이패드2url' }, + { name: '아이패드3.jpeg', imageUrl: '아이패드3url' }, ], - region: '연수구 연수3동', - price: '650,000', - description: '펜슬 아이패드 파우치 아이패드 케이스 펜슬케이스 펜슬촉 다드립니다', + region: '서울', + title: '아이패드 에어 팔아요.', + user: { + displayName: '홍길동/연구과제팀/직원', + email: 'ghdrlfehd@test.com', + uid: 'ghdrlfehd1234', + }, }, +]; + +const userProducts = [ { + id: 1, + category: '가구/인테리어', + createAt: '1608828208635', + description: '해외 이민으로 인해 가전제품 팝니다!010-****-****로 연락주세요!', + price: 350000, + productImages: [ + { name: '가전1.jpeg', imageUrl: '가전1url' }, + { name: '가전2.jpeg', imageUrl: '가전2url' }, + { name: '가전3.jpeg', imageUrl: '가전3url' }, + ], + region: '서울시 강남구', + title: '해외 이사로 인한 가전제품 팔아요!', user: { - email: 'tester@example.com', - displayName: '홍 길동', - uid: '1234abcd', + displayName: '홍길동/연구과제팀/직원', + email: 'ghdrlfehd@test.com', + uid: 'ghdrlfehd1234', }, - id: 5, - title: '겔럭시S7 핑크블로썸 팝니다.', + }, + { + id: 4, category: '디지털/가전', + createAt: '1608838040530', + description: '아이패드 에어 중고 팔아요64기가 와이파이 버전입니다.', + price: 250000, productImages: [ - { name: 'test13', imageUrl: 'testImageUrl13' }, - { name: 'test14', imageUrl: 'testImageUrl14' }, - { name: 'test15', imageUrl: 'testImageUrl15' }, + { name: '아이패드1.jpeg', imageUrl: '아이패드1url' }, + { name: '아이패드2.jpeg', imageUrl: '아이패드2url' }, + { name: '아이패드3.jpeg', imageUrl: '아이패드3url' }, ], - region: '학익1동', - price: '100,000', - description: '✔통신사 sk로 쓰던 폰이며 색깔은 딸기우유색입니다\n✔정상해지 완료 한 제품입니다 😊\n✔32기가 입니다\n✔케이스 생활을 해도 생활기스가 약하게 있는 점 이해부탁드려요\n생활기스는 가까이서 보시면 티가 납니다😊\n✔거래 장소는 학익동 인천향교유림회관 앞입니다!\n✔중고제품이다 보니 환불 안되시는 점 주의해주세요!', + region: '서울', + title: '아이패드 에어 팔아요.', + user: { + displayName: '홍길동/연구과제팀/직원', + email: 'ghdrlfehd@test.com', + uid: 'ghdrlfehd1234', + }, }, ]; export default products; + +export { userProducts }; diff --git a/fixtures/user.js b/fixtures/user.js index c55f85e..31a2af3 100644 --- a/fixtures/user.js +++ b/fixtures/user.js @@ -1,7 +1,7 @@ const logInUser = { - uid: '1234abcd', displayName: '홍 길동', - email: 'tester@example.com', + email: 'ghdrlfehd@example.com', + uid: 'ghdrlfehd1234', }; const logOutUser = { diff --git a/src/authSlice.js b/src/authSlice.js index af49b29..25809f9 100644 --- a/src/authSlice.js +++ b/src/authSlice.js @@ -6,9 +6,12 @@ import { saveItem, deleteItem } from './services/storage'; import { setIsLoading } from './commonSlice'; +import { + googleAuthLogin, +} from './services/firebase'; + import { postLogin, - postGoogleSignIn, postSignup, postLogout, } from './services/api'; @@ -58,7 +61,7 @@ export function requestLogin({ loginFields }) { return async (dispatch) => { try { dispatch(setIsLoading(true)); - const { user } = await postLogin({ email, password }); + const user = await postLogin({ email, password }); const { displayName, uid } = user; dispatch(setUser({ email, displayName, uid })); @@ -75,20 +78,15 @@ export function requestLogin({ loginFields }) { export function requestGoogleSignIn() { return async (dispatch) => { - try { - dispatch(setIsLoading(true)); - const { user } = await postGoogleSignIn(); - const { email, displayName, uid } = user; + dispatch(setIsLoading(true)); + const { user } = await googleAuthLogin(); + const { email, displayName, uid } = user; - dispatch(setUser({ email, displayName, uid })); - saveItem('user', { email, displayName, uid }); - dispatch(setIsLoading(false)); + dispatch(setUser({ email, displayName, uid })); + saveItem('user', { email, displayName, uid }); + dispatch(setIsLoading(false)); - dispatch(push('/')); - } catch (error) { - dispatch(setError(error.message)); - dispatch(setIsLoading(false)); - } + dispatch(push('/')); }; } @@ -101,7 +99,7 @@ export function requestSignup({ signupFields }) { return async (dispatch) => { try { dispatch(setIsLoading(true)); - const { user } = await postSignup({ email, password }); + const user = await postSignup({ email, password }); user.updateProfile({ displayName: userNickname }); const { displayName, uid } = user; diff --git a/src/authSlice.test.js b/src/authSlice.test.js index f3f0aa1..f9b04d0 100644 --- a/src/authSlice.test.js +++ b/src/authSlice.test.js @@ -12,7 +12,6 @@ import authReducer, { } from './authSlice'; import { - postGoogleSignIn, postLogin, postSignup, } from './services/api'; @@ -24,6 +23,7 @@ const middlewares = [...getDefaultMiddleware()]; const mockStore = configureStore(middlewares); jest.mock('./services/api'); +jest.mock('./services/firebase'); jest.mock('connected-react-router'); describe('reducer', () => { @@ -87,8 +87,8 @@ describe('actions', () => { }); const loginFields = { - email: 'tester@example.com', - password: '1234abcd', + email: 'ghdrlfehd@example.com', + password: 'ghdrlfehd1234', }; describe('requestLogin', () => { @@ -97,9 +97,7 @@ describe('actions', () => { }); it('dispatches requestLogin action and returns user', async () => { - postLogin.mockImplementationOnce(() => ({ - user: logInUser, - })); + postLogin.mockImplementationOnce(() => logInUser); await store.dispatch(requestLogin({ loginFields })); @@ -133,38 +131,15 @@ describe('actions', () => { store = mockStore({}); }); - context('when request success', () => { - it('returns user and change url path', async () => { - postGoogleSignIn.mockImplementationOnce(() => ({ - user: logInUser, - })); - - await store.dispatch(requestGoogleSignIn()); - - const actions = store.getActions(); + it('returns user and change url path', async () => { + const actions = store.getActions(); - expect(actions[0]).toEqual(setIsLoading(true)); - expect(actions[1]).toEqual(setUser(logInUser)); - expect(actions[2]).toEqual(setIsLoading(false)); - expect(actions[3]).toEqual(push('/')); - }); - }); + await store.dispatch(requestGoogleSignIn()); - context('when request fail', () => { - it('returns an error', async () => { - postGoogleSignIn.mockImplementationOnce( - () => Promise.reject( - new Error('something bad happened'), - ), - ); - - try { - await store.dispatch(requestGoogleSignIn()); - } catch { - const actions = store.getActions(); - expect(actions[0].payload.error).toEqual('Something bad happened'); - } - }); + expect(actions[0]).toEqual(setIsLoading(true)); + expect(actions[1]).toEqual(setUser(logInUser)); + expect(actions[2]).toEqual(setIsLoading(false)); + expect(actions[3]).toEqual(push('/')); }); }); @@ -172,7 +147,7 @@ describe('actions', () => { const signupFields = { firstName: '홍', lastName: '길동', - email: 'tester@example.com', + email: 'ghdrlfehd@example.com', password: '1234abcd', }; @@ -184,10 +159,8 @@ describe('actions', () => { it('returns user and change url path', async () => { const updateProfile = jest.fn(); postSignup.mockImplementationOnce(() => ({ - user: { - ...logInUser, - updateProfile, - }, + ...logInUser, + updateProfile, })); await store.dispatch(requestSignup({ signupFields })); diff --git a/src/components/container/ProductContainer.test.jsx b/src/components/container/ProductContainer.test.jsx index fa2cf77..5b6f24a 100644 --- a/src/components/container/ProductContainer.test.jsx +++ b/src/components/container/ProductContainer.test.jsx @@ -5,7 +5,7 @@ import { useSelector, useDispatch } from 'react-redux'; import ProductContainer from './ProductContainer'; -import products from '../../../fixtures/products'; +import product from '../../../fixtures/product'; jest.mock('react-redux'); @@ -29,7 +29,7 @@ describe('ProductContainer', () => { } context('with product', () => { - given('product', () => products[0]); + given('product', () => product); it('dispatchs called', () => { renderProductContainer(); @@ -38,10 +38,11 @@ describe('ProductContainer', () => { }); it('renders product', () => { + const { title, region } = product; const { container } = renderProductContainer(); - expect(container).toHaveTextContent('크리넥스 KF-AD 소형 마스크 팝니다.'); - expect(container).toHaveTextContent('미추홀구 용현5동'); + expect(container).toHaveTextContent(title); + expect(container).toHaveTextContent(region); }); }); }); diff --git a/src/components/presentational/ArticleProfile.test.jsx b/src/components/presentational/ArticleProfile.test.jsx index b66e9ff..a1980e3 100644 --- a/src/components/presentational/ArticleProfile.test.jsx +++ b/src/components/presentational/ArticleProfile.test.jsx @@ -8,11 +8,12 @@ import { logInUser } from '../../../fixtures/user'; describe('ArticleProfile', () => { it('render seller profile', () => { + const { displayName, email } = logInUser; const { container } = render(( )); - expect(container).toHaveTextContent('홍 길동'); - expect(container).toHaveTextContent('tester@example.com'); + expect(container).toHaveTextContent(displayName); + expect(container).toHaveTextContent(email); }); }); diff --git a/src/components/presentational/ProductDetail.test.jsx b/src/components/presentational/ProductDetail.test.jsx index f868798..9d0790d 100644 --- a/src/components/presentational/ProductDetail.test.jsx +++ b/src/components/presentational/ProductDetail.test.jsx @@ -16,10 +16,11 @@ describe('ProductDetail', () => { } it('renders product detail', () => { + const { title, region } = products[0]; const { container } = renderProductDetail({ product: products[0] }); - expect(container).toHaveTextContent('크리넥스 KF-AD 소형 마스크 팝니다.'); - expect(container).toHaveTextContent('미추홀구 용현5동'); + expect(container).toHaveTextContent(title); + expect(container).toHaveTextContent(region); }); context('without product images', () => { diff --git a/src/pages/HomePage.test.jsx b/src/pages/HomePage.test.jsx index 1652b37..cd77959 100644 --- a/src/pages/HomePage.test.jsx +++ b/src/pages/HomePage.test.jsx @@ -8,6 +8,7 @@ import { render, fireEvent } from '@testing-library/react'; import HomePage from './HomePage'; import products from '../../fixtures/products'; +import product from '../../fixtures/product'; const mockPush = jest.fn(); @@ -55,9 +56,11 @@ describe('HomePage', () => { context('when click product', () => { it('occur handle event', () => { + const { title } = product; + const { getByText } = renderHomePage(); - fireEvent.click(getByText('크리넥스 KF-AD 소형 마스크 팝니다.')); + fireEvent.click(getByText(title)); expect(mockPush).toBeCalledWith('/products/1'); }); diff --git a/src/pages/ProductPage.test.jsx b/src/pages/ProductPage.test.jsx index 2f0d657..ee37cc3 100644 --- a/src/pages/ProductPage.test.jsx +++ b/src/pages/ProductPage.test.jsx @@ -7,43 +7,45 @@ import { useSelector, useDispatch } from 'react-redux'; import { MemoryRouter } from 'react-router-dom'; import ProductPage from './ProductPage'; -import products from '../../fixtures/products'; +import product from '../../fixtures/product'; describe('ProductPage', () => { const dispatch = jest.fn(); + const { title, region, id } = product; beforeEach(() => { dispatch.mockClear(); useDispatch.mockImplementation(() => dispatch); useSelector.mockImplementation((selector) => selector({ productReducer: { - product: products[0], + product, }, })); }); context('with params props', () => { it('renders product', () => { - const params = { productId: 1 }; + const params = { productId: id }; + const { container } = render(( )); - expect(container).toHaveTextContent('크리넥스 KF-AD 소형 마스크 팝니다.'); - expect(container).toHaveTextContent('미추홀구 용현5동'); + expect(container).toHaveTextContent(title); + expect(container).toHaveTextContent(region); }); }); context('without params props', () => { it('renders product', () => { const { container } = render(( - + )); - expect(container).toHaveTextContent('크리넥스 KF-AD 소형 마스크 팝니다.'); - expect(container).toHaveTextContent('미추홀구 용현5동'); + expect(container).toHaveTextContent(title); + expect(container).toHaveTextContent(region); }); }); }); diff --git a/src/services/__mocks__/firebase.js b/src/services/__mocks__/firebase.js new file mode 100644 index 0000000..b80a0c4 --- /dev/null +++ b/src/services/__mocks__/firebase.js @@ -0,0 +1,72 @@ +import products from '../../../fixtures/products'; +import { logInUser } from '../../../fixtures/user'; + +const collections = { + products, +}; + +const googleAuthLogin = jest.fn().mockImplementation(() => Promise.resolve({ user: logInUser })); + +const firebase = { + auth: jest.fn(() => ({ + signInWithEmailAndPassword: jest.fn((email, password) => ({ + user: { + displayName: undefined, email, password, + }, + })), + createUserWithEmailAndPassword: jest.fn((email, password) => ({ + user: { + displayName: undefined, email, password, + }, + })), + signOut: jest.fn(), + })), + firestore: jest.fn(() => ({ + collection: jest.fn().mockImplementation((path) => ({ + get: jest.fn().mockResolvedValue({ + docs: collections[path].map((item) => ({ + id: item.id, + data: () => item, + })), + }), + doc: jest.fn().mockImplementation((docId) => ({ + get: jest.fn().mockResolvedValue({ + data: () => products.find(({ id }) => id === docId), + }), + update: jest.fn(), + delete: jest.fn(), + })), + add: jest.fn().mockImplementation((item) => item), + where: jest.fn().mockImplementation((_, operator, value) => { + let result = null; + + if (operator === '==') { + result = ({ + get: jest.fn().mockResolvedValue({ + docs: collections[path] + .filter((doc) => doc.user.uid === value) + .map((doc) => ({ + id: doc.uid, + data: () => doc, + })), + }), + }); + } + return result; + }), + })), + })), + storage: jest.fn().mockImplementation(() => ({ + refFromURL: jest.fn().mockImplementation(() => ({ + delete: jest.fn(), + })), + ref: jest.fn(() => ({ + child: jest.fn(() => ({ + put: jest.fn(), + getDownloadURL: jest.fn(() => 'MOCK_IMAGE_URL'), + })), + })), + })), +}; + +export { firebase, googleAuthLogin }; diff --git a/src/services/api.js b/src/services/api.js index ddc386b..9a2c8b0 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -1,5 +1,5 @@ import { v4 as uuidv4 } from 'uuid'; -import firebase from '../../plugin/firebase'; +import { firebase } from './firebase'; import { isEmpty } from '../utils'; export async function fetchProducts() { @@ -43,10 +43,10 @@ export async function fetchUserProducts({ user }) { export async function uploadProductImages({ files }) { async function uploadProductImage(file) { - const uploadTask = firebase.storage() + const reference = firebase.storage() .ref().child(`${file.name}${uuidv4()}`); - const response = await uploadTask.put(file); - const imageUrl = await response.ref.getDownloadURL(); + await reference.put(file); + const imageUrl = await reference.getDownloadURL(); return imageUrl; } @@ -87,9 +87,9 @@ export async function deleteAllImages(productImages) { export async function postDeleteProduct({ product }) { const { id, productImages } = product; await firebase - .firestore().doc(`products/${id}`).delete(); + .firestore().collection('products').doc(id).delete(); - if (isEmpty(productImages || [])) { + if (isEmpty(productImages)) { return; } @@ -98,35 +98,21 @@ export async function postDeleteProduct({ product }) { } export async function postLogin({ email, password }) { - const response = await firebase + const { user } = await firebase .auth() .signInWithEmailAndPassword(email, password); - return response; -} - -export async function postGoogleSignIn() { - const response = await firebase - .auth() - .signInWithPopup( - new firebase.auth.GoogleAuthProvider(), - ); - - return response; + return user; } export async function postSignup({ email, password }) { - const response = await firebase + const { user } = await firebase .auth() .createUserWithEmailAndPassword(email, password); - return response; + return user; } export async function postLogout() { - const response = await firebase - .auth() - .signOut(); - - return response; + await firebase.auth().signOut(); } diff --git a/src/services/api.test.js b/src/services/api.test.js index 3b805e5..29eff2b 100644 --- a/src/services/api.test.js +++ b/src/services/api.test.js @@ -1,127 +1,158 @@ -import * as firebase from 'firebase'; - import { + fetchProduct, + fetchProducts, + fetchUserProducts, + postProduct, + postDeleteProduct, + postEditProduct, + deleteAllImages, postLogin, - postGoogleSignIn, postSignup, postLogout, - postProduct, + uploadProductImages, } from './api'; -describe('firebase services', () => { - describe('postLogin', () => { - const mockPostLogin = ({ email, password }) => { - firebase.auth() - .signInWithEmailAndPassword = jest.fn().mockResolvedValue({ - email, password, - }); - }; - - const email = 'tester@example.com'; - const password = '123456'; - - beforeEach(() => { - mockPostLogin({ email, password }); - }); +import products, { userProducts } from '../../fixtures/products'; +import product from '../../fixtures/product'; +import { logInUser } from '../../fixtures/user'; - it('returns uid', async () => { - const user = await postLogin({ email, password }); +jest.mock('./firebase.js'); - expect(user).toEqual({ email, password }); +describe('api', () => { + describe('fetchProducts', () => { + it('returns products', async () => { + const data = await fetchProducts(); + + expect(data).toEqual(products); }); }); - describe('postGoogleSignIn', () => { - const mockGoogleSignIn = ({ user }) => { - firebase.auth() - .signInWithPopup = jest.fn().mockResolvedValue(user); - }; + describe('fetchProduct', () => { + it('returns product', async () => { + const productId = 1; - const user = { - displayName: 'tester', - uid: 'abc1234', - }; + const data = await fetchProduct(productId); - beforeEach(() => { - mockGoogleSignIn({ user }); + expect(data).toEqual( + products.find(({ id }) => id === productId), + ); }); + }); - it('returns uid', async () => { - const mockUser = await postGoogleSignIn(); + describe('fetchUserProducts', () => { + it('returns userProducts', async () => { + const user = logInUser; - expect(mockUser).toEqual({ - displayName: 'tester', - uid: 'abc1234', - }); + const data = await fetchUserProducts({ user }); + + expect(data).toEqual(userProducts); }); }); - describe('postLogout', () => { - const mockLogout = () => { - firebase.auth() - .signOut = jest.fn().mockResolvedValue(true); - }; + describe('postProduct', () => { + it('return post id', async () => { + const data = await postProduct(product); - beforeEach(() => { - mockLogout(); + expect(data).toEqual(product.id); }); + }); - it('returns promise', async () => { - const logout = await postLogout(); + describe('uploadProductImages', () => { + it('returns productImages', async () => { + const files = [ + new File(['file'], 'productImage1.png', { + type: 'application/json', + }), + new File(['file'], 'productImage2.png', { + type: 'application/json', + }), + new File(['file'], 'productImage3.png', { + type: 'application/json', + }), + ]; + + const data = await uploadProductImages({ files }); + + const productImages = files.map((file) => ({ + name: file.name, + imageUrl: 'MOCK_IMAGE_URL', + })); + + expect(data).toEqual(productImages); + }); + }); - expect(logout).toBe(true); + describe('postEditProduct', () => { + it('request product post edit', async () => { + const productId = 1; + const editedProduct = { + ...product, + title: '가전제품 팜', + price: 400000, + }; + + await postEditProduct({ productId, editedProduct }); }); }); - describe('postSignup', () => { - const mockFirebaseSignup = ({ email, password }) => { - firebase.auth() - .createUserWithEmailAndPassword = jest.fn().mockResolvedValue({ - displayName: '', - email, - password, - uid: '', - }); - }; - - const email = 'tester@example.com'; - const password = '123456'; - - beforeEach(() => { - mockFirebaseSignup({ email, password }); + describe('postDeleteProduct', () => { + context('productImages is not empty', () => { + it('request delete all images and product post delete', async () => { + const { productImages } = product; + + await postDeleteProduct({ product }); + + const deleteUrls = productImages.map(({ imageUrl }) => imageUrl); + + await deleteAllImages(deleteUrls); + }); }); - it('returns new account', async () => { - const newUser = await postSignup({ email, password }); + context('productImages is empty', () => { + it('request only post delete', async () => { + const emptyImagesInPost = { + ...product, + productImages: [], + }; - expect(newUser.email).toBe(email); + await postDeleteProduct({ product: emptyImagesInPost }); + }); }); }); - describe('postProduct', () => { - const add = jest.fn((product) => product); - const collection = jest.spyOn( - firebase.firestore(), 'collection', - ).mockReturnValue({ add }); - - it('post new product', async () => { - const newProduct = { - title: 'test title', - description: 'test description', - productImages: [], - createdAt: Date.now(), - user: { - uid: 'test1234', - displayName: '홍 길동', - email: 'tester@example.com', - }, - }; + describe('postLogin', () => { + it('returns user', async () => { + const email = 'ghdrlfehd@test.com'; + const password = '123456'; + + const data = await postLogin({ email, password }); + + expect(data).toEqual({ + displayName: undefined, + email, + password, + }); + }); + }); - await postProduct(newProduct); + describe('postSignup', () => { + it('returns sign up user', async () => { + const email = 'ghdrlfehd@test.com'; + const password = '123456'; - expect(collection).toHaveBeenCalledWith('products'); + const data = await postSignup({ email, password }); - expect(add).toHaveBeenCalledWith(newProduct); + expect(data).toEqual({ + displayName: undefined, + email, + password, + }); + }); + }); + + describe('postLogout', () => { + it('request logout', async () => { + await postLogout(); }); }); }); diff --git a/plugin/firebase.js b/src/services/firebase.js similarity index 72% rename from plugin/firebase.js rename to src/services/firebase.js index 514156d..9a17605 100644 --- a/plugin/firebase.js +++ b/src/services/firebase.js @@ -15,4 +15,7 @@ const firebaseConfig = { firebase.initializeApp(firebaseConfig); -export default firebase; +const googleAuthProvider = new firebase.auth.GoogleAuthProvider(); +const googleAuthLogin = () => firebase.auth().signInWithPopup(googleAuthProvider); + +export { firebase, googleAuthLogin };