From 4c511e404f5ffc61e541b7fa374d36497c20b69b Mon Sep 17 00:00:00 2001 From: npmrun <1549469775@qq.com> Date: Fri, 15 May 2026 16:10:45 +0800 Subject: [PATCH] feat: add PasswordStrength component with real-time strength scoring Co-Authored-By: Claude Opus 4.7 --- app/components/register/PasswordStrength.vue | 53 ++++++++++++++++++++++ .../register/__tests__/PasswordStrength.test.ts | 39 ++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 app/components/register/PasswordStrength.vue create mode 100644 app/components/register/__tests__/PasswordStrength.test.ts diff --git a/app/components/register/PasswordStrength.vue b/app/components/register/PasswordStrength.vue new file mode 100644 index 0000000..debcbf8 --- /dev/null +++ b/app/components/register/PasswordStrength.vue @@ -0,0 +1,53 @@ + + + diff --git a/app/components/register/__tests__/PasswordStrength.test.ts b/app/components/register/__tests__/PasswordStrength.test.ts new file mode 100644 index 0000000..82b70ef --- /dev/null +++ b/app/components/register/__tests__/PasswordStrength.test.ts @@ -0,0 +1,39 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import PasswordStrength from '../PasswordStrength.vue' + +describe('PasswordStrength', () => { + it('renders nothing for empty password', () => { + const wrapper = mount(PasswordStrength, { props: { password: '' } }) + expect(wrapper.find('[data-testid="strength-bar"]').exists()).toBe(false) + }) + + it('score 1 for weak password (only letters, < 8)', () => { + const wrapper = mount(PasswordStrength, { props: { password: 'abc' } }) + expect(wrapper.find('[data-testid="strength-bar"]').attributes('data-score')).toBe('1') + expect(wrapper.text()).toContain('弱') + }) + + it('score 1 for only digits', () => { + const wrapper = mount(PasswordStrength, { props: { password: '1234567' } }) + expect(wrapper.find('[data-testid="strength-bar"]').attributes('data-score')).toBe('1') + }) + + it('score 2 for letters+digits >= 8 chars', () => { + const wrapper = mount(PasswordStrength, { props: { password: 'abc12345' } }) + expect(wrapper.find('[data-testid="strength-bar"]').attributes('data-score')).toBe('2') + expect(wrapper.text()).toContain('中') + }) + + it('score 3 for upper+lower+digits >= 10 chars', () => { + const wrapper = mount(PasswordStrength, { props: { password: 'Abcdef1234' } }) + expect(wrapper.find('[data-testid="strength-bar"]').attributes('data-score')).toBe('3') + expect(wrapper.text()).toContain('强') + }) + + it('score 4 for upper+lower+digits+special >= 12 chars', () => { + const wrapper = mount(PasswordStrength, { props: { password: 'Abcdef1234!@' } }) + expect(wrapper.find('[data-testid="strength-bar"]').attributes('data-score')).toBe('4') + expect(wrapper.text()).toContain('很强') + }) +})