原文链接:http://www.jianshu.com/p/2a9367afe9e7
1510997059(1).jpg
1. 将原项目迁移进入KOA2,并顺利通过index/index路由进行访问
1.1 新建项目,配置项目结构所需的一系列的文件,使 index/index 可以打开
将原项目 Praisethumb 拖拽到 sublime 编辑器中,新建一个koatest 文件夹
打开小黑窗进入koatest 文件夹中
cd Desktop
cd koatest
初始化项目
npm init
找寻 koa2 包教程,www.npmjs.com-> 搜索框输入koa2
参考链接:https://www.npmjs.com/package/koa2
开始配置koa2 -> 在小黑窗中安装koa2包
npm install koa@next
在koatest文件夹中新建文件 app.js, copy 如下代码
const Koa = require('koa');
const app = new Koa();
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
由于使用的是 ES6 所以将 require 引用 改为 import name from 'name'
import Koa from 'koa';
const app = new Koa();
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
此时在小黑窗中输入 node app.js 会报如下的错误,原因是为将ES6 代码编译为 可解析的 ES5
4Y4V)NM0S7MLXBOBDM9NH2G.png
开始安装编译依赖包 babel ,在此阐述一下 -dev 的问题,安装包时加 -dev 说明其只在开发环境下使用而上线时有命令可以直接将其去掉, babel 便是此类的安装包
npm install babel-preset-es2015 --save-dev
http://www.ruanyifeng.com/blog/2016/01/babel.html?20170213113809阮一峰先生的 babel 教程
在项目中新建 .babelrc ,babel 的配置文件 输入如下代码
{
"presets":[
"es2015",
"stage-0"
],
"plugins":[]
}
安装babel 编译所需的其他包,stage-0 是 ES7 的一个阶段,是为了使 babel 可以识别后面写的 async 和 await
cnpm install babel-preset-stage-0 --save-dev
http://www.jianshu.com/p/c84d52828e45async 和 await 详解
编译 app.js 文件,并启动服务
babel app.js -o app_o.js
node app_o.js
启动时报了如下错误,猜测是由于哪个包装的时候未装完整便退出了,所以将文件夹中的 node_modules 文件删除 再重新安装一遍项目所需的包 cnpm install 再次启动 node app_o.js 时便成功了
1511065654(1).jpg
启动成功后,在浏览器中输入http://localhost:3000/显示为 Hello Koa证明一切都没问题了
14.此时需要配置路由 为 /index/index ,使用 koa-simple-router 包
https://www.npmjs.com/package/koa-simple-router包的网址
npm install koa-simple-router --save
在 app.js 文件的代码改为如下所示的
import Koa from 'koa';
import router from 'koa-simple-router';
const app = new Koa();
app.use(router(_ => {
_.get('/', (ctx, next) => {
ctx.body = 'hello'
})
_.post('/name/:id', (ctx, next) => {
// ...
})
})
app.listen(3000);
为了使项目变得更加的分化明了
新建一个 midddleware 文件夹放项目的容错文件
新建一个 config 文件夹放项目的配置文件
新建一个 controller 文件夹放项目的路由配置文件
新建一个向后端请求数据的文件夹 models
新建一个放 html 页面的文件夹 views
再加一个放静态文件 .css .js 的文件夹 public
文件创建解构如下
public -> css -> index.css
public -> scripts -> index.js
controller -> initController.js
controller -> indexController.js
编辑 initController.js 文件,将 app.js 文件中的路由配置方法代码拿到 该文件中略加修改,最后讲方法导出
import index from './indexController';//引入 indexController 文件导出的方法
const controllerInit = {
//配置初始化函数
init(app, router) {
app.use(router(_ => {
_.get('/index/index', index.index())
}))
}
}
//导出初始化方法,使其全局可用
export default controllerInit;
编辑 indexController.js 文件,并导出该方法给 initController.js 文件使用
const indexController ={
index(){
return async(ctx,next)=>{
ctx.body = await ctx.render('index.html',function(){
title:'大拇指点赞'
})
}
}
}
// 导出该方法给 initController.js 文件使用
export default indexController;
在 app.js 文件中引用 initController 并执行
import initController from './controller/initController';
initController.init(app,router);
由于在controller js 文件中都使用了 koa-swig 框架中的 rander 函数,而且需要这个框架在静态文件中引用文件,所以要引用 koa-swig
https://www.npmjs.com/package/koa-swig包的网址
npm install koa-swig --save
https://www.cnblogs.com/elementstorm/p/3142644.htmlswig 使用指南
在 swig 使用指南中找到 模板继承模块,在项目中的 views 文件夹中新建 layout.html 和 index.html 将如下代码 copy 进去
layout.html
{% block title %}My Site{% endblock %}
{% block head %}
{% endblock %}
{% block content %}{% endblock %}
index.html
{% extends 'layout.html' %}
{% block title %}My Page{% endblock %}
{% block head %}
{% parent %}
{% endblock %}
{% block content %}
This is just an awesome page.
{% endblock %}
以为用的是 koa2 所以用 swig 时还要引用 co 模块,该模块无需安装,在 app.js 文件中输入如下代码
import co from 'co';
app.context.render = co.wrap(render({
root: __dirname + 'views',
autoescape: true,
cache: 'memory', // disable, set to false
ext: 'html',
writeBody: false
}));
html 文件中相互引用路径时需要安装 koa-static 来配置
npm install koa-static --save
在 app.js 文件中输入如下代码
import serve from 'koa-static';
app.use(serve(__dirname + '/test/fixtures'));
在 config 文件夹中新建 config.js 文件
http://es6.ruanyifeng.com/?search=map&x=0&y=0#docs/set-mapES
6-Map 方法详述
安装 path
npm install path --save-dev
编辑 config.js 文件,将方法导出 app.js 会使用
import path from 'path';
const CONFIG = new Map();
CONFIG.set('port',3000);
CONFIG.set('staticDir',path.join(__dirname,'..','public'));
CONFIG.set('viewDir',path.join(__dirname,'..','views'));
export default CONFIG;
在 app.js 文件中引入 CONFIG 并修改配置路径
import CONFIG from './config/config';
initController.init(app,router);
app.context.render = co.wrap(render({
root: CONFIG.get('viewDir'),
autoescape: true,
cache: 'memory', // disable, set to false
ext: 'html',
writeBody: false
}));
app.use(serve(CONFIG.get('staticDir')));
app.listen(CONFIG.get('port'));
编译文件
babel app.js -o app_o.js //期间莫名其妙报了错,然后检查了下需要引用的包,看看 package.json 文件中是否存在没有的安装一遍,之后还是报错,便将 node_modules 文件夹删掉 在将所有的包重装了一遍 npm install 可以了
进入 config 和 controller 文件夹中,将里面的 .js 文件后缀名改为 .es,再在命令行中进行编译
cd config
babel config.es -o config.js
cd ..
cd controller
babel initController.es -o initController.js
babel indexController.es -o indexController.js
启动服务
cd..
node app_o.js
此时报了如下的错误,
1511073380(1).jpg
原因是在 indexController 中用到了 async 和 await 但是并没有编译的很好,因为 babel 默认是不会编译较高级的函数的,所以需要装两个包使其支持
cnpm install babel-register --save-dev
cnpm install babel-polyfill --save-dev
装好之后在 app.js 文件中引入
import babel_co from 'babel-core/register';
import babel_po from 'babel-pocyfill';
再编译一遍文件
babel app.js -o app_o.js
cd controller
babel indexcontroller
babel indexController.es -o indexController.js
运行服务 报错为如下图
image.png
在 app.js 文件中引入 CONFIG
import CONFIG from './config/config';
编译修改过的文件
babel app.js -o app_o.js
cd config
babel config.es -o config.js
切记每次修改了 .es 都需要在重新编译一遍
运行服务
node app_o.js
在浏览器打开页面http://localhost:3000/index/index展示如下图所示 便表示成功了接下来就是第二步将原项目迁移过来
1511076432(1).jpg
1.2 将之前所做的 项目 Praisethumb 中的文件配置到新项目中
1.将之前的 css 样式 放到 koatest 项目中的 index.css 文件中
{
margin: 0;
padding: 0;
}
body {
background-color: #b1c8ac;
padding: 50px;
position: relative;
height: 600px;
}
.a {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
background-color: #ffcaaa;
width: 226px;
height: 360px;
border-radius: 38px 0 0 38px;
border: 1px solid #95755e;
border-width: 1px 0 1px 1px;
}
.a:before {
content: " ";
display: block;
position: absolute;
width: 246px;
height: 240px;
border-top: 1px solid #95755e;
bottom: 0;
top: 0;
right: 0;
left: 0;
margin: auto auto auto -224px;
background-color: #ffcaaa;
}
.a:after {
content: " ";
display: block;
position: absolute;
width: 150px;
height: 90px;
border: 1px solid #95755e;
border-width: 1px 1px 0 0;
border-radius: 0 45px 45px 0;
bottom: 0;
top: 0;
right: 0;
left: 0;
margin: 0 auto auto 30px;
background-color: #ffcaaa;
transform: rotate(-65deg);
transform-origin: left top;
box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset, -80px 2px 10px 1px #ffcaaa inset, -100px 2px 20px 0px #efb38f inset;
transition: all .3s;
}
.b {
width: 180px;
height: 90px;
border: 1px solid #95755e;
position: absolute;
border-radius: 45px;
box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;
background-color: #ffcaaa;
z-index: -1;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto -90px -1px auto;
-webkit-box-reflect: above 178px;
box-reflect: above 178px;
}
.b:before {
content: " ";
display: block;
position: absolute;
width: 180px;
height: 90px;
border: 1px solid #95755e;
right: 0;
top: -91px;
border-radius: 45px;
border-width: 1px 1px 1px 0;
box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;
background-color: #ffcaaa;
}
.c {
width: 180px;
height: 90px;
border: 1px solid #95755e;
position: absolute;
border-radius: 45px;
box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;
background-color: #ffcaaa;
z-index: -1;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: 90px -90px -1px auto;
/-webkit-box-reflect: above 178px;
box-reflect: above 178px;
/
}
.c:before {
content: " ";
display: block;
position: absolute;
width: 180px;
height: 90px;
border: 1px solid #95755e;
right: 0;
top: -91px;
border-radius: 45px;
border-width: 1px 1px 1px 0;
box-shadow: -4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;
background-color: #ffcaaa;
}
/.b:after{content: " ";display: block;position: absolute;width: 180px;height:90px;border: 1px solid #95755e;right: 0;top:182px;border-radius: 45px;border-width: 1px 1px 1px 0;box-shadow:-4px -4px 22px 2px #ffcaaa inset, -4px 4px 30px 2px #ffcaaa inset, -25px 2px 10px 3px #fce0d4 inset;background-color: #ffcaaa;}/
.hide {
opacity: 0;
color: red;
font-size: 60px;
position: absolute;
right: 60px;
top: 150px;
}
.num {
animation: myani .6s ease;
-moz-animation: myani .6s ease;
-webkit-animation: myani .6s ease;
-o-animation: myani .6s ease;
}
@keyframes myani() {
form {
opacity: 0;
top: 150px;
}
to {
opacity: 1;
top: 50px;
}
}
@-moz-keyframes myani {
form {
opacity: 0;
top: 150px;
}
to {
opacity: 1;
top: 50px;
}
}
@-webkit-keyframes myani {
form {
opacity: 0;
top: 150px;
}
to {
opacity: 1;
top: 50px;
}
}
@-o-keyframes myani {
form {
opacity: 0;
top: 150px;
}
to {
opacity: 1;
top: 50px;
}
}
:root {
--green: #b1c8ac;
}
body {
background-color: var(--green);
}
将 html 内容也拿过来
index.html
{% extends 'layout.html' %}
{% block title %}My Page{% endblock %}
{% block head %}
{% parent %}
{% endblock %}
{% block content %}
+1
SystemJS.config({
//使用的 js 文件的文件夹路径
baseURL: '/scripts'
});
//使用的 js 文件名称
SystemJS.import('index-es.js').then(function(m) {
$.extend({
//将自己写的函数挂载到 jq 上称为一个插件
thumb:m.default.Thumb
})
//回调函数
callBack();
});
//定义回调函数
function callBack() {
//为页面元素添加方法
var f = new $.thumb(0,$('#thumb'));
f.clickAction();
}
{% endblock %}
拿 js
window.add = function (num) {
return num + 1;
}
将编译过的 点击小手子类继承父类的 js文件(index.es.js)复制到 项目的 scripts 文件夹下
index-es.js
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.proto= superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var PraiseButton = function () {
function PraiseButton(num, element) {
_classCallCheck(this, PraiseButton);
this.num = num;
this.element = element;
_createClass(PraiseButton, [{
key: 'clickAction',
value: function clickAction() {
var _this = this;
this.element.click(function () {
if (_this.num < 10) {
_this.element.css('-webkit-filter', 'grayscale(0)');
$('#animation').addClass('num');
_this.num = add(_this.num);
setTimeout(function () {
$('#animation').removeClass('num');
}, 1000);
} else {
_this.element.css('-webkit-filter', 'grayscale(1)');
_this.num = 0;
}
console.log(_this.num);
});
}
}]);
return PraiseButton;
}();
var Thumb = function (_PraiseButton) {
_inherits(Thumb, _PraiseButton);
function Thumb(num, element) {
_classCallCheck(this, Thumb);
return _possibleConstructorReturn(this, (Thumb.proto|| Object.getPrototypeOf(Thumb)).call(this, num, element));
}
return Thumb;
}(PraiseButton);
exports.default = { Thumb: Thumb
// let f = new Thumb(0,$('#thumb'));
// f.clickAction();
};
重启服务
node app_o.js
刷新http://localhost:3000/index/index页面,发现项目已经移植成功
2. 使用 PHP + MySQL 完成点赞借口,实现用户点击一次更新数据库点赞次数
在项目中新建一个 praise.php 文件
编辑文件
//用php的面向对象来写
/**
* 新建一个类
*/
class Conmysql
{
//定义所需的变量
//public关键字表示属性或方法是公开可见的
public $servername;
public $username;
public $password;
public $dbname;
}
?>
用 XAMPP 启动 Apache 和 MySQL
1511081397(1).jpg
在浏览器中打开http://localhost/phpmyadmin/页面
在左侧操作栏中点击【新建】
输入新数据库的名字 praise 点击【创建】
新建数据表 text 2
字段分别为 id 和 num
id 需要设置为主键
点击保存
具体设计如下图所示
image.png
在 text 数据表中手动添加一条数据
点击数据表【text】
点击 【SQL】
点击【INSERT】
将输入域的值修改为如下所示,点击【执行】
INSERT INTO `text`(`id`, `num`) VALUES (1,0)
在 php 文件中编辑
//用php的面向对象来写
/**
* 新建一个类
*/
class Conmysql
{
//定义所需的变量
//public关键字表示属性或方法是公开可见的
public $servername;
public $username;
public $password;
public $dbname;
public $con = null;
//添加构造方法
public function __construct($servername,$username,$password,$dbname){
$this->servername = $servername;
$this->username = $username;
$this->password = $password;
$this->dbname = $dbname;
}
//创建数据库链接方法
//参考网址:http://www.runoob.com/php/php-mysql-connect.html -> 实例 (PDO)
public function getConnection(){
//这里用的是 PDO 方法
try {
$dsn = "mysql:host=$this->servername;dbname=$this->dbname";
$this->con = new PDO($dsn, $this->username, $this->password);
//echo "连接成功";
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
//更新数据的方法
public function updateDate($sql){
//如果未连接的话就链接到数据库
if($this->con == null){
$this->getConnection();
}
//执行sql
//参考链接:http://www.runoob.com/php/php-mysql-insert.html -> 实例 (PDO)
$res=$this->con->exec($sql);
//关闭链接
$this->closeCon();
}
//关闭链接的方法
public function closeCon(){
$this->con = null;
}
}
/**
* 创建子类
*/
class realConn extends Conmysql
{
//继承父类的构造方法
public function __construct($servername,$username,$password,$dbname){
parent::__construct($servername,$username,$password,$dbname);
}
//真正执行 sql 的方法
public function updateRealDate(){
$sql = "UPDATE text SET num=num+1 WHERE id=1";
$this->updateDate($sql);
}
}
//将子类实例化执行方法
$praiseCon = new realConn('localhost','root','','praise');
$praiseCon->updateRealDate();
?>
将 praise.php 文件复制到 C:\xampp\htdocs 文件夹下,在浏览器中打开http://localhost/praise.php,再查看 text 数据表中会发现 num 的值为 1 ,刷 php 页面一次值便会加 1,至此点赞接口便完成了
3. 使用KOA2+ES6封装PHP点赞接口,并建立路由
1.在 koatest 项目文件夹的 models 文件夹中新建一个 indexmodel.js 文件
编辑 indexmodel.js 文件
import rpA from 'request-promise';
class indexModel {
constructor(ctx) {
this.ctx = ctx;
}
//为了实现数据库更新建立方法 传数据的接口
updateNum() {
//在这里 return 一个 promise 模块传入 initController.js 再在indexController.js 中调用需要用到一个模块 request-promise 参考网址:https://www.npmjs.com/package/request-promise
// 获取文件
const options = {
uri: 'http://localhost/praise.php',
method:'GET'
};
return new Promise((resolve,reject)=>{
rpA(options).then(function(result){
const info = JSON.parse(result);
if(info){
resolve({data:info.result});
}else{
reject({});
}
})
})
}
}
//将该方法导出, indexController.js 文件要用到
export default indexModel;
由于 updateNum 方法中需要用到 request-promise 模块 所以需要安装两个包
参考链接:https://www.npmjs.com/package/request-promise
npm install --save request
npm install --save request-promise
编辑 indexController.js 文件
indexController 对象中增加一个 提交数据的方法
//引入所需方法的文件
import indexModel from '../models/indexModel';
update(){
return async(ctx,next)=>{
const indexM = new indexModel(ctx);
ctx.body = await indexM.updateNum();
}
}
编辑 initController.js 文件
将 indexController 提交数据的方法注册到 一个新的路由上
_.get('/index/update', index.update());
babel 编译文件
将 indexmodel.js 重命名为 indexmodel.es
cd models
babel indexmodel.es -o indexmodel.js
cd ..
cd controller
babel indexController.es -o indexController.js
babel initController.es -o initController.js
此时运行服务会发现小手点击并没有与服务器关联起来,此时需要用 axios 模块来使其连接到 koa2 点赞接口上
4. 将用户点击事件通过 axios 链接到 KOA2 点赞接口
在 koatest 项目中的 scripts 文件夹中新建 index.es 文件,并将 praisethumb 项目中的 scripts -> index.js 文件代码复制过来
class PraiseButton{
constructor(num,element){
this.num = num;
this.element = element;
}
clickAction(){
this.element.click(()=>{
if(this.num < 10){
this.element.css('-webkit-filter','grayscale(0)');
$('#animation').addClass('num');
this.num = add(this.num);
setTimeout(function () {
$('#animation').removeClass('num');
},1000);
}else{
this.element.css('-webkit-filter','grayscale(1)');
this.num = 0;
}
console.log(this.num);
})
}
}
class Thumb extends PraiseButton{
constructor(num,element){
super(num,element)
}
}
export default{Thumb}
// let f = new Thumb(0,$('#thumb'));
// f.clickAction();
编辑 index.es 文件,这里是要用 axios 模块来使其连接到 koa2 点赞接口上
参考链接:https://www.npmjs.com/package/axios
这里有三种引用的方法:npm 装包,浏览器装包,cdn,这里我们用的是 cdn 方法,将如下代码 copy 至 index.html 文件中
将如下代码 copy 至 index.es -> this.element.click 点击事件中
axios.get('/index/update')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
编修改过的文件 index.es
cd public\scripts\
babel index.es -o index-es.js
运行服务
cd ../..
node app_o.js
点击时页面http://localhost:3000/index/index报如下图所示的错误
image.png
编辑 praise.php 文件中的 updateDate 方法
//更新数据的方法
public function updateDate($sql){
//如果未连接的话就链接到数据库
if($this->con == null){
$this->getConnection();
}
//向前台输出 json 格式的数据
header('content-type:application/json;charset=utf8');
//执行sql
//参考链接:http://www.runoob.com/php/php-mysql-insert.html -> 实例 (PDO)
$res=$this->con->exec($sql);
//执行之后 输出返回的数据
$arr = array('result'=>$res);
echo json_encode($arr);
//关闭链接
$this->closeCon();
}
运行服务,发现又报了 404 ,排查之后发现是 index.es 文件中的 uodate 写成了 uodete ,诶,修改后 编译 ,再运行点击一下小手,数据库里面的 num 的值 +1 证明成功了
需要注意的是 php返回的数据必须严格是 json 格式的 不然前台 .js 文件 (未编译:indexmodel.es 已编译 indexmodel.js)中用到的 JSON.parse(result); 会一直报错导致页面崩溃
cd public\scripts\
babel index.es -o index-es.js
cd../..
node app_o.js
5. 对用户连续点击事件进行稀释
稀释所用的方法就是 setTimeout
编辑 index.es 文件
let f = '';
class PraiseButton{
constructor(num,element){
this.num = num;
this.element = element;
}
clickAction(){
this.element.click(()=>{
//判断事件是否已经存在,如果存在便会将其清除掉,所以点击只会执行最后一次点击的那次事件
if(f){
clearTimeout(f);
}
f = setTimeout(()=>{
if(this.num < 10){
this.element.css('-webkit-filter','grayscale(0)');
$('#animation').addClass('num');
this.num = add(this.num);
setTimeout(function () {
$('#animation').removeClass('num');
},1000);
axios.get('/index/update')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}else{
this.element.css('-webkit-filter','grayscale(1)');
this.num = 0;
}
console.log(this.num);
},800)
})
}
}
class Thumb extends PraiseButton{
constructor(num,element){
super(num,element)
}
}
export default{Thumb}
// let f = new Thumb(0,$('#thumb'));
// f.clickAction();
编译文件
cd public\scripts\
babel index.es -o index-es.js
运行服务,稀释成功
node app_o.js
6. 完成点赞接口的自动化测试、点赞+1功能的自动化测试、真实页面点击自动化测试
1. 点赞+1功能的自动化测试
安装 karma
cnpm install karma --save-dev
安装断言库、核心、chrome 启动器
cnpm install karma-jasmine jasmine-core karma-chrome-launcher --save-dev
安装无界面浏览器、无界面浏览器启动器
cnpm install phantomjs --save-dev
cnpm install karma-phantomjs-launcher --save-dev
karma 初始化生成配置文件 karma.conf.js
karma init
jasmine
no
PhantomJS
yes
5.在项目中新建一个 test 文件夹,在该文件夹下做三大测试
将 praisethumb 项目文件夹的中 index.spce.js 文件复制到 test 文件夹下
编辑 karma.conf.js 文件
files: [
'test/index.spec.js',
'public/scripts/index.js'
],
singleRun: true,
启动测试,运行成功
karma start
2. 点赞接口的自动化测试
1.先安装 mocha
cnpm install mocha --save-dev
安装 supertest
cnpm install supertest --save-dev
在 test 文件夹下新建一个 server.js 文件
编辑 sever.js 文件,这里我们需要用到 supertest 模块
参考链接:https://www.npmjs.com/package/supertest
import requestsuper from 'supertest';
//这里引用的是 app_o.js 文件拿到 app,所以需要在 app.js 文件中将其导出,然后再将 app.js 文件编译为 app_o.js 文件
import app from '../app_o.js';
//先定义一个拿到端口的方法
function request(){
return requestsuper(app.listen());
}
describe('测试路由', function() {
it('点赞', function(done) {
request()
.get('/index/update')
.expect(200)
.end(function(err,res){
if(res.data==1)return done(err);
done();
})
});
});
修改 app.js 文件
export default app;
编译文件
babel app.js -o app_o.js
cd test\
babel server.js -o server-es.js
执行 server-es.js 文件
cd ..
mocha test\server-es.js
此时报如下图所示的错误
image.png
将 mocha 安装至全局
cnpm install mocha -g
执行测试
mocha test\server-es.js
执行成功
image.png
3. 真实页面点击自动化测试
1.安装 selenium-webdriver
参考链接:https://www.npmjs.com/package/selenium-webdriver
cnpm install selenium-webdriver
2.下面火狐浏览器所需的相应组件
参考链接:https://github.com/mozilla/geckodriver/releases/找到与当前设备匹配的一款点击下载 我的是 win64
将下载好的压缩包解压至 koatest 项目文件夹中,删除压缩包
再安装两个包
cnpm install selenium-standalone --save
cnpm install protractor --save
test 文件夹下新建 e2e.js 文件
编辑 e2e.js 文件
参考链接:https://www.npmjs.com/package/selenium-webdriver-> Usage
const {Builder, By, Key, until} = require('selenium-webdriver');
let driver = new Builder()
.forBrowser('firefox')
.build();
//设置地址
driver.get('http://localhost:3000/index/index');
driver.findElement(By.id('thumb')).click();
const _animation = driver.findElement(By.id('animation'))
driver.wait(_animation.isDisplayed(), 1000);
// driver.quit(); //为了看到效果将关闭浏览器的行为暂时注释掉
执行测试脚本 e2e.js 文件
node test\e2e.js
此时会发现浏览器打开页面后,页面并不能加载出来原因是这个 koatest 项目此时并没有处于运行状态,所以需要新建一个命令行窗口中执行项目运行操作
image.png
在新窗口中输入命令
cd Desktop
cd koatest
node app_o.js
此时再在之前的命令行窗口中执行测试脚本 e2e.js 文件
node test\e2e.js
整个实战到此结束。
作者:sunxiaochuan
链接:http://www.jianshu.com/p/2a9367afe9e7
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。