前段
Change-Id: I718d4d07ea03c6d2b6bcbd4d426c5d1af2201bf4
diff --git a/src/api/auth.js b/src/api/auth.js
new file mode 100644
index 0000000..ad845bb
--- /dev/null
+++ b/src/api/auth.js
@@ -0,0 +1,37 @@
+// src/api/auth.js
+import axios from 'axios';
+
+// 创建并导出 axios 实例
+export const api = axios.create({
+ baseURL: 'http://localhost:8088',
+ timeout: 5000,
+});
+
+// 请求拦截器
+api.interceptors.request.use(config => {
+ const token = localStorage.getItem('token');
+ if (token) {
+ config.headers.Authorization = `Bearer ${token}`;
+ }
+ return config;
+});
+
+export const login = async (username, password) => {
+ const response = await api.post('/user/login', null, {
+ params: { username, password }
+ });
+ if (response.data.code === 200 && response.data.data.token) {
+ localStorage.setItem('token', response.data.data.token);
+ }
+ return response;
+};
+
+export const register = (username, password, code) => {
+ return api.post('/user/regist', null, {
+ params: { username, password, code }
+ });
+};
+
+export const getUserInfo = (token) => {
+ return api.get('/user/info', { params: { token } });
+};
\ No newline at end of file
diff --git a/src/api/auth.test.js b/src/api/auth.test.js
new file mode 100644
index 0000000..c9ace4d
--- /dev/null
+++ b/src/api/auth.test.js
@@ -0,0 +1,114 @@
+import MockAdapter from 'axios-mock-adapter';
+import { api, login, register, getUserInfo } from './auth';
+
+describe('auth API', () => {
+ let mockAxios;
+
+ beforeEach(() => {
+ // 确保使用我们导出的 api 实例
+ mockAxios = new MockAdapter(api);
+ localStorage.clear();
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ describe('login', () => {
+ it('should send login request with username and password', async () => {
+ const mockResponse = {
+ code: 200,
+ data: {
+ token: 'mock-token',
+ // 确保响应结构与实际API一致
+ userInfo: { username: 'testuser' }
+ },
+ message: '登录成功'
+ };
+
+ mockAxios.onPost('/user/login').reply(200, mockResponse);
+
+ const response = await login('testuser', 'testpass');
+
+ expect(response.data).toEqual(mockResponse);
+ // 检查token是否存入localStorage
+ expect(localStorage.getItem('token')).toBe('mock-token');
+ });
+
+
+ it('should handle login failure', async () => {
+ mockAxios.onPost('/user/login').reply(401);
+
+ await expect(login('wronguser', 'wrongpass')).rejects.toThrow();
+ });
+ });
+
+ describe('register', () => {
+ it('should send register request with username, password and code', async () => {
+ const mockResponse = {
+ code: 200,
+ message: '注册成功'
+ };
+
+ mockAxios.onPost('/user/regist').reply(200, mockResponse);
+
+ const response = await register('newuser', 'newpass', 'invite123');
+
+ expect(response.data).toEqual(mockResponse);
+ });
+
+ it('should handle registration failure', async () => {
+ mockAxios.onPost('/user/regist').reply(400);
+
+ await expect(register('newuser', 'newpass', 'wrongcode')).rejects.toThrow();
+ });
+ });
+
+ describe('getUserInfo', () => {
+ it('should send request with token to get user info', async () => {
+ const mockResponse = {
+ code: 200,
+ data: { username: 'testuser', role: 'user' }
+ };
+
+ mockAxios.onGet('/user/info').reply(200, mockResponse);
+
+ const response = await getUserInfo('test-token');
+
+ expect(response.data).toEqual(mockResponse);
+ });
+
+ it('should handle unauthorized request', async () => {
+ mockAxios.onGet('/user/info').reply(401);
+
+ await expect(getUserInfo('invalid-token')).rejects.toThrow();
+ });
+ });
+
+ describe('request interceptor', () => {
+ it('should add Authorization header when token exists', async () => {
+ localStorage.setItem('token', 'test-token');
+ const mockResponse = { data: 'success' };
+
+ mockAxios.onGet('/test').reply((config) => {
+ expect(config.headers.Authorization).toBe('Bearer test-token');
+ return [200, mockResponse];
+ });
+
+ const response = await api.get('/test');
+ expect(response.data).toEqual(mockResponse);
+ });
+
+ it('should not add Authorization header when token does not exist', async () => {
+ const mockResponse = { data: 'success' };
+
+ mockAxios.onGet('/test').reply((config) => {
+ expect(config.headers.Authorization).toBeUndefined();
+ return [200, mockResponse];
+ });
+
+ const response = await api.get('/test');
+ expect(response.data).toEqual(mockResponse);
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/api/helpComment.js b/src/api/helpComment.js
new file mode 100644
index 0000000..e711587
--- /dev/null
+++ b/src/api/helpComment.js
@@ -0,0 +1,13 @@
+import { api } from './auth';
+
+export const likePostComment = (commentId) => {
+ return api.post(`/help/comments/${commentId}/like`);
+};
+
+export const getCommentReplies = (commentId) => {
+ return api.get(`/help/comments/${commentId}/replies`);
+};
+
+export const addCommentReply = (commentId, replyData) => {
+ return api.post(`/help/comments/${commentId}/replies`, replyData);
+};
\ No newline at end of file
diff --git a/src/api/helpComment.test.js b/src/api/helpComment.test.js
new file mode 100644
index 0000000..2b7be4c
--- /dev/null
+++ b/src/api/helpComment.test.js
@@ -0,0 +1,45 @@
+import MockAdapter from 'axios-mock-adapter';
+import { api } from './auth'; // 添加api导入
+import { likePostComment, getCommentReplies, addCommentReply } from './helpComment';
+
+describe('求助帖评论API', () => {
+ let mockAxios;
+
+ beforeEach(() => {
+ mockAxios = new MockAdapter(api);
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ describe('likePostComment - 点赞求助帖评论', () => {
+ it('应该成功发送点赞请求', async () => {
+ const mockResponse = { code: 200, message: '点赞成功' };
+ mockAxios.onPost('/help/comments/123/like').reply(200, mockResponse);
+
+ const response = await likePostComment('123');
+ expect(response.data).toEqual(mockResponse);
+ });
+ });
+
+ describe('getCommentReplies - 获取评论回复', () => {
+ it('应该返回正确的回复数据结构', async () => {
+ const mockData = [{ id: '1', content: '回复内容' }];
+ mockAxios.onGet('/help/comments/456/replies').reply(200, { code: 200, data: mockData });
+
+ const response = await getCommentReplies('456');
+ expect(response.data.data).toEqual(mockData);
+ });
+ });
+
+ describe('addCommentReply - 添加评论回复', () => {
+ it('应该正确发送回复内容', async () => {
+ const testData = { content: '测试回复', author: 'user1' };
+ mockAxios.onPost('/help/comments/789/replies', testData).reply(200, { code: 200 });
+
+ const response = await addCommentReply('789', testData);
+ expect(response.status).toBe(200);
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/api/helpPost.js b/src/api/helpPost.js
new file mode 100644
index 0000000..426e92b
--- /dev/null
+++ b/src/api/helpPost.js
@@ -0,0 +1,28 @@
+// src/api/helpPost.js
+import { api } from './auth'; // 复用已有的axios实例
+
+export const createPost = (title, content, authorId) => {
+ return api.post('/help/posts', {
+ title,
+ content,
+ authorId
+ });
+};
+
+export const getPosts = (page = 1, size = 5) => {
+ return api.get('/help/posts', {
+ params: { page, size }
+ });
+};
+
+export const getPostDetail = (postId) => {
+ return api.get(`/help/posts/${postId}`);
+};
+
+export const likePost = (postId) => {
+ return api.post(`/help/posts/${postId}/like`);
+};
+
+export const addPostComment = (postId, commentData) => {
+ return api.post(`/help/posts/${postId}/comments`, commentData);
+};
\ No newline at end of file
diff --git a/src/api/helpPost.test.js b/src/api/helpPost.test.js
new file mode 100644
index 0000000..e163090
--- /dev/null
+++ b/src/api/helpPost.test.js
@@ -0,0 +1,60 @@
+import MockAdapter from 'axios-mock-adapter';
+import { api } from './auth'; // 添加api导入
+import { createPost, getPosts, getPostDetail, likePost, addPostComment } from './helpPost';
+
+describe('求助帖API', () => {
+ let mockAxios;
+
+ beforeEach(() => {
+ mockAxios = new MockAdapter(api);
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ describe('createPost - 创建求助帖', () => {
+ it('应该正确发送帖子数据', async () => {
+ const postData = {
+ title: '测试标题',
+ content: '测试内容',
+ authorId: 'user123'
+ };
+ mockAxios.onPost('/help/posts', postData).reply(201, { code: 201 });
+
+ const response = await createPost(postData.title, postData.content, postData.authorId);
+ expect(response.status).toBe(201);
+ });
+ });
+
+ describe('getPosts - 获取求助帖列表', () => {
+ it('应该支持分页参数', async () => {
+ const page = 2, size = 10;
+ mockAxios.onGet('/help/posts', { params: { page, size } }).reply(200, {
+ code: 200,
+ data: []
+ });
+
+ const response = await getPosts(page, size);
+ expect(response.status).toBe(200);
+ });
+ });
+
+ describe('likePost - 点赞求助帖', () => {
+ it('应该正确发送点赞请求', async () => {
+ mockAxios.onPost('/help/posts/post123/like').reply(200, { code: 200 });
+ const response = await likePost('post123');
+ expect(response.status).toBe(200);
+ });
+ });
+
+ describe('addPostComment - 添加帖子评论', () => {
+ it('应该正确发送评论数据', async () => {
+ const comment = { content: '测试评论', author: 'user1' };
+ mockAxios.onPost('/help/posts/post456/comments', comment).reply(200, { code: 200 });
+
+ const response = await addPostComment('post456', comment);
+ expect(response.status).toBe(200);
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/api/torrent.js b/src/api/torrent.js
new file mode 100644
index 0000000..7118436
--- /dev/null
+++ b/src/api/torrent.js
@@ -0,0 +1,48 @@
+// src/api/torrent.js
+import { api } from './auth'; // 复用已有的axios实例
+
+export const createTorrent = (torrentName, description, username, category, region, resolution, subtitle, filePath) => {
+ return api.post('/torrent', {
+ torrentName,
+ description,
+ username,
+ category,
+ region,
+ resolution,
+ subtitle,
+ filePath
+ });
+};
+
+export const getTorrents = (page = 1, size = 5) => {
+ return api.get('/torrent', {
+ params: { page, size }
+ });
+};
+
+export const getTorrentDetail = (torrentId) => {
+ return api.get(`/torrent/${torrentId}`).then(response => {
+ // 确保数据结构一致
+ if (response.data && response.data.data) {
+ return {
+ ...response,
+ data: {
+ ...response.data,
+ data: {
+ torrent: response.data.data.post || response.data.data.torrent,
+ comments: response.data.data.comments || []
+ }
+ }
+ };
+ }
+ return response;
+ });
+};
+
+export const likeTorrent = (torrentId) => {
+ return api.post(`/torrent/${torrentId}/like`);
+};
+
+export const addTorrentComment = (torrentId, commentData) => {
+ return api.post(`/torrent/${torrentId}/comments`, commentData);
+};
\ No newline at end of file
diff --git a/src/api/torrent.test.js b/src/api/torrent.test.js
new file mode 100644
index 0000000..c4de6c5
--- /dev/null
+++ b/src/api/torrent.test.js
@@ -0,0 +1,58 @@
+import MockAdapter from 'axios-mock-adapter';
+import { api } from './auth'; // 添加api导入
+import { createTorrent, getTorrents, getTorrentDetail, likeTorrent, addTorrentComment } from './torrent';
+
+describe('种子资源API', () => {
+ let mockAxios;
+
+ beforeEach(() => {
+ mockAxios = new MockAdapter(api);
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ describe('createTorrent - 创建种子', () => {
+ it('应该发送完整的种子数据', async () => {
+ const torrentData = {
+ torrentName: '测试种子',
+ description: '描述内容',
+ username: 'user1',
+ category: '电影',
+ region: '美国',
+ resolution: '1080p',
+ subtitle: '中文字幕',
+ filePath: '/path/to/file'
+ };
+ mockAxios.onPost('/torrent', torrentData).reply(201, { code: 201 });
+
+ const response = await createTorrent(...Object.values(torrentData));
+ expect(response.status).toBe(201);
+ });
+ });
+
+ describe('getTorrentDetail - 获取种子详情', () => {
+ it('应该规范化返回的数据结构', async () => {
+ const mockData = {
+ data: {
+ post: { id: '123', name: '测试种子' },
+ comments: [{ id: '1', content: '评论1' }]
+ }
+ };
+ mockAxios.onGet('/torrent/123').reply(200, mockData);
+
+ const response = await getTorrentDetail('123');
+ expect(response.data.data.torrent.name).toBe('测试种子');
+ expect(response.data.data.comments).toHaveLength(1);
+ });
+ });
+
+ describe('likeTorrent - 点赞种子', () => {
+ it('应该成功发送点赞请求', async () => {
+ mockAxios.onPost('/torrent/t123/like').reply(200, { code: 200 });
+ const response = await likeTorrent('t123');
+ expect(response.status).toBe(200);
+ });
+ });
+});
\ No newline at end of file
diff --git a/src/api/torrentComment.js b/src/api/torrentComment.js
new file mode 100644
index 0000000..f15ce4b
--- /dev/null
+++ b/src/api/torrentComment.js
@@ -0,0 +1,13 @@
+import { api } from './auth';
+
+export const likeTorrentComment = (commentId) => {
+ return api.post(`/torrent/comments/${commentId}/like`);
+};
+
+export const getCommentReplies = (commentId) => {
+ return api.get(`/torrent/comments/${commentId}/replies`);
+};
+
+export const addCommentReply = (commentId, replyData) => {
+ return api.post(`/torrent/comments/${commentId}/replies`, replyData);
+};
\ No newline at end of file
diff --git a/src/api/torrentComment.test.js b/src/api/torrentComment.test.js
new file mode 100644
index 0000000..585b0d3
--- /dev/null
+++ b/src/api/torrentComment.test.js
@@ -0,0 +1,60 @@
+import MockAdapter from 'axios-mock-adapter';
+import { api } from './auth'; // 添加api导入
+import { likeTorrentComment, getCommentReplies, addCommentReply } from './torrentComment';
+
+describe('种子评论API', () => {
+ let mockAxios;
+
+ beforeEach(() => {
+ mockAxios = new MockAdapter(api);
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
+ });
+
+ describe('likeTorrentComment - 点赞种子评论', () => {
+ it('应该成功发送点赞请求', async () => {
+ const commentId = '123';
+ const mockResponse = { code: 200, message: '点赞成功' };
+
+ mockAxios.onPost(`/torrent/comments/${commentId}/like`).reply(200, mockResponse);
+
+ const response = await likeTorrentComment(commentId);
+ expect(response.data).toEqual(mockResponse);
+ });
+
+ it('应该处理点赞失败的情况', async () => {
+ mockAxios.onPost('/torrent/comments/123/like').reply(500);
+ await expect(likeTorrentComment('123')).rejects.toThrow();
+ });
+ });
+
+ describe('getCommentReplies - 获取评论回复', () => {
+ it('应该成功获取回复列表', async () => {
+ const commentId = '456';
+ const mockResponse = {
+ code: 200,
+ data: [{ id: '1', content: '回复1' }, { id: '2', content: '回复2' }]
+ };
+
+ mockAxios.onGet(`/torrent/comments/${commentId}/replies`).reply(200, mockResponse);
+
+ const response = await getCommentReplies(commentId);
+ expect(response.data).toEqual(mockResponse);
+ });
+ });
+
+ describe('addCommentReply - 添加评论回复', () => {
+ it('应该成功添加回复', async () => {
+ const commentId = '789';
+ const replyData = { content: '测试回复' };
+ const mockResponse = { code: 200, data: { id: '3', ...replyData } };
+
+ mockAxios.onPost(`/torrent/comments/${commentId}/replies`, replyData).reply(200, mockResponse);
+
+ const response = await addCommentReply(commentId, replyData);
+ expect(response.data).toEqual(mockResponse);
+ });
+ });
+});
\ No newline at end of file