diff --git a/resources/assets/src/components/auth/Login.vue b/resources/assets/src/components/auth/Login.vue new file mode 100644 index 00000000..a28d13e1 --- /dev/null +++ b/resources/assets/src/components/auth/Login.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/resources/assets/src/components/route.js b/resources/assets/src/components/route.js index e9a3e55d..2eb3d70d 100644 --- a/resources/assets/src/components/route.js +++ b/resources/assets/src/components/route.js @@ -34,4 +34,9 @@ export default [ component: () => import('./admin/Customization'), el: '#change-color' }, + { + path: 'auth/login', + component: () => import('./auth/Login'), + el: 'form' + }, ]; diff --git a/resources/assets/tests/components/auth/Login.test.js b/resources/assets/tests/components/auth/Login.test.js new file mode 100644 index 00000000..98164967 --- /dev/null +++ b/resources/assets/tests/components/auth/Login.test.js @@ -0,0 +1,69 @@ +import Vue from 'vue'; +import { mount } from '@vue/test-utils'; +import Login from '@/components/auth/Login'; +import { swal } from '@/js/notify'; + +jest.mock('@/js/notify'); + +test('show captcha if too many login fails', () => { + window.__bs_data__ = { tooManyFails: true }; + const wrapper = mount(Login); + expect(wrapper.find('img').attributes().src).toMatch(/\/auth\/captcha\?v=\d+/); +}); + +test('click to refresh captcha', () => { + window.__bs_data__ = { tooManyFails: true }; + jest.spyOn(Date, 'now'); + const wrapper = mount(Login); + wrapper.find('img').trigger('click'); + expect(Date.now).toHaveBeenCalledTimes(2); +}); + +test('login', async () => { + window.__bs_data__ = { tooManyFails: false }; + Vue.prototype.$http.post + .mockResolvedValueOnce({ errno: 1, msg: 'fail' }) + .mockResolvedValueOnce({ errno: 1, login_fails: 4 }) + .mockResolvedValueOnce({ errno: 0, msg: 'ok' }); + const wrapper = mount(Login); + const button = wrapper.find('button'); + const info = wrapper.find('.callout-info'); + const warning = wrapper.find('.callout-warning'); + + button.trigger('click'); + expect(Vue.prototype.$http.post).not.toBeCalled(); + expect(info.text()).toBe('auth.emptyIdentification'); + + wrapper.find('[type="email"]').setValue('a@b.c'); + button.trigger('click'); + expect(Vue.prototype.$http.post).not.toBeCalled(); + expect(info.text()).toBe('auth.emptyPassword'); + + wrapper.find('[type="password"]').setValue('123'); + button.trigger('click'); + await wrapper.vm.$nextTick(); + expect(Vue.prototype.$http.post).toBeCalledWith( + '/auth/login', + { identification: 'a@b.c', password: '123', keep: false } + ); + expect(warning.text()).toBe('fail'); + + button.trigger('click'); + await wrapper.vm.$nextTick(); + expect(swal).toBeCalledWith({ type: 'error', html: 'auth.tooManyFails' }); + expect(wrapper.find('img').exists()).toBeTrue(); + + button.trigger('click'); + expect(info.text()).toBe('auth.emptyCaptcha'); + + wrapper.find('[type="text"]').setValue('a'); + wrapper.find('[type="checkbox"]').setChecked(); + button.trigger('click'); + expect(Vue.prototype.$http.post).toBeCalledWith( + '/auth/login', + { identification: 'a@b.c', password: '123', keep: true, captcha: 'a' } + ); + await wrapper.vm.$nextTick(); + jest.runAllTimers(); + expect(swal).toBeCalledWith({ type: 'success', html: 'ok' }); +}); diff --git a/resources/lang/en/front-end.yml b/resources/lang/en/front-end.yml index eba84efb..31d069f5 100644 --- a/resources/lang/en/front-end.yml +++ b/resources/lang/en/front-end.yml @@ -17,6 +17,15 @@ auth: sending: Sending reset: Reset resetting: Resetting + nickname: Nickname + email: Email + identification: Email or player name + password: Password + captcha: CAPTCHA + change-captcha: Click to change CAPTCHA image. + login-link: Already registered? Log in here. + forgot-link: Forgot password? + keep: Remember me skinlib: addToCloset: Add to closet diff --git a/resources/lang/zh_CN/front-end.yml b/resources/lang/zh_CN/front-end.yml index 435036b7..988b3f90 100644 --- a/resources/lang/zh_CN/front-end.yml +++ b/resources/lang/zh_CN/front-end.yml @@ -17,6 +17,15 @@ auth: sending: 发送中 reset: 重置 resetting: 重置中 + nickname: 昵称 + email: Email + identification: Email 或角色名 + password: 密码 + captcha: 请输入验证码 + change-captcha: 点击以更换图片 + login-link: 已经有账号了?登录 + forgot-link: 忘记密码? + keep: 记住我 skinlib: addToCloset: 添加至衣柜 diff --git a/resources/views/auth/login.tpl b/resources/views/auth/login.tpl index 1ef063e1..af0542fc 100644 --- a/resources/views/auth/login.tpl +++ b/resources/views/auth/login.tpl @@ -16,50 +16,7 @@
{{ Session::pull('msg') }}
@endif -
-
- - -
-
- - -
- -
-
-
- -
-
- -
- CAPTCHA -
- -
- -
- -
-
-
- -
-
- -
- -
-
- -
-
-
+

@lang('auth.register-link') @@ -67,4 +24,12 @@ + + @endsection