-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✅ test: feed 조회, feed 조회수 업데이트 API, QueryFeedDto 테스트 작성
- Loading branch information
1 parent
9f1e5d1
commit 90843dc
Showing
4 changed files
with
296 additions
and
203 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { validate } from 'class-validator'; | ||
import { QueryFeedDto } from '../../../src/feed/dto/query-feed.dto'; | ||
|
||
describe('QueryFeedDto Test', () => { | ||
//given | ||
let queryFeedDto: QueryFeedDto; | ||
|
||
beforeEach(() => { | ||
queryFeedDto = new QueryFeedDto(); | ||
}); | ||
|
||
it('limit에 1보다 작은 값을 입력하면 유효성 검사에 실패한다.', async () => { | ||
//given | ||
queryFeedDto.limit = -1; | ||
|
||
//when | ||
const errors = await validate(queryFeedDto); | ||
|
||
//then | ||
expect(errors).toHaveLength(1); | ||
expect(errors[0].constraints).toHaveProperty('min'); | ||
}); | ||
|
||
it('limit에 자연수가 아닌 실수를 입력하면 유효성 검사에 실패한다.', async () => { | ||
//given | ||
queryFeedDto.limit = 1.254; | ||
|
||
//when | ||
const errors = await validate(queryFeedDto); | ||
|
||
//then | ||
expect(errors).toHaveLength(1); | ||
expect(errors[0].constraints).toHaveProperty('isInt'); | ||
}); | ||
|
||
it('limit에 문자열을 입력하면 유효성 검사에 실패한다.', async () => { | ||
//given | ||
queryFeedDto.limit = 'abcdefg' as any; | ||
|
||
//when | ||
const errors = await validate(queryFeedDto); | ||
|
||
//then | ||
expect(errors).toHaveLength(1); | ||
expect(errors[0].constraints).toHaveProperty('isInt'); | ||
}); | ||
|
||
it('lastId에 음수를 입력하면 유효성 검사에 실패한다.', async () => { | ||
//given | ||
queryFeedDto.lastId = -1; | ||
|
||
//when | ||
const errors = await validate(queryFeedDto); | ||
|
||
//then | ||
expect(errors).toHaveLength(1); | ||
expect(errors[0].constraints).toHaveProperty('min'); | ||
}); | ||
|
||
it('lastId에 자연수가 아닌 실수를 입력하면 유효성 검사에 실패한다.', async () => { | ||
//given | ||
queryFeedDto.lastId = 1.254; | ||
|
||
//when | ||
const errors = await validate(queryFeedDto); | ||
|
||
//then | ||
expect(errors).toHaveLength(1); | ||
expect(errors[0].constraints).toHaveProperty('isInt'); | ||
}); | ||
|
||
it('lastId에 문자열을 입력하면 유효성 검사에 실패한다.', async () => { | ||
//given | ||
queryFeedDto.lastId = 'abcdefg' as any; | ||
|
||
//when | ||
const errors = await validate(queryFeedDto); | ||
|
||
//then | ||
expect(errors).toHaveLength(1); | ||
expect(errors[0].constraints).toHaveProperty('isInt'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,204 +1,127 @@ | ||
import { INestApplication } from '@nestjs/common'; | ||
import * as request from 'supertest'; | ||
import { FeedFixture } from './fixture/feedFixture'; | ||
import { RedisService } from '../../src/common/redis/redis.service'; | ||
import { redisKeys } from '../../src/common/redis/redis.constant'; | ||
import { FeedFixture } from '../fixture/feed.fixture'; | ||
import { FeedRepository } from '../../src/feed/feed.repository'; | ||
import { RssAcceptRepository } from '../../src/rss/rss.repository'; | ||
import { RssFixture } from '../fixture/rss.fixture'; | ||
|
||
describe('Feed E2E Test', () => { | ||
describe('GET api/feed E2E Test', () => { | ||
let app: INestApplication; | ||
let redisService: RedisService; | ||
const testFeedId = 1; | ||
const testIp = `1.1.1.1`; | ||
const latestId = 20; | ||
|
||
beforeAll(async () => { | ||
app = global.testApp; | ||
redisService = app.get(RedisService); | ||
const feedRepository = app.get(FeedRepository); | ||
const rssAcceptRepository = app.get(RssAcceptRepository); | ||
|
||
const blog = await rssAcceptRepository.save({ | ||
name: 'test', | ||
userName: 'test', | ||
email: '[email protected]', | ||
rssUrl: 'https://test.com/rss', | ||
}); | ||
const blog = await rssAcceptRepository.save(RssFixture.createRssFixture()); | ||
|
||
const feeds = Array.from({ length: 20 }).map((_, i) => { | ||
const title = `Test Feed ${i + 1}`; | ||
const path = `http://test.com/post/${i + 1}`; | ||
const thumbnail = `http://test.com/thumbnail/${i + 1}`; | ||
return FeedFixture.createFeedFixture(blog, { title, path, thumbnail }); | ||
const feeds = Array.from({ length: latestId }).map((_, i) => { | ||
return FeedFixture.createFeedFixture(blog, _, i + 1); | ||
}); | ||
|
||
await Promise.all([ | ||
feedRepository.save(feeds), | ||
redisService.redisClient.sadd(`feed:${testFeedId}:ip`, testIp), | ||
await Promise.all([feedRepository.save(feeds)]); | ||
}); | ||
|
||
it('lastId가 없으면 최신 피드부터 전송한다.', async () => { | ||
//given | ||
const testQuery = { limit: 5 }; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()) | ||
.get('/api/feed') | ||
.query(testQuery); | ||
const feedIdArray = []; | ||
for (const feed of response.body.data.result) { | ||
feedIdArray.push(feed.id); | ||
} | ||
|
||
//then | ||
expect(response.status).toBe(200); | ||
expect(feedIdArray).toStrictEqual([ | ||
latestId, | ||
latestId - 1, | ||
latestId - 2, | ||
latestId - 3, | ||
latestId - 4, | ||
]); | ||
expect(response.body.data.hasMore).toBe(true); | ||
expect(response.body.data.lastId).toBe(16); | ||
}); | ||
|
||
describe('GET /api/feed', () => { | ||
describe('페이지네이션이 정상적으로 동작한다.', () => { | ||
it('lastId가 없으면 최신 피드부터 전송한다.', async () => { | ||
//given | ||
const testQuery = { limit: 5 }; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()) | ||
.get('/api/feed') | ||
.query(testQuery); | ||
|
||
//then | ||
expect(response.status).toBe(200); | ||
expect(response.body.message).toBe('피드 조회 완료'); | ||
expect(response.body.data.result).toHaveLength(5); | ||
expect(response.body.data.hasMore).toBe(true); | ||
expect(response.body.data.lastId).toBe(16); | ||
}); | ||
|
||
it('lastId가 있으면 해당 피드 다음 순서부터 전송한다.', async () => { | ||
//given | ||
const testQuery = { limit: 5, lastId: 11 }; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()) | ||
.get('/api/feed') | ||
.query(testQuery); | ||
|
||
//then | ||
expect(response.status).toBe(200); | ||
expect(response.body.message).toBe('피드 조회 완료'); | ||
expect(response.body.data.result).toHaveLength(5); | ||
expect(response.body.data.hasMore).toBe(true); | ||
expect(response.body.data.lastId).toBe(6); | ||
}); | ||
|
||
it('남은 피드 개수보다 limit의 크기가 커도 정상적으로 동작한다.', async () => { | ||
//given | ||
const testQuery = { limit: 15, lastId: 10 }; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()) | ||
.get('/api/feed') | ||
.query(testQuery); | ||
|
||
//then | ||
expect(response.status).toBe(200); | ||
expect(response.body.message).toBe('피드 조회 완료'); | ||
expect(response.body.data.result).toHaveLength(9); | ||
expect(response.body.data.hasMore).toBe(false); | ||
expect(response.body.data.lastId).toBe(1); | ||
}); | ||
|
||
it('남은 피드 개수가 0이면 lastId 0, 빈 배열로 응답한다.', async () => { | ||
//given | ||
const testQuery = { limit: 15, lastId: 1 }; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()) | ||
.get('/api/feed') | ||
.query(testQuery); | ||
|
||
//then | ||
expect(response.status).toBe(200); | ||
expect(response.body.message).toBe('피드 조회 완료'); | ||
expect(response.body.data.result).toHaveLength(0); | ||
expect(response.body.data.hasMore).toBe(false); | ||
expect(response.body.data.lastId).toBe(0); | ||
}); | ||
}); | ||
it('lastId가 있으면 해당 피드 다음 순서부터 전송한다.', async () => { | ||
//given | ||
const testQuery = { limit: 5, lastId: 11 }; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()) | ||
.get('/api/feed') | ||
.query(testQuery); | ||
const feedIdArray = []; | ||
for (const feed of response.body.data.result) { | ||
feedIdArray.push(feed.id); | ||
} | ||
|
||
//then | ||
expect(response.status).toBe(200); | ||
expect(feedIdArray).toStrictEqual([ | ||
testQuery.lastId - 1, | ||
testQuery.lastId - 2, | ||
testQuery.lastId - 3, | ||
testQuery.lastId - 4, | ||
testQuery.lastId - 5, | ||
]); | ||
expect(response.body.data.hasMore).toBe(true); | ||
expect(response.body.data.lastId).toBe(6); | ||
}); | ||
|
||
describe('POST /api/feed/:feedId', () => { | ||
describe('Redis에 해당 IP가 없을 때', () => { | ||
it('쿠키가 없는 경우', async () => { | ||
//given | ||
const testNewIp = `123.234.123.234`; | ||
|
||
try { | ||
//when | ||
const response = await request(app.getHttpServer()) | ||
.post(`/api/feed/${testFeedId}`) | ||
.set('X-Forwarded-For', testNewIp); | ||
|
||
//then | ||
const feedDailyViewCount = parseInt( | ||
await redisService.redisClient.zscore( | ||
redisKeys.FEED_TREND_KEY, | ||
testFeedId.toString(), | ||
), | ||
); | ||
|
||
expect(response.status).toBe(200); | ||
expect(response.body.message).toBe( | ||
'요청이 성공적으로 처리되었습니다.', | ||
); | ||
expect(feedDailyViewCount).toBe(1); | ||
} finally { | ||
//cleanup | ||
await Promise.all([ | ||
redisService.redisClient.zrem( | ||
redisKeys.FEED_TREND_KEY, | ||
testFeedId.toString(), | ||
), | ||
redisService.redisClient.srem(`feed:${testFeedId}:ip`, testNewIp), | ||
]); | ||
} | ||
}); | ||
}); | ||
it('limit의 크기보다 남은 Feed의 개수가 적은 경우면 정상적으로 동작한다.', async () => { | ||
//given | ||
const testQuery = { limit: 15, lastId: 10 }; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()) | ||
.get('/api/feed') | ||
.query(testQuery); | ||
const feedIdArray = []; | ||
for (const feed of response.body.data.result) { | ||
feedIdArray.push(feed.id); | ||
} | ||
|
||
//then | ||
expect(response.status).toBe(200); | ||
expect(feedIdArray).toStrictEqual([ | ||
testQuery.lastId - 1, | ||
testQuery.lastId - 2, | ||
testQuery.lastId - 3, | ||
testQuery.lastId - 4, | ||
testQuery.lastId - 5, | ||
testQuery.lastId - 6, | ||
testQuery.lastId - 7, | ||
testQuery.lastId - 8, | ||
testQuery.lastId - 9, | ||
]); | ||
expect(response.body.data.hasMore).toBe(false); | ||
expect(response.body.data.lastId).toBe(1); | ||
}); | ||
|
||
describe('Redis에 해당 IP가 있을 때', () => { | ||
it('쿠키가 있는 경우', async () => { | ||
//when | ||
const response = await request(app.getHttpServer()) | ||
.post(`/api/feed/${testFeedId}`) | ||
.set('Cookie', `View_count_${testFeedId}=${testFeedId}`) | ||
.set('X-Forwarded-For', testIp); | ||
|
||
//then | ||
const feedDailyViewCount = await redisService.redisClient.zscore( | ||
redisKeys.FEED_TREND_KEY, | ||
testFeedId.toString(), | ||
); | ||
expect(response.status).toBe(200); | ||
expect(response.body.message).toBe('요청이 성공적으로 처리되었습니다.'); | ||
expect(feedDailyViewCount).toBeNull(); | ||
}); | ||
|
||
it('쿠키가 없는 경우', async () => { | ||
//when | ||
const response = await request(app.getHttpServer()) | ||
.post(`/api/feed/${testFeedId}`) | ||
.set('X-Forwarded-For', testIp); | ||
|
||
//then | ||
const feedDailyViewCount = await redisService.redisClient.zscore( | ||
redisKeys.FEED_TREND_KEY, | ||
testFeedId.toString(), | ||
); | ||
expect(response.status).toBe(200); | ||
expect(response.body.message).toBe('요청이 성공적으로 처리되었습니다.'); | ||
expect(feedDailyViewCount).toBeNull(); | ||
}); | ||
|
||
describe('잘못된 요청을 보냈을 때', () => { | ||
it('해당 피드 ID가 존재하지 않는 경우', async () => { | ||
//given | ||
const notExistFeedId = 50000; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()).post( | ||
`/api/feed/${notExistFeedId}`, | ||
); | ||
|
||
//then | ||
expect(response.status).toBe(404); | ||
expect(response.body.message).toBe( | ||
`${notExistFeedId}번 피드를 찾을 수 없습니다.`, | ||
); | ||
}); | ||
}); | ||
}); | ||
it('남은 피드 개수가 0이면 lastId 0, 빈 배열로 응답한다.', async () => { | ||
//given | ||
const testQuery = { limit: 15, lastId: 1 }; | ||
|
||
//when | ||
const response = await request(app.getHttpServer()) | ||
.get('/api/feed') | ||
.query(testQuery); | ||
const feedIdArray = []; | ||
for (const feed of response.body.data.result) { | ||
feedIdArray.push(feed.id); | ||
} | ||
|
||
//then | ||
expect(response.status).toBe(200); | ||
expect(feedIdArray).toStrictEqual([]); | ||
expect(response.body.data.hasMore).toBe(false); | ||
expect(response.body.data.lastId).toBe(0); | ||
}); | ||
}); |
Oops, something went wrong.