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 };