Skip to content

Commit

Permalink
Merge pull request #74 from jihwooon/issue-49
Browse files Browse the repository at this point in the history
Admin 계정을 가진 계정만 상품을 조회 할 수 있게 하라
  • Loading branch information
jihwooon authored Sep 26, 2023
2 parents 014d536 + 10852b9 commit e4bf9fb
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 48 deletions.
2 changes: 2 additions & 0 deletions server/src/items/web/item-detail.controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ItemReader } from '../application/item.reader'
import { MYSQL_CONNECTION } from '../../config/database/constants'
import { Connection } from 'mysql2/promise'
import { ItemResponse } from '../dto/detail-item.dto'
import { JwtProvider } from '../../jwt/jwt.provider'

describe('ItemController class', () => {
let itemController: ItemDetailController
Expand All @@ -19,6 +20,7 @@ describe('ItemController class', () => {
providers: [
ItemReader,
ItemRepository,
JwtProvider,
{
provide: MYSQL_CONNECTION,
useValue: connection,
Expand Down
8 changes: 7 additions & 1 deletion server/src/items/web/item-detail.controller.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { Controller, Get, Param } from '@nestjs/common'
import { Controller, Get, Param, UseGuards } from '@nestjs/common'
import { ItemResponse } from '../dto/detail-item.dto'
import { ItemReader } from '../application/item.reader'
import { JwtAuthGuard } from '../../config/auth/guards/jwt-auth.guard'
import { RolesGuard } from '../../config/auth/guards/role-auth.guard'
import { Roles } from '../../config/auth/role.decorator'
import { Role } from '../../members/domain/member-role.enum'

@Controller('items')
export class ItemDetailController {
constructor(private readonly itemService: ItemReader) {}

@Get(':id')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN)
async getItemHandler(@Param('id') id: number): Promise<ItemResponse> {
const { itemName, itemDetail, price, stockNumber, itemSellStatus } = await this.itemService.getItem(id)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Test, TestingModule } from '@nestjs/testing'
import {
ForbiddenException,
INestApplication,
InternalServerErrorException,
NotFoundException,
ValidationPipe,
ForbiddenException,
} from '@nestjs/common'
import * as request from 'supertest'
import { ItemCreater } from '../src/items/application/item.creater'
Expand All @@ -18,7 +18,6 @@ import { ItemRepository } from '../src/items/domain/item.repository'
import { MYSQL_CONNECTION } from '../src/config/database/constants'
import { Connection } from 'mysql2/promise'
import { CreateItemRequest } from '../src/items/dto/save-item.dto'
import { ItemResponse } from '../src/items/dto/detail-item.dto'
import { UpdateItemRequest } from '../src/items/dto/update-item.dto'
import { MemberRepository } from '../src/members/domain/member.repository'
import { userMock } from '../src/fixture/memberFixture'
Expand All @@ -27,11 +26,10 @@ import { jwtTokenFixture } from '../src/fixture/jwtTokenFixture'
import { JwtProvider } from '../src/jwt/jwt.provider'
import { RolesGuard } from '../src/config/auth/guards/role-auth.guard'

describe('ItemController (e2e)', () => {
describe('ItemCreateController (e2e)', () => {
let app: INestApplication
let connection: Connection
let itemCreater: ItemCreater
let itemReader: ItemReader
let itemUpdater: ItemUpdater
let jwtProvider: JwtProvider
let rolesGuard: RolesGuard
Expand All @@ -56,7 +54,6 @@ describe('ItemController (e2e)', () => {
}).compile()

itemCreater = moduleFixture.get<ItemCreater>(ItemCreater)
itemReader = moduleFixture.get<ItemReader>(ItemReader)
itemUpdater = moduleFixture.get<ItemUpdater>(ItemUpdater)
jwtProvider = moduleFixture.get<JwtProvider>(JwtProvider)
rolesGuard = moduleFixture.get<RolesGuard>(RolesGuard)
Expand Down Expand Up @@ -255,48 +252,6 @@ describe('ItemController (e2e)', () => {
})
})

describe('GET /items/:id', () => {
const itemResponse: ItemResponse = {
id: itemMock().id,
itemName: itemMock().itemName,
itemDetail: itemMock().itemDetail,
price: itemMock().price,
stockNumber: itemMock().stockNumber,
sellStatus: itemMock().itemSellStatus,
}
context('id 요청을 하면', () => {
beforeEach(() => {
itemReader.getItem = jest.fn().mockImplementation(() => itemResponse)
})

it('상태코드 200을 응답해야 한다', async () => {
const { status, body } = await request(app.getHttpServer()).get(`/items/${itemMock().id}`)

expect(status).toEqual(200)
expect(body).toEqual(itemResponse)
})
})

context('잘못된 id 요청을 하면', () => {
const not_found_id = (itemMock().id = 9999)
beforeEach(() => {
itemReader.getItem = jest
.fn()
.mockRejectedValue(new NotFoundException(`${not_found_id}에 해당하는 상품을 찾을 수 없습니다.`))
})
it('상태코드 404를 응답해야 한다', async () => {
const { status, body } = await request(app.getHttpServer()).get(`/items/${not_found_id}`)

expect(status).toEqual(404)
expect(body).toEqual({
error: 'Not Found',
message: '9999에 해당하는 상품을 찾을 수 없습니다.',
statusCode: 404,
})
})
})
})

describe('PATCH /items/:id', () => {
context('id와 변경 된 item 요청을 하면', () => {
beforeEach(() => {
Expand Down
120 changes: 120 additions & 0 deletions server/test/item-detail.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { Test, TestingModule } from '@nestjs/testing'
import { INestApplication, NotFoundException, ForbiddenException } from '@nestjs/common'
import * as request from 'supertest'
import { ItemCreater } from '../src/items/application/item.creater'
import { ItemReader } from '../src/items/application/item.reader'
import { ItemUpdater } from '../src/items/application/item.updater'
import { itemMock } from '../src/fixture/itemFixture'
import { ItemUpdateController } from '../src/items/web/item-update.controller'
import { ItemDetailController } from '../src/items/web/item-detail.controller'
import { ItemCreateController } from '../src/items/web/item-create.controller'
import { ItemRepository } from '../src/items/domain/item.repository'
import { MYSQL_CONNECTION } from '../src/config/database/constants'
import { Connection } from 'mysql2/promise'
import { MemberRepository } from '../src/members/domain/member.repository'
import { userMock } from '../src/fixture/memberFixture'
import { JwtAuthGuard } from '../src/config/auth/guards/jwt-auth.guard'
import { jwtTokenFixture } from '../src/fixture/jwtTokenFixture'
import { JwtProvider } from '../src/jwt/jwt.provider'
import { RolesGuard } from '../src/config/auth/guards/role-auth.guard'

describe('ItemDetailController (e2e)', () => {
let app: INestApplication
let connection: Connection
let itemReader: ItemReader
let jwtProvider: JwtProvider
let rolesGuard: RolesGuard

beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
controllers: [ItemCreateController, ItemDetailController, ItemUpdateController],
providers: [
ItemRepository,
ItemReader,
ItemCreater,
ItemUpdater,
MemberRepository,
JwtProvider,
JwtAuthGuard,
RolesGuard,
{
provide: MYSQL_CONNECTION,
useValue: connection,
},
],
}).compile()

itemReader = moduleFixture.get<ItemReader>(ItemReader)
rolesGuard = moduleFixture.get<RolesGuard>(RolesGuard)
jwtProvider = moduleFixture.get<JwtProvider>(JwtProvider)

app = moduleFixture.createNestApplication()

await app.init()
})

describe('GET /items/:id', () => {
beforeEach(() => {
itemReader.getItem = jest.fn().mockImplementation(() => itemMock())
jwtProvider.validateToken = jest.fn().mockResolvedValue(userMock().email)
rolesGuard.canActivate = jest.fn().mockResolvedValue(true)
})
context('회원 id가 주어지고 요청을 성공하면', () => {
it('상태코드 200을 응답해야 한다', async () => {
const itemResponse = {
id: itemMock().id + '',
itemName: itemMock().itemName,
itemDetail: itemMock().itemDetail,
price: itemMock().price,
stockNumber: itemMock().stockNumber,
sellStatus: itemMock().itemSellStatus,
}
const { status, body } = await request(app.getHttpServer())
.get(`/items/${itemMock().id}`)
.set('Authorization', 'Bearer ' + jwtTokenFixture().accessToken)

expect(status).toEqual(200)
expect(body).toEqual(itemResponse)
})
})

context('회원 id가 주어지고 요청을 실패하면', () => {
const not_found_id = (itemMock().id = 9999)
beforeEach(() => {
itemReader.getItem = jest
.fn()
.mockRejectedValue(new NotFoundException(`${not_found_id}에 해당하는 상품을 찾을 수 없습니다.`))
})
it('상태코드 404를 응답해야 한다', async () => {
const { status, body } = await request(app.getHttpServer())
.get(`/items/${not_found_id}`)
.set('Authorization', 'Bearer ' + jwtTokenFixture().accessToken)

expect(status).toEqual(404)
expect(body).toEqual({
error: 'Not Found',
message: '9999에 해당하는 상품을 찾을 수 없습니다.',
statusCode: 404,
})
})
})

context('회원 id가 주어지고 권한 접근을 실패하면', () => {
beforeEach(() => {
rolesGuard.canActivate = jest.fn().mockRejectedValue(new ForbiddenException('접근 할 수 없는 권한입니다'))
})
it('상태코드 403을 응답해야 한다', async () => {
const { status, body } = await request(app.getHttpServer())
.get(`/items/${itemMock().id}`)
.set('Authorization', 'Bearer ' + jwtTokenFixture().accessToken)

expect(status).toEqual(403)
expect(body).toEqual({ error: 'Forbidden', message: '접근 할 수 없는 권한입니다', statusCode: 403 })
})
})
})

afterAll(async () => {
await app.close()
})
})

0 comments on commit e4bf9fb

Please sign in to comment.