diff --git a/test/business/login.e2e-spec.ts b/test/business/login.e2e-spec.ts new file mode 100644 index 0000000..38f4cc4 --- /dev/null +++ b/test/business/login.e2e-spec.ts @@ -0,0 +1,182 @@ +/** + * 登录功能端到端测试 + */ + +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { AppModule } from '../../src/app.module'; + +describe('Login (e2e)', () => { + let app: INestApplication; + + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); + }); + + afterEach(async () => { + await app.close(); + }); + + describe('/auth/register (POST)', () => { + it('should register a new user', () => { + return request(app.getHttpServer()) + .post('/auth/register') + .send({ + username: 'testuser' + Date.now(), + password: 'password123', + nickname: '测试用户', + email: `test${Date.now()}@example.com` + }) + .expect(201) + .expect((res) => { + expect(res.body.success).toBe(true); + expect(res.body.data.user.username).toBeDefined(); + expect(res.body.data.access_token).toBeDefined(); + }); + }); + + it('should return error for invalid password', () => { + return request(app.getHttpServer()) + .post('/auth/register') + .send({ + username: 'testuser', + password: '123', // 密码太短 + nickname: '测试用户' + }) + .expect(400); + }); + }); + + describe('/auth/login (POST)', () => { + it('should login with valid credentials', async () => { + // 先注册用户 + const username = 'logintest' + Date.now(); + await request(app.getHttpServer()) + .post('/auth/register') + .send({ + username, + password: 'password123', + nickname: '登录测试用户' + }); + + // 然后登录 + return request(app.getHttpServer()) + .post('/auth/login') + .send({ + identifier: username, + password: 'password123' + }) + .expect(200) + .expect((res) => { + expect(res.body.success).toBe(true); + expect(res.body.data.user.username).toBe(username); + expect(res.body.data.access_token).toBeDefined(); + }); + }); + + it('should return error for invalid credentials', () => { + return request(app.getHttpServer()) + .post('/auth/login') + .send({ + identifier: 'nonexistent', + password: 'wrongpassword' + }) + .expect(200) // 业务层返回200,但success为false + .expect((res) => { + expect(res.body.success).toBe(false); + expect(res.body.error_code).toBe('LOGIN_FAILED'); + }); + }); + }); + + describe('/auth/github (POST)', () => { + it('should handle GitHub OAuth login', () => { + return request(app.getHttpServer()) + .post('/auth/github') + .send({ + github_id: 'github' + Date.now(), + username: 'githubuser' + Date.now(), + nickname: 'GitHub用户', + email: `github${Date.now()}@example.com`, + avatar_url: 'https://avatars.githubusercontent.com/u/123456' + }) + .expect(200) + .expect((res) => { + expect(res.body.success).toBe(true); + expect(res.body.data.user.username).toBeDefined(); + expect(res.body.data.is_new_user).toBe(true); + }); + }); + }); + + describe('/auth/forgot-password (POST)', () => { + it('should send password reset code', async () => { + // 先注册用户 + const email = `reset${Date.now()}@example.com`; + await request(app.getHttpServer()) + .post('/auth/register') + .send({ + username: 'resettest' + Date.now(), + password: 'password123', + nickname: '重置测试用户', + email + }); + + // 发送重置验证码 + return request(app.getHttpServer()) + .post('/auth/forgot-password') + .send({ + identifier: email + }) + .expect(200) + .expect((res) => { + expect(res.body.success).toBe(true); + expect(res.body.data.verification_code).toMatch(/^\d{6}$/); + }); + }); + }); + + describe('/auth/reset-password (POST)', () => { + it('should reset password with valid code', async () => { + // 先注册用户 + const email = `resetpwd${Date.now()}@example.com`; + await request(app.getHttpServer()) + .post('/auth/register') + .send({ + username: 'resetpwdtest' + Date.now(), + password: 'password123', + nickname: '重置密码测试用户', + email + }); + + // 获取验证码 + const codeResponse = await request(app.getHttpServer()) + .post('/auth/forgot-password') + .send({ + identifier: email + }); + + const verificationCode = codeResponse.body.data.verification_code; + + // 重置密码 + return request(app.getHttpServer()) + .post('/auth/reset-password') + .send({ + identifier: email, + verification_code: verificationCode, + new_password: 'newpassword123' + }) + .expect(200) + .expect((res) => { + expect(res.body.success).toBe(true); + expect(res.body.message).toBe('密码重置成功'); + }); + }); + }); +}); \ No newline at end of file