diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/client/Makefile b/client/Makefile new file mode 100644 index 0000000..5a8a531 --- /dev/null +++ b/client/Makefile @@ -0,0 +1,9 @@ +.PHONY: dist build +install: + @npm install + +dev: install + @npm run dev + +build: + @npm run build diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..cb832b7 --- /dev/null +++ b/client/README.md @@ -0,0 +1,32 @@ +# element-starter + +> A starter kit for Element UI generated by vue-cli + +*If you are familiar with [cooking](https://github.com/elemefe/cooking), [here](https://github.com/ElementUI/element-cooking-starter) is a starter generated with it* + +## Environment + +`Node >= 6` + +## Start + + - Clone or download this repository + - Enter your local directory, and install dependencies: + +``` bash +npm install +``` + +## Develop + +``` bash +# serve with hot reload at localhost:8010 +npm run dev +``` + +## Build + +``` bash +# build for production with minification +npm run build +``` diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..b35ce9f --- /dev/null +++ b/client/package.json @@ -0,0 +1,46 @@ +{ + "name": "element-starter", + "description": "A Vue.js project", + "author": "yi.shyang@ele.me", + "private": true, + "scripts": { + "dev": "webpack-dev-server -d --inline --hot --env.dev", + "build": "rimraf dist && webpack -p --progress --hide-modules" + }, + "dependencies": { + "axios": "^0.15.3", + "element-ui": "^1.1.2", + "lodash": "^4.17.4", + "rupiah-format": "^1.0.0", + "slug": "^0.9.1", + "vue": "^2.1.8", + "vue-localstorage": "^0.1.3", + "vue-router": "^2.3.0" + }, + "engines": { + "node": ">=6" + }, + "devDependencies": { + "autoprefixer": "^6.6.0", + "babel-core": "^6.21.0", + "babel-eslint": "^7.1.1", + "babel-loader": "^6.2.10", + "babel-preset-es2015": "^6.13.2", + "css-loader": "^0.26.1", + "element-theme": "^0.7.1", + "eslint": "^3.12.2", + "eslint-config-enough": "^0.2.2", + "eslint-loader": "^1.6.1", + "file-loader": "^0.9.0", + "html-loader": "^0.4.4", + "html-webpack-plugin": "^2.24.1", + "postcss-loader": "^1.2.1", + "rimraf": "^2.5.4", + "style-loader": "^0.13.1", + "url-loader": "^0.5.7", + "vue-loader": "^10.0.0", + "vue-template-compiler": "^2.1.8", + "webpack": "^2.2.0-rc.4", + "webpack-dev-server": "beta" + } +} diff --git a/client/postcss.config.js b/client/postcss.config.js new file mode 100644 index 0000000..1b602ce --- /dev/null +++ b/client/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + require('autoprefixer')() + ] +} diff --git a/client/src/App.vue b/client/src/App.vue new file mode 100644 index 0000000..a92de63 --- /dev/null +++ b/client/src/App.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/client/src/assets/logo.png b/client/src/assets/logo.png new file mode 100644 index 0000000..f3d2503 Binary files /dev/null and b/client/src/assets/logo.png differ diff --git a/client/src/components/Home.vue b/client/src/components/Home.vue new file mode 100644 index 0000000..d138b90 --- /dev/null +++ b/client/src/components/Home.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/client/src/components/Shop.vue b/client/src/components/Shop.vue new file mode 100644 index 0000000..58dd35a --- /dev/null +++ b/client/src/components/Shop.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/client/src/components/item/Item.vue b/client/src/components/item/Item.vue new file mode 100644 index 0000000..d138b90 --- /dev/null +++ b/client/src/components/item/Item.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/client/src/components/item/ItemAll.vue b/client/src/components/item/ItemAll.vue new file mode 100644 index 0000000..315533a --- /dev/null +++ b/client/src/components/item/ItemAll.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/client/src/components/item/ItemDetail.vue b/client/src/components/item/ItemDetail.vue new file mode 100644 index 0000000..b4856ea --- /dev/null +++ b/client/src/components/item/ItemDetail.vue @@ -0,0 +1,22 @@ + + diff --git a/client/src/components/item/ItemEdit.vue b/client/src/components/item/ItemEdit.vue new file mode 100644 index 0000000..ab8a852 --- /dev/null +++ b/client/src/components/item/ItemEdit.vue @@ -0,0 +1,76 @@ + + + diff --git a/client/src/components/item/ItemNew.vue b/client/src/components/item/ItemNew.vue new file mode 100644 index 0000000..e57eeee --- /dev/null +++ b/client/src/components/item/ItemNew.vue @@ -0,0 +1,66 @@ + + + diff --git a/client/src/components/post/Post.vue b/client/src/components/post/Post.vue new file mode 100644 index 0000000..d138b90 --- /dev/null +++ b/client/src/components/post/Post.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/client/src/components/post/PostAll.vue b/client/src/components/post/PostAll.vue new file mode 100644 index 0000000..a9881ec --- /dev/null +++ b/client/src/components/post/PostAll.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/client/src/components/post/PostDetail.vue b/client/src/components/post/PostDetail.vue new file mode 100644 index 0000000..b4856ea --- /dev/null +++ b/client/src/components/post/PostDetail.vue @@ -0,0 +1,22 @@ + + diff --git a/client/src/components/post/PostEdit.vue b/client/src/components/post/PostEdit.vue new file mode 100644 index 0000000..ce3cf58 --- /dev/null +++ b/client/src/components/post/PostEdit.vue @@ -0,0 +1,75 @@ + + + diff --git a/client/src/components/post/PostNew.vue b/client/src/components/post/PostNew.vue new file mode 100644 index 0000000..cc3f616 --- /dev/null +++ b/client/src/components/post/PostNew.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/client/src/components/user/User.vue b/client/src/components/user/User.vue new file mode 100644 index 0000000..4729d6b --- /dev/null +++ b/client/src/components/user/User.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/client/src/components/user/UserDetail.vue b/client/src/components/user/UserDetail.vue new file mode 100644 index 0000000..eab90d2 --- /dev/null +++ b/client/src/components/user/UserDetail.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/client/src/index.html b/client/src/index.html new file mode 100644 index 0000000..21b90e8 --- /dev/null +++ b/client/src/index.html @@ -0,0 +1,18 @@ + + + + + + Diky Arga Vue Blog + + + + +
+ + + diff --git a/client/src/main.js b/client/src/main.js new file mode 100644 index 0000000..7aa5ecf --- /dev/null +++ b/client/src/main.js @@ -0,0 +1,23 @@ +import Vue from 'vue' +import VueRouter from 'vue-router' +import ElementUI from 'element-ui' +import 'element-ui/lib/theme-default/index.css' +import VueLocalStorage from 'vue-localstorage' +import App from './App.vue' + + +import { routes } from './routes' + +Vue.use(VueRouter) +Vue.use(ElementUI) +Vue.use(VueLocalStorage) +const router = new VueRouter({ + routes, + mode: 'history' +}) + +new Vue({ + el: '#app', + router, + render: h => h(App) +}) diff --git a/client/src/routes.js b/client/src/routes.js new file mode 100644 index 0000000..e894d89 --- /dev/null +++ b/client/src/routes.js @@ -0,0 +1,36 @@ +import Home from './components/Home.vue' +import Shop from './components/Shop.vue' +import User from './components/user/User.vue' + +import Item from './components/item/Item.vue' +import ItemAll from './components/item/ItemAll.vue' +import ItemDetail from './components/item/ItemDetail.vue' +import ItemNew from './components/item/ItemNew.vue' +import ItemEdit from './components/item/ItemEdit.vue' + +import Post from './components/post/Post.vue' +import PostAll from './components/post/PostAll.vue' +import PostDetail from './components/post/PostDetail.vue' +import PostNew from './components/post/PostNew.vue' +import PostEdit from './components/post/PostEdit.vue' + +export const routes = [ + { path : '', component: Home, children: [ + {path: '/shop', component: Shop} + ]}, + { path : '/users', component: User}, + { path : '/items', component:Item, children: [ + {path: '', component: ItemAll}, + {path: 'new', component: ItemNew}, + {path: ':id', component: ItemDetail}, + {path: ':id/edit', component: ItemEdit} + ]}, + { + path: '/posts', component: Post, children: [ + {path: '', component: PostAll}, + {path: 'new', component: PostNew}, + {path: ':id', component: PostDetail}, + {path: ':id/edit', component: PostEdit} + ] + } +] diff --git a/client/src/vendor.js b/client/src/vendor.js new file mode 100644 index 0000000..986e5d0 --- /dev/null +++ b/client/src/vendor.js @@ -0,0 +1,2 @@ +import Vue from 'vue' +import ElementUI from 'element-ui' \ No newline at end of file diff --git a/client/webpack.config.js b/client/webpack.config.js new file mode 100644 index 0000000..b617dee --- /dev/null +++ b/client/webpack.config.js @@ -0,0 +1,95 @@ +const { + resolve +} = require('path') +const webpack = require('webpack') +const HtmlWebpackPlugin = require('html-webpack-plugin') +const url = require('url') +const publicPath = '' + +module.exports = (options = {}) => ({ + entry: { + vendor: './src/vendor', + index: './src/main.js' + }, + output: { + path: resolve(__dirname, 'dist'), + filename: options.dev ? '[name].js' : '[name].js?[chunkhash]', + chunkFilename: '[id].js?[chunkhash]', + publicPath: options.dev ? '/assets/' : publicPath + }, + module: { + rules: [{ + test: /\.vue$/, + use: ['vue-loader'] + }, + { + test: /\.js$/, + use: ['babel-loader'], + exclude: /node_modules/ + }, + { + test: /\.html$/, + use: [{ + loader: 'html-loader', + options: { + root: resolve(__dirname, 'src'), + attrs: ['img:src', 'link:href'] + } + }] + }, + { + test: /\.css$/, + use: ['style-loader', 'css-loader', 'postcss-loader'] + }, + { + test: /favicon\.png$/, + use: [{ + loader: 'file-loader', + options: { + name: '[name].[ext]?[hash]' + } + }] + }, + { + test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/, + exclude: /favicon\.png$/, + use: [{ + loader: 'url-loader', + options: { + limit: 10000 + } + }] + } + ] + }, + plugins: [ + new webpack.optimize.CommonsChunkPlugin({ + names: ['vendor', 'manifest'] + }), + new HtmlWebpackPlugin({ + template: 'src/index.html' + }) + ], + resolve: { + alias: { + '~': resolve(__dirname, 'src') + } + }, + devServer: { + host: '127.0.0.1', + port: 8010, + proxy: { + '/api/': { + target: 'http://127.0.0.1:8080', + changeOrigin: true, + pathRewrite: { + '^/api': '' + } + } + }, + historyApiFallback: { + index: url.parse(options.dev ? '/assets/' : publicPath).pathname + } + }, + devtool: options.dev ? '#eval-source-map' : '#source-map' +}) \ No newline at end of file diff --git a/README.md b/server/README.md similarity index 100% rename from README.md rename to server/README.md diff --git a/server/app.js b/server/app.js new file mode 100644 index 0000000..9cc384d --- /dev/null +++ b/server/app.js @@ -0,0 +1,49 @@ +var express = require('express'); +var cors = require('cors') +var path = require('path'); +var favicon = require('serve-favicon'); +var logger = require('morgan'); +var cookieParser = require('cookie-parser'); +var bodyParser = require('body-parser'); + +var index = require('./routes/index'); +var users = require('./routes/users'); +var postsApi = require('./routes/apis/posts'); + +var app = express(); +app.use(cors()) +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'jade'); + +// uncomment after placing your favicon in /public +//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); +app.use(logger('dev')); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: false })); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'public'))); + +app.use('/', index); +app.use('/users', users); +app.use('/api/posts', postsApi); + +// catch 404 and forward to error handler +app.use(function(req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); + +module.exports = app; diff --git a/server/bin/www b/server/bin/www new file mode 100755 index 0000000..aa1db4f --- /dev/null +++ b/server/bin/www @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var app = require('../app'); +var debug = require('debug')('blog-tdd:server'); +var http = require('http'); + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/server/config/config.json b/server/config/config.json new file mode 100644 index 0000000..8185ec0 --- /dev/null +++ b/server/config/config.json @@ -0,0 +1,23 @@ +{ + "development": { + "username": "dikyarga", + "password": "dikyarga", + "database": "blog", + "host": "127.0.0.1", + "dialect": "postgres" + }, + "test": { + "username": "root", + "password": null, + "database": "database_test", + "host": "127.0.0.1", + "dialect": "mysql" + }, + "production": { + "username": "root", + "password": null, + "database": "database_production", + "host": "127.0.0.1", + "dialect": "mysql" + } +} diff --git a/server/controllers/postController.js b/server/controllers/postController.js new file mode 100644 index 0000000..441fed6 --- /dev/null +++ b/server/controllers/postController.js @@ -0,0 +1,61 @@ +let db = require('../models') + +let slug = require('slug') + +module.exports = { + index: function(req, res, next){ + db.Post.findAll().then(function(posts){ + res.json(posts) + }) + }, + create: function(req, res, next){ + let published = req.body.published == 'true' || true + db.Post.create({ + title: req.body.title, + body: req.body.body, + slug: slug(req.body.title, {lower: true}), + published: published + }).then(() => { + res.json({ + status: true, + msg: 'Post saved' + }) + }) + }, + show: function(req, res, next){ + db.Post.findById(req.params.id).then((post) => { + res.json(post) + }) + }, + update: function(req, res, next){ + let published = req.body.published == 'true' || true + + db.Post.update({ + title: req.body.title, + body: req.body.body, + slug: slug(req.body.title, {lower: true}), + published: published + }, { + where: { + id: req.params.id + } + }).then(() => { + res.json({ + status: true, + msg: 'Post updated' + }) + }) + }, + destroy: function(req, res, next){ + db.Post.destroy({ + where: { + id: req.params.id + } + }).then(() => { + res.json({ + status: true, + msg: 'Post destroyed' + }) + }) + } +} diff --git a/server/migrations/20170313090315-create-post.js b/server/migrations/20170313090315-create-post.js new file mode 100644 index 0000000..3475c26 --- /dev/null +++ b/server/migrations/20170313090315-create-post.js @@ -0,0 +1,36 @@ +'use strict'; +module.exports = { + up: function(queryInterface, Sequelize) { + return queryInterface.createTable('Posts', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + title: { + type: Sequelize.STRING + }, + body: { + type: Sequelize.STRING + }, + slug: { + type: Sequelize.STRING + }, + published: { + type: Sequelize.BOOLEAN + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + down: function(queryInterface, Sequelize) { + return queryInterface.dropTable('Posts'); + } +}; \ No newline at end of file diff --git a/server/models/index.js b/server/models/index.js new file mode 100644 index 0000000..7540dba --- /dev/null +++ b/server/models/index.js @@ -0,0 +1,36 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var Sequelize = require('sequelize'); +var basename = path.basename(module.filename); +var env = process.env.NODE_ENV || 'development'; +var config = require(__dirname + '/../config/config.json')[env]; +var db = {}; + +if (config.use_env_variable) { + var sequelize = new Sequelize(process.env[config.use_env_variable]); +} else { + var sequelize = new Sequelize(config.database, config.username, config.password, config); +} + +fs + .readdirSync(__dirname) + .filter(function(file) { + return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); + }) + .forEach(function(file) { + var model = sequelize['import'](path.join(__dirname, file)); + db[model.name] = model; + }); + +Object.keys(db).forEach(function(modelName) { + if (db[modelName].associate) { + db[modelName].associate(db); + } +}); + +db.sequelize = sequelize; +db.Sequelize = Sequelize; + +module.exports = db; diff --git a/server/models/post.js b/server/models/post.js new file mode 100644 index 0000000..d884408 --- /dev/null +++ b/server/models/post.js @@ -0,0 +1,16 @@ +'use strict'; +module.exports = function(sequelize, DataTypes) { + var Post = sequelize.define('Post', { + title: DataTypes.STRING, + body: DataTypes.STRING, + slug: DataTypes.STRING, + published: DataTypes.BOOLEAN + }, { + classMethods: { + associate: function(models) { + // associations can be defined here + } + } + }); + return Post; +}; \ No newline at end of file diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..81d476f --- /dev/null +++ b/server/package.json @@ -0,0 +1,22 @@ +{ + "name": "blog-tdd", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www", + "dev": "nodemon ./bin/www" + }, + "dependencies": { + "body-parser": "~1.16.0", + "cookie-parser": "~1.4.3", + "cors": "^2.8.1", + "debug": "~2.6.0", + "express": "~4.14.1", + "jade": "~1.11.0", + "morgan": "~1.7.0", + "pg": "^6.1.4", + "sequelize": "^3.30.2", + "serve-favicon": "~2.3.2", + "slug": "^0.9.1" + } +} diff --git a/server/public/stylesheets/style.css b/server/public/stylesheets/style.css new file mode 100644 index 0000000..9453385 --- /dev/null +++ b/server/public/stylesheets/style.css @@ -0,0 +1,8 @@ +body { + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; +} + +a { + color: #00B7FF; +} diff --git a/server/routes/apis/posts.js b/server/routes/apis/posts.js new file mode 100644 index 0000000..992e2b6 --- /dev/null +++ b/server/routes/apis/posts.js @@ -0,0 +1,17 @@ +var express = require('express'); +var router = express.Router(); + +var postController = require('../../controllers/postController') + +/* GET users listing. */ +router.get('/', postController.index); + +router.get('/:id', postController.show); + +router.post('/', postController.create) + +router.put('/:id', postController.update); + +router.delete('/:id', postController.destroy); + +module.exports = router; diff --git a/server/routes/index.js b/server/routes/index.js new file mode 100644 index 0000000..418f4f5 --- /dev/null +++ b/server/routes/index.js @@ -0,0 +1,13 @@ +var express = require('express'); +var router = express.Router(); + +/* GET home page. */ +router.get('/', function(req, res, next) { + res.render('index', { title: 'Express' }); +}); + +router.get('/ping', function(req, res, next){ + res.json({msg:'pong'}) +}) + +module.exports = router; diff --git a/server/routes/posts.js b/server/routes/posts.js new file mode 100644 index 0000000..c55a9c3 --- /dev/null +++ b/server/routes/posts.js @@ -0,0 +1,15 @@ +var express = require('express'); +var router = express.Router(); + +var postController = require('../controllers/postController') + +/* GET users listing. */ +router.get('/', function(req, res, next) { + res.send('respond with a resource'); +}); + +router.post('/', function(req, res, next){ + +}) + +module.exports = router; diff --git a/server/routes/users.js b/server/routes/users.js new file mode 100644 index 0000000..623e430 --- /dev/null +++ b/server/routes/users.js @@ -0,0 +1,9 @@ +var express = require('express'); +var router = express.Router(); + +/* GET users listing. */ +router.get('/', function(req, res, next) { + res.send('respond with a resource'); +}); + +module.exports = router; diff --git a/server/test/blog-test.js b/server/test/blog-test.js new file mode 100644 index 0000000..dfd65d4 --- /dev/null +++ b/server/test/blog-test.js @@ -0,0 +1,117 @@ +var chai = require('chai') +var chaiHttp = require('chai-http') + +var should = chai.should() + +chai.use(chaiHttp) + +let serverHost = 'http://localhost:3000' + + +describe('Server is running test', () => { + it('Should be return "pong" when try to access /ping', (done) => { + chai.request(serverHost).get('/ping').end((err, res) => { + if (err) { + done(err) + } else { + // res.body.should.be.json; + res.body.msg.should.equal('pong'); + done() + } + }); + }) +}) + +describe('CRUD Post test', () => { + describe('Read all data', () => { + it('Should be return array of post when try to access "/api.posts/"', (done) => { + chai.request(serverHost).get('/api/posts').end((err, res) => { + if (err) { + done(err) + } else { + res.should.have.status(200); + res.should.be.json; + res.body.should.be.a('array'); + res.body[0].should.have.property('title'); + res.body[0].should.have.property('body'); + res.body[0].should.have.property('slug'); + done() + } + }); + }) + }) + describe('Create a post', () => { + it('Should be return success message when try to create post "/api/posts"', (done) => { + chai.request(serverHost) + .post('/api/posts') + .send({ + title: 'Test from Chai', + body: 'Ini body test bukan bodyParser', + published: true + }) + .end((err, res) => { + if (err) { + done(err) + } else { + res.should.have.status(200); + res.should.be.json; + res.body.status.should.equal(true) + done() + } + }); + }) + }) + describe('Retrive single post', () => { + it('Should be return a post data when try to get single post "/api/posts/1"', (done) => { + chai.request(serverHost).get('/api/posts/1').end((err, res) => { + if (err) { + done(err) + } else { + res.should.have.status(200); + res.should.be.json; + res.body.should.be.an('object') + res.body.should.have.property('title'); + res.body.should.have.property('body'); + res.body.should.have.property('slug'); + done() + } + }); + }) + }) + describe('Update a post', () => { + it('Should be return success message when try to Update blogpost "/api/posts/1"', (done) => { + chai.request(serverHost) + .put('/api/posts/1') + .send({ + title: 'Test from Chai Updated', + body: 'Ini body test bukan bodyParser Updated', + published: true + }) + .end((err, res) => { + if (err) { + done(err) + } else { + res.should.have.status(200); + res.should.be.json; + res.body.status.should.equal(true) + done() + } + }); + }) + }) + describe('Detele single post', () => { + it('Should be return success message when try to delete single blogpost "/api/posts/2"', (done) => { + chai.request(serverHost).delete('/api/posts/2').end((err, res) => { + if (err) { + done(err) + } else { + res.should.have.status(200); + res.should.be.json; + res.body.should.be.an('object') + res.body.status.should.equal(true) + done() + } + }); + }) + }) +}) diff --git a/server/views/error.jade b/server/views/error.jade new file mode 100644 index 0000000..51ec12c --- /dev/null +++ b/server/views/error.jade @@ -0,0 +1,6 @@ +extends layout + +block content + h1= message + h2= error.status + pre #{error.stack} diff --git a/server/views/index.jade b/server/views/index.jade new file mode 100644 index 0000000..3d63b9a --- /dev/null +++ b/server/views/index.jade @@ -0,0 +1,5 @@ +extends layout + +block content + h1= title + p Welcome to #{title} diff --git a/server/views/layout.jade b/server/views/layout.jade new file mode 100644 index 0000000..15af079 --- /dev/null +++ b/server/views/layout.jade @@ -0,0 +1,7 @@ +doctype html +html + head + title= title + link(rel='stylesheet', href='/stylesheets/style.css') + body + block content diff --git a/untitled.webm b/untitled.webm new file mode 100644 index 0000000..16e6645 Binary files /dev/null and b/untitled.webm differ