Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

[FE] test: 테스트 코드 뼈대 구현 #472

Merged
merged 5 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 15 additions & 39 deletions frontend/cypress/e2e/main-page.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,27 @@ describe('동글 메인 페이지', () => {
cy.visit(`/`);
});

describe('글 업로드 테스트', () => {
it('Add Post 버튼을 누르면 글 가져오기 모달 창이 열린다.', () => {
cy.findByText('Add Post').click();
describe('로그인 성공 테스트', () => {
it('로그인 하기 버튼을 누르면 로그인 모달 창이 열린다.', () => {
cy.findByText('로그인하기').click();

cy.findByText('글 가져오기').should('exist');
cy.findByText('간편 로그인').should('exist');
});

it('드래그 앤 드롭으로 마크다운 파일을 업로드할 수 있다.', () => {
cy.findByText('Add Post').click();
cy.findByLabelText('파일 업로드').attachFile('markdown-test.md', {
subjectType: 'drag-n-drop',
});

cy.findByText('markdown-test').should('exist');
cy.findByText('e2e 테스트를 위한 마크다운 파일입니다.').should('exist');
cy.findByText('글 정보').should('exist');
cy.findByLabelText('오른쪽 사이드바 토글').should('exist');
});

it('기본 카테고리에서 업로드한 글을 확인할 수 있다.', () => {
cy.findByText('기본').click();

cy.findAllByText('markdown-test').should('exist');
it('카카오 로그인 버튼을 누르면 카카오로 로그인 할 수 있는 화면이 나타난다.', () => {
cy.findByText('로그인하기').click();
cy.findByLabelText('카카오 로그인 화면으로 이동').click();
cy.visit(`/oauth/login/kakao?code=mock`);
cy.findByText('로그아웃').should('exist');
});
});

describe('카테고리 테스트', () => {
it('카테고리 추가 버튼을 클릭하여 입력 창에 이름을 입력하고 엔터를 쳐서 카테고리를 추가할 수 있다.', () => {
cy.findByLabelText('카테고리 추가 입력 창 열기').click();
cy.findByLabelText('카테고리 추가 입력 창').focus().type('동글이{enter}');
cy.findByText('동글이').should('exist');
});

it('카테고리 이름 수정 버튼을 클릭하여 입력 창에 이름을 입력하고 엔터를 쳐서 카테고리 이름을 수정할 수 있다.', () => {
cy.findByText('동글이').realHover();
cy.findByLabelText('동글이 카테고리 이름 수정').click();
cy.findByLabelText('동글이 카테고리 이름 수정 입력 창').focus().type('동글동글이{enter}');
cy.findByText('동글이').should('not.exist');
cy.findByText('동글동글이').should('exist');
});

it('카테고리 삭제 버튼을 클릭하여 카테고리를 삭제할 수 있다.', () => {
cy.findByText('동글동글이').realHover();
cy.findByLabelText('동글동글이 카테고리 삭제').click();
cy.findByText('동글동글이').should('not.exist');
describe('로그인 실패 테스트', () => {
it('카카오 로그인 버튼을 누르면 카카오로 로그인 할 수 있는 화면이 나타난다.', () => {
cy.findByText('로그인하기').click();
cy.findByLabelText('카카오 로그인 화면으로 이동').click();
cy.visit(`/oauth/login/kakao`);
cy.findByText('로그인을 실패했습니다').should('exist');
});
});
});
54 changes: 54 additions & 0 deletions frontend/cypress/e2e/space-page.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
describe('동글 스페이스 페이지', () => {
beforeEach(() => {
cy.viewport(1440, 810);
cy.visit(`/`);
});

describe('글 업로드 테스트', () => {
it('Add Post 버튼을 누르면 글 가져오기 모달 창이 열린다.', () => {
cy.findByText('Add Post').click();

cy.findByText('글 가져오기').should('exist');
});

it('드래그 앤 드롭으로 마크다운 파일을 업로드할 수 있다.', () => {
cy.findByText('Add Post').click();
cy.findByLabelText('파일 업로드').attachFile('markdown-test.md', {
subjectType: 'drag-n-drop',
});

cy.findByText('markdown-test').should('exist');
cy.findByText('e2e 테스트를 위한 마크다운 파일입니다.').should('exist');
cy.findByText('글 정보').should('exist');
cy.findByLabelText('오른쪽 사이드바 토글').should('exist');
});

it('기본 카테고리에서 업로드한 글을 확인할 수 있다.', () => {
cy.findByText('기본').click();

cy.findAllByText('markdown-test').should('exist');
});
});

describe('카테고리 테스트', () => {
it('카테고리 추가 버튼을 클릭하여 입력 창에 이름을 입력하고 엔터를 쳐서 카테고리를 추가할 수 있다.', () => {
cy.findByLabelText('카테고리 추가 입력 창 열기').click();
cy.findByLabelText('카테고리 추가 입력 창').focus().type('동글이{enter}');
cy.findByText('동글이').should('exist');
});

it('카테고리 이름 수정 버튼을 클릭하여 입력 창에 이름을 입력하고 엔터를 쳐서 카테고리 이름을 수정할 수 있다.', () => {
cy.findByText('동글이').realHover();
cy.findByLabelText('동글이 카테고리 이름 수정').click();
cy.findByLabelText('동글이 카테고리 이름 수정 입력 창').focus().type('동글동글이{enter}');
cy.findByText('동글이').should('not.exist');
cy.findByText('동글동글이').should('exist');
});

it('카테고리 삭제 버튼을 클릭하여 카테고리를 삭제할 수 있다.', () => {
cy.findByText('동글동글이').realHover();
cy.findByLabelText('동글동글이 카테고리 삭제').click();
cy.findByText('동글동글이').should('not.exist');
});
});
});
18 changes: 18 additions & 0 deletions frontend/src/mocks/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { DefaultBodyType, PathParams, RestRequest } from 'msw';

export const MOCK_ACCESS_TOKEN = 'mockAccessToken';

export const ERROR_RESPONSE = {
error: {
message: '유효하지 않은 토큰입니다.',
hint: 'AccessToken이 만료되었습니다. RefreshToken값을 요청하세요.',
code: 4011,
},
};

export const isValidAccessToken = (req: RestRequest<DefaultBodyType, PathParams<string>>) => {
const authorizationHeader = req.headers.get('Authorization');

if (authorizationHeader === `Bearer ${MOCK_ACCESS_TOKEN}`) return true;
return false;
};
17 changes: 15 additions & 2 deletions frontend/src/mocks/handlers/category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@ import {
UpdateCategoryTitleArgs,
} from 'types/apis/category';
import { hasDefinedField } from 'utils/typeGuard';
import { ERROR_RESPONSE, isValidAccessToken } from 'mocks/auth';

export const categoryHandlers = [
// 카테고리 목록 조회
rest.get(categoryURL, (_, res, ctx) => {
rest.get(categoryURL, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.json(categories), ctx.delay(300), ctx.status(200));
}),

// 카테고리 추가
rest.post(categoryURL, (req, res, ctx) => {
const body = req.body as AddCategoriesRequest;

if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

if (!body || !body.categoryName)
return res(
ctx.delay(300),
Expand All @@ -30,6 +35,8 @@ export const categoryHandlers = [

// 카테고리 글 목록 조회
rest.get(`${categoryURL}/:categoryId`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

const categoryId = Number(req.params.categoryId);

if (categoryId !== 1 && categoryId !== 3)
Expand All @@ -51,6 +58,8 @@ export const categoryHandlers = [
const categoryId = Number(req.params.categoryId);
const body = await req.json();

if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

// 카테고리 순서 변경
if (hasDefinedField<UpdateCategoryOrderArgs['body']>(body, 'nextCategoryId')) {
if (!body.nextCategoryId) {
Expand Down Expand Up @@ -83,6 +92,8 @@ export const categoryHandlers = [

// 카테고리 이름 수정
if (hasDefinedField<UpdateCategoryTitleArgs['body']>(body, 'categoryName')) {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

if (!body.categoryName)
return res(
ctx.delay(300),
Expand All @@ -96,7 +107,9 @@ export const categoryHandlers = [
}),

// 카테고리 삭제
rest.delete(`${categoryURL}/:categoryId`, (_, res, ctx) => {
rest.delete(`${categoryURL}/:categoryId`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.delay(300), ctx.status(204));
}),
];
25 changes: 19 additions & 6 deletions frontend/src/mocks/handlers/connections.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
import { connectionsURL } from 'constants/apis/url';
import { ERROR_RESPONSE, isValidAccessToken } from 'mocks/auth';
import { rest } from 'msw';

export const connectionsHandlers = [
// 티스토리 정보 저장
rest.post(`${connectionsURL}/tistory`, (_, res, ctx) => {
rest.post(`${connectionsURL}/tistory`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),

// 미디움 정보 저장
rest.post(`${connectionsURL}/medium`, (_, res, ctx) => {
rest.post(`${connectionsURL}/medium`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),

// 노션 정보 저장
rest.post(`${connectionsURL}/notion`, (_, res, ctx) => {
rest.post(`${connectionsURL}/notion`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),

// 티스토리 연결 해제
rest.post(`${connectionsURL}/tistory/disconnect`, (_, res, ctx) => {
rest.post(`${connectionsURL}/tistory/disconnect`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),

// 미디움 연결 해제
rest.post(`${connectionsURL}/medium/disconnect`, (_, res, ctx) => {
rest.post(`${connectionsURL}/medium/disconnect`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),

// 노션 연결 해제
rest.post(`${connectionsURL}/notion/disconnect`, (_, res, ctx) => {
rest.post(`${connectionsURL}/notion/disconnect`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),
];
3 changes: 2 additions & 1 deletion frontend/src/mocks/handlers/login.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { authURL, loginURL } from 'constants/apis/url';
import { MOCK_ACCESS_TOKEN } from 'mocks/auth';
import { rest } from 'msw';

export const loginHandlers = [
// 카카오 로그인/회원가입: POST
rest.post(`${loginURL}/kakao`, (_, res, ctx) => {
return res(ctx.delay(300), ctx.status(200));
return res(ctx.delay(300), ctx.status(200), ctx.json({ accessToken: MOCK_ACCESS_TOKEN }));
}),

rest.post(`${authURL}/logout`, (_, res, ctx) => {
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/mocks/handlers/member.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { memberURL } from 'constants/apis/url';
import { ERROR_RESPONSE, isValidAccessToken } from 'mocks/auth';
import { member } from 'mocks/memberContentsMock';
import { rest } from 'msw';

export const memberHandlers = [
rest.get(memberURL, (_, res, ctx) => {
// 멤버 정보 가져오기: GET
rest.get(memberURL, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.json(member), ctx.status(200));
}),

// 회원 탈퇴: POST
rest.post(`${memberURL}/delete`, (_, res, ctx) => {
rest.post(`${memberURL}/delete`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),
];
13 changes: 10 additions & 3 deletions frontend/src/mocks/handlers/trash.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import { trashURL } from 'constants/apis/url';
import { ERROR_RESPONSE, isValidAccessToken } from 'mocks/auth';
import { deletedWritings } from 'mocks/trashCanContentsMock';
import { rest } from 'msw';

export const trashHandlers = [
// 글 휴지통으로 이동 / 글 영구 삭제
rest.post(trashURL, (_, res, ctx) => {
rest.post(trashURL, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),

// 휴지통에서 글 목록 조회
rest.get(trashURL, (_, res, ctx) => {
rest.get(trashURL, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.json(deletedWritings), ctx.status(200));
}),

// 휴지통에서 글 복구
rest.post(`${trashURL}/restore`, (_, res, ctx) => {
rest.post(`${trashURL}/restore`, (req, res, ctx) => {
if (!isValidAccessToken(req)) return res(ctx.status(401), ctx.json(ERROR_RESPONSE));

return res(ctx.status(200));
}),
];
Loading
Loading