diff --git a/app/api.js b/app/api.js index d9b84f50..efc1150e 100644 --- a/app/api.js +++ b/app/api.js @@ -6,6 +6,7 @@ let DOMAIN = DEV_ENV; //获取当前网站的根目录 var Local_Host = window.location.host; +var Local_Href = window.location.href; //根据local host切换api function hasHost(host) { @@ -13,7 +14,7 @@ function hasHost(host) { } function isDevHost(host) { - const re = /dev\.|192\.|localhost/i; + const re = /dev\.|192\.|localhost|0\./i; const founds = host.match(re); if (founds != null) { return true; @@ -44,7 +45,7 @@ var API_CONST = { verifyTelResetPassWord: API_URL + 'User.VerifyTelResetPassWord', receiveTelResetPassWord: API_URL + 'User.ReceiveTelResetPassWord', logout: API_URL + "User.Logout", - weixin_login: API_URL + "openuser.login&serviceid=weixin&redirecturl=" + Local_Host, + weixin_login: API_URL + "openuser.login&serviceid=weixin&redirecturl=" + Local_Href, current_user: API_URL + 'User.CurrentUser', currentUserDetail: API_URL + 'User.CurrentUserDetail', changeAvatar: API_URL + 'User.ChangeAvatar', diff --git a/app/components/Index/index.js b/app/components/Index/index.js index d7d82ab8..3b5cba88 100644 --- a/app/components/Index/index.js +++ b/app/components/Index/index.js @@ -119,22 +119,6 @@ var Index = React.createClass({
-
- - {ImgNodes} - -
-
- {sliderButtons} -
-
-
@@ -170,49 +154,6 @@ var Index = React.createClass({ -
- -
- -
-
-
访谈
-
INTERVIEW
-
-
- -
- -
- -
- -
- -
-
-
活动
-
ACTIVITY
-
-
- -
- -
- -
diff --git a/app/components/SidePage.js b/app/components/SidePage.js index 04d92402..f1d3999e 100644 --- a/app/components/SidePage.js +++ b/app/components/SidePage.js @@ -16,10 +16,6 @@ var style={ loginBox: { position: 'relative', }, - logoutIcon:{ - // float: 'left', - // margin: '2px -73px 0 33px' - }, logout:{ position: 'absolute', top: '58px', @@ -88,7 +84,6 @@ var SidePage = React.createClass({ render: function() { var accountContent = ''; if(this.props.userData && this.props.userData.isLogin){ - //这个link应该指向用户中心 accountContent = (
@@ -123,7 +118,6 @@ var SidePage = React.createClass({ } return(
摄影师
-
- -
访谈
-
-
-
- -
活动
-
-
diff --git a/app/stores/AlbumsStore.js b/app/stores/AlbumsStore.js index b7bfebc6..c9160283 100644 --- a/app/stores/AlbumsStore.js +++ b/app/stores/AlbumsStore.js @@ -28,7 +28,7 @@ var AlbumsStore = Reflux.createStore({ this.listenTo(AlbumsActions.search.failed,this.onFailed); this.listenTo(AlbumsActions.getMyAlbums.success,this.onGetMyAlbumsSuccess); this.listenTo(AlbumsActions.getMyAlbums.failed,this.onFailed); - this.listenTo(AlbumsActions.getCategories.success,this.onGetCategoiesSuccess); + this.listenTo(AlbumsActions.getCategories.success,this.onGetCategoriesSuccess); this.listenTo(AlbumsActions.getCategories.failed,this.onFailed); this.listenTo(AlbumsActions.onSale.success,this.onSaleSuccess); this.listenTo(AlbumsActions.onSale.failed,this.onFailed); @@ -39,7 +39,7 @@ var AlbumsStore = Reflux.createStore({ }, onFailed : function(res){ this.data.hintMessage = '网络错误'; - this.data.flag == 'failed'; + this.data.flag = 'failed'; this.trigger(this.data); }, onAddSuccess : function(res){ @@ -107,7 +107,7 @@ var AlbumsStore = Reflux.createStore({ this.data.flag = 'getMyAlbums'; this.trigger(this.data); }, - onGetCategoiesSuccess : function(res){ + onGetCategoriesSuccess : function(res){ if(res.Success){ this.data.categories = res.Result; this.hintMessage = ''; diff --git a/karma.conf.js b/karma.conf.js index d428fffa..f7e65fe2 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -5,7 +5,7 @@ module.exports = function karmaConfig (config) { config.set({ frameworks: [ // Set framework to mocha - 'mocha' + 'mocha', 'sinon' ], reporters: [ diff --git a/package.json b/package.json index 1e7093a1..555f694f 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "karma-coverage": "^0.5.3", "karma-mocha": "^0.2.0", "karma-phantomjs-launcher": "^0.2.1", + "karma-sinon": "^1.0.4", "karma-sourcemap-loader": "^0.3.6", "karma-spec-reporter": "0.0.22", "karma-tap": "^1.0.3", @@ -60,6 +61,7 @@ "phantomjs": "^1.9.18", "phantomjs-polyfill": "0.0.1", "react-hot-loader": "^1.3.0", + "sinon": "^1.17.2", "style-loader": "^0.13.0", "webpack": "^1.12.2", "webpack-dev-server": "^1.12.1", diff --git a/tests/apiSwitch_test.js b/tests/apiSwitch_test.js index 900f66f9..6c5a4978 100644 --- a/tests/apiSwitch_test.js +++ b/tests/apiSwitch_test.js @@ -14,30 +14,18 @@ describe('API switch', () => { 'dev.manage.aiyaopai.com', 'localhost:8080', '192.168.3.2:5000/#/login_page', - 'http://yaopai-mobile-dev.herokuapp.com/' + 'http://yaopai-mobile-dev.herokuapp.com/', + 'http://0.0.0.0:5000', + 'dev.p.aiyaopai.com' ]; const prodHosts = [ 'm.aiyaopai.com/', 'manage.aiyaopai.com', - 'http://yaopai-mobile.herokuapp.com/' + 'http://yaopai-mobile.herokuapp.com/', + 'p.aiyaopai.com' ]; - it('will get right local host', () => { - const dev_host = 'http://yaopai-mobile-dev.heroku.com/#/work?_k=gn36vo'; - const pro_host = 'http://yaopai-mobile.heroku.com/#/work?_k=gn36vo'; - - const re = /dev\.|192\.|localhost/i; - expect(dev_host).to.match(re); - expect(pro_host).to.not.match(re); - expect('m.aiyaopai.com/').to.not.match(re); - expect('dev.m.aiyaopai.com/').to.match(re); - expect('dev.manage.aiyaopai.com').to.match(re); - expect('manage.aiyaopai.com').to.not.match(re); - expect('localhost:8080').to.match(re); - expect('192.168.3.2:5000/#/login_page').to.match(re); - }); - it('has hosts', () => { devHosts.forEach((host, i) => { expect(hasHost(host)).to.equal(true); @@ -82,7 +70,7 @@ function isProdHost(host) { } function isDevHost(host) { - const re = /dev\.|192\.|localhost/i; + const re = /dev\.|192\.|localhost|0\./i; const founds = host.match(re); if (founds != null) { return true; diff --git a/tests/components/SignupPage_test.js b/tests/components/SignupPage_test.js new file mode 100644 index 00000000..f9a11134 --- /dev/null +++ b/tests/components/SignupPage_test.js @@ -0,0 +1,288 @@ +import React from 'react/addons'; +import assert from 'assert'; +import SignupPage from '../../app/components/SignupPage.js'; + +// 定义常用React测试函数 +const { + renderIntoDocument, + findRenderedDOMComponentWithClass, + Simulate +} = React.addons.TestUtils; + +describe('用户注册页面 SignupPage', () => { + // sinon绑定 showMessage + let spyShowMessage = sinon.spy(SignupPage.prototype.__reactAutoBindMap, 'showMessage'); + beforeEach(() => { + spyShowMessage.reset(); + }); + // 渲染被调用的模块 + const component = renderIntoDocument( + + ); + // 通过Class获取组件 + const signupPage = findRenderedDOMComponentWithClass(component, 'signupPage'); + + it('React渲染页面成功', () => { + // 获取textContent内容,简单判断是否成功 + assert.equal(signupPage.getDOMNode().textContent, '获取验证码创建账号'); + }); + + describe('手机号输入框 组件', () => { + // 获取手机号输入框DOM + const mobileNumber = React.findDOMNode(component.refs.mobileNumber); + + it('mobileNumber 组件存在', () => { + // 检测是否为text属性 + assert.equal(mobileNumber.getAttribute('type'), 'text'); + // 检测placeholder是否为 手机号 + assert.equal(mobileNumber.getAttribute('placeholder'), '手机号'); + }); + + it('输入号码后,会更新state', () => { + // 获得初始state + const initialPhone = component.state.phone; + // 初始号码为空 + assert.equal(initialPhone, ''); + // 模拟进入控件 + Simulate.click(mobileNumber); + // 修改输入框内容 + mobileNumber.value = '13552987637'; + Simulate.change(mobileNumber); + const changedPhone = component.state.phone; + // 测试输入前后的state不一样 + assert.notEqual(changedPhone, initialPhone); + }); + }); + + describe('获取验证码 组件', () => { + it('getVerificationCode 组件存在', () => { + const getVerificationCode = React.findDOMNode(component.refs.getVerificationCode); + assert.equal(getVerificationCode.textContent, '获取验证码'); + }); + + it('点击后激活 _handleGetCode', () => { + let spyGetCode = sinon.spy(SignupPage.prototype.__reactAutoBindMap, "_handleGetCode"); + const component = renderIntoDocument( + + ); + + // 模拟点击 + const getVerificationCode = React.findDOMNode(component.refs.getVerificationCode); + Simulate.click(getVerificationCode); + // 验证 + assert.equal(spyGetCode.called, true); + }); + + describe('_handleGetCode', () => { + it('等待验证码时,直接返回', () => { + component.state.codeLeft = 8; + // 马上取值,强制state更新 + const forceState = component.state.codeLeft; + const re = component._handleGetCode(); + // 直接返回的函数是undefined + assert.equal(typeof re, 'undefined'); + }); + + it('初始化时,进入函数,判断手机', () => { + component.state.codeLeft = 0; + // 马上取值,强制state更新 + const forceState = component.state.codeLeft; + const re = component._handleGetCode(); + // 直接返回的函数是undefined + assert.equal(re, false); + }); + + it('手机号符合/不符合', () => { + const component = renderIntoDocument(); + const validatedMobile = '13552987637'; + component.state.phone = validatedMobile; + const forceState = component.state.phone; + const re = component._handleGetCode(); + // 进入验证环节 + assert.equal(re, false); + // 手机号符合,不会调用showMessage + assert.equal(spyShowMessage.called, false); + + const inValidatedMobile = '1355298763777'; + component.state.phone = inValidatedMobile; + const forceState2 = component.state.phone; + const reInvalidate = component._handleGetCode(); + // 进入验证环节 + assert.equal(reInvalidate, false); + // 手机号不符合,会调用showMessage + assert.equal(spyShowMessage.called, true); + // 以正确提示信息调用 + assert.equal(spyShowMessage.withArgs('请输入正确的手机号码').calledOnce, true); + }); + }); + }); + + describe('密码输入框 组件', () => { + it('passWord 组件存在', () => { + const passWord = React.findDOMNode(component.refs.passWord); + assert.equal(passWord.placeholder, '输入密码'); + }); + + it('_handlePassword1Change', () => { + // 密码修改前 + let password1 = component.state.password1; + assert.equal(password1, ''); + // 修改密码 + const passWord = React.findDOMNode(component.refs.passWord); + const testPass = "testing password"; + passWord.value = testPass; + Simulate.change(passWord); + const forceState = component.state.password1; + // 密码修改后 + assert.equal(component.state.password1, testPass); + }); + }); + + describe('验证码输入框 组件', () => { + const verificationCode = React.findDOMNode(component.refs.verificationCode); + it('verificationCode 组件存在', () => { + assert.equal(verificationCode.placeholder, '验证码') + }); + + it('_handleCodeChange', () => { + // 修改注册码前 + let vCode = component.state.code; + assert.equal(vCode, ''); + // 修改注册码 + const testCode = 'asldfjoewf'; + verificationCode.value = testCode; + Simulate.change(verificationCode); + const forceState = component.state.code; + // 修改注册码后 + assert.equal(component.state.code, testCode); + }); + }); + + describe('创建账号 组件', () => { + it('signupButton 组件存在', () => { + const signupButton = React.findDOMNode(component.refs.signupButton); + assert.equal(signupButton.textContent, '创建账号'); + }); + + describe('_handleRegister', () => { + // 初始化spy + const component = renderIntoDocument(); + + // spyShowMessage.withArgs('请输入正确的手机号码'); + it('手机号 验证', () => { + // 错误手机号码 + component.state.phone = '12345678'; + let forceState = component.state.phone; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs('请输入正确的手机号码').calledOnce, true); + + // 正确手机号 + component.state.phone = '13552987637'; + forceState = component.state.phone; + // 运行测试 + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs('请输入正确的手机号码').calledOnce, true); + + }); + + it('密码不为空 验证', () => { + // spy参数 + const spyArg = '请输入密码'; + // 空密码 + component.state.password1 = ''; + let forceState = component.state.password1; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledOnce, true); + + // 有内容的密码 + component.state.password1 = 'asdfwfd'; + forceState = component.state.password1; + // 运行测试 + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledOnce, true); + }); + + + it('密码长度应在6-18之间', () => { + const spyArg = '密码长度应在6-18之间'; + + // 1位密码 + component.state.password1 = '1'; + let forceState = component.state.password1; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledOnce, true); + + // 4位密码 + component.state.password1 = '1234'; + forceState = component.state.password1; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledTwice, true); + + // 8位密码 + component.state.password1 = '12345678'; + forceState = component.state.password1; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledTwice, true); + + // 19位密码 + component.state.password1 = '1234567890123456789'; + forceState = component.state.password1; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledThrice, true); + }); + + it('验证码不为空', () => { + const spyArg = '请输入验证码'; + // 设置符合的密码,让验证码可以继续测试 + component.state.password1 = '12345678'; + // 空验证码 + component.state.code = ''; + let forceState = component.state.code; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledOnce, true); + + // 有效验证码 + component.state.code = '1234'; + forceState = component.state.code; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledOnce, true); + }); + + it('验证码必须4位数', ()=> { + const spyArg = '请输入4位数字验证码'; + // 设置符合的密码,让验证码可以继续测试 + component.state.password1 = '12345678'; + // 2位无效验证码 + component.state.code = '12'; + let forceState = component.state.code; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledOnce, true); + + // 有效验证码 + component.state.code = '7890'; + forceState = component.state.code; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledOnce, true); + + // 8位无效验证码 + component.state.code = '12345678'; + forceState = component.state.code; + component._handleRegister(); + + assert.equal(spyShowMessage.withArgs(spyArg).calledTwice, true); + }); + }); + }); +}); diff --git a/tests/refluxTestHelpers.js b/tests/refluxTestHelpers.js new file mode 100644 index 00000000..c5c212d8 --- /dev/null +++ b/tests/refluxTestHelpers.js @@ -0,0 +1,29 @@ +import { expect } from 'chai'; + +exports.storeIsDefined = (store) => { + expect(store).to.exist; +}; + +exports.storeHasData = (store, key = "NA") => { + if (key == "NA"){ + describe('has data object', () => { + it('has data object', ()=> { + expect(store.data).to.exist; + }); + }); + }else{ + describe('has data element', () => { + it(`has data element << ${key} >>`, ()=> { + expect(store.data[key]).to.exist; + }); + }) + } +}; + +exports.storeHasMethod = function (store, method) { + describe('store has method', () => { + it(`has method methold << ${method} >>`, ()=> { + expect(store[method]).to.exist; + }); + }) +}; \ No newline at end of file diff --git a/tests/stores/AlbumsStore_test.js b/tests/stores/AlbumsStore_test.js new file mode 100644 index 00000000..ed3ab859 --- /dev/null +++ b/tests/stores/AlbumsStore_test.js @@ -0,0 +1,185 @@ +import Reflux from 'reflux'; +import { + storeIsDefined, storeHasData, storeHasMethod +} +from '../refluxTestHelpers'; +import { + expect +} +from 'chai'; + +import AlbumsStore from '../../app/stores/AlbumsStore'; + +describe('Albums Store Test', () => { + const successfulRes = { + Success: true, + Result: [1, 2, 3] + }; + + const errorMsg = 'error message'; + + const failedRes = { + Success: false, + ErrorMsg: errorMsg + }; + + beforeEach(() => { + AlbumsStore.data.hintMessage = ''; + AlbumsStore.data.flag = ''; + }); + + it('has store', () => { + storeIsDefined(AlbumsStore); + storeHasData(AlbumsStore); + }); + + it('has methods', () => { + const methods = [ + 'onFailed', + 'onAddSuccess', + 'onGetSuccess', + 'onUpdateSuccess', + 'onDeleteSuccess', + 'onSearchSuccess', + 'onGetMyAlbumsSuccess', + 'onGetCategoriesSuccess', + 'onSaleSuccess', + 'offSaleSuccess', + 'onRecommendListSuccess' + ]; + methods.forEach((method) => { + storeHasMethod(AlbumsStore, method); + }) + }); + + it('works on failed', () => { + AlbumsStore.onFailed(); + expect(AlbumsStore.data.hintMessage).to.equal('网络错误'); + expect(AlbumsStore.data.flag).to.equal('failed'); + }); + + it('works on add success', () => { + AlbumsStore.onAddSuccess(successfulRes); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.flag).to.equal('add'); + + AlbumsStore.onAddSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.flag).to.equal('add'); + }); + + it('works on get success', () => { + AlbumsStore.onGetSuccess(successfulRes); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.workData).to.equal(successfulRes); + expect(AlbumsStore.data.flag).to.equal('get'); + + AlbumsStore.onGetSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.workData).is.empty; + expect(AlbumsStore.data.flag).to.equal('get'); + }); + + it('works on update success', () => { + AlbumsStore.onUpdateSuccess(successfulRes); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.flag).to.equal('update'); + + AlbumsStore.onUpdateSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.flag).to.equal('update'); + }); + + it('works on delete success', () => { + AlbumsStore.onDeleteSuccess(successfulRes); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.flag).to.equal('delete'); + + AlbumsStore.onDeleteSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.flag).to.equal('delete'); + }); + + it('works on search success', () => { + // 有数据的时候 + let res = { + Success: true, + Count: 1, + PageIndex: 1, + PageCount: 1, + PageSize: 1, + Total: 1, + Result: [1, 2, 3] + }; + + AlbumsStore.onSearchSuccess(res); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.flag).to.equal('search'); + + storeHasData(AlbumsStore, 'count'); + storeHasData(AlbumsStore, 'pageCount'); + storeHasData(AlbumsStore, 'pageIndex'); + storeHasData(AlbumsStore, 'pageSize'); + storeHasData(AlbumsStore, 'total'); + storeHasData(AlbumsStore, 'workList'); + + // 没有数据的时候 + AlbumsStore.onSearchSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.workList).is.empty; + expect(AlbumsStore.data.flag).to.equal('search'); + }); + + it('works on get my albums success', () => { + AlbumsStore.onGetMyAlbumsSuccess(successfulRes); + expect(AlbumsStore.data.workList).to.equal(successfulRes.Result); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.flag).to.equal('getMyAlbums'); + + AlbumsStore.onGetMyAlbumsSuccess(failedRes); + expect(AlbumsStore.data.workList).is.empty; + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.flag).to.equal('getMyAlbums'); + }); + + it('works on get catagoies success', () => { + AlbumsStore.onGetCategoriesSuccess(successfulRes); + expect(AlbumsStore.data.categories).to.equal(successfulRes.Result); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.flag).to.equal('getCategories'); + + AlbumsStore.onGetCategoriesSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.flag).to.equal('getCategories'); + }); + + it('works on sale success', () => { + AlbumsStore.onSaleSuccess(successfulRes); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.flag).to.equal('onSale'); + + AlbumsStore.onSaleSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.flag).to.equal('onSale'); + }); + + it('works off sale success', () => { + AlbumsStore.offSaleSuccess(successfulRes); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.flag).to.equal('offSale'); + + AlbumsStore.offSaleSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.flag).to.equal('offSale'); + }); + + it('works on recommend list success', () => { + AlbumsStore.onRecommendListSuccess(successfulRes); + expect(AlbumsStore.data.hintMessage).is.empty; + expect(AlbumsStore.data.workList).to.equal(successfulRes.Result); + + AlbumsStore.onRecommendListSuccess(failedRes); + expect(AlbumsStore.data.hintMessage).to.equal(errorMsg); + expect(AlbumsStore.data.flag).to.equal('recommendList'); + }); +}); \ No newline at end of file diff --git a/tests/testHelper_test.js b/tests/testHelper_test.js new file mode 100644 index 00000000..55c96fbd --- /dev/null +++ b/tests/testHelper_test.js @@ -0,0 +1,28 @@ +import { + storeIsDefined, storeHasMethod, storeHasData +} +from './refluxTestHelpers'; + +describe('test helpers', () => { + it('is a defined store', ()=> { + let store = {}; + storeIsDefined(store); + }); + + it('has a defined method', ()=> { + let store = { + demoMethod: () => {} + }; + storeHasMethod(store, 'demoMethod'); + }); + + it('has a data', ()=> { + let store = { + data: { + demo: 1, + } + } + storeHasData(store); + storeHasData(store, 'demo'); + }); +}) \ No newline at end of file