├── .gitignore ├── src └── app.js ├── package.json ├── README.md └── tests └── test.spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var server = express(); 3 | var bodyParser = require("body-parser"); 4 | 5 | var model = {}; 6 | 7 | server.use(bodyParser.json()); 8 | 9 | server.listen(3000); 10 | module.exports = { model, server }; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cp-m2-practice", 3 | "version": "1.0.0", 4 | "description": "just for practice", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha ./tests/*.spec.js -w" 8 | }, 9 | "author": "JavierBalonga", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.13.0", 13 | "express": "^4.12.4" 14 | }, 15 | "devDependencies": { 16 | "chai": "^4.1.1", 17 | "mocha": "^3.5.0", 18 | "supertest-session": "^3.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Checkpoint M3 2 | 3 | _We start the M3 checkpoint. As was customary in these last tasks, we started with a paragraph translated in Google Translate LOL. Successes!_ 4 | 5 | 6 | 7 | ## Comenzando 🔧 8 | 9 | 🚀`npm install` 10 | 🚀Podes correr `npm test` para ejecutar los test. 11 | 🚀Revisen la estructura del proyecto. 12 | 🚀Empiecen a trabajar en base a los test. Cambien el xit por un it cuando el test este listo para correr. 13 | Hagan `git commit` a medida que van pasando los test. 14 | 15 | 16 | 17 | 18 | ### Notas al pie 📋 19 | 20 | * Sacate todas las dudas y participá si podés. 📢 21 | * Cortá con un ☕ o un poco de aire si necesitás descansar 😊. 22 | 23 | 24 | 25 | --- 26 | hecho con ❤️. 27 | -------------------------------------------------------------------------------- /tests/test.spec.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const session = require('supertest-session'); 3 | const {model, server} = require('../src/app.js'); 4 | 5 | 6 | describe('model ', function(){ 7 | 8 | beforeEach(() => { 9 | if (model.reset) { 10 | model.reset(); 11 | } 12 | }); 13 | 14 | xit('must have a propertie `clients` as a object', function(){ 15 | expect(model).to.have.property('clients').and.to.be.an('object'); 16 | }) 17 | 18 | describe('must have a reset method for resetting the model ', function(){ 19 | xit('must be a function', function(){ 20 | expect(model.reset).to.be.a('function'); 21 | }) 22 | xit('must reset clients to {}', function(){ 23 | model.clients = {javier: 'https://github.com/JavierBalonga', comment: 'aca me podes heatear tranquilo ;)'} 24 | model.reset(); 25 | expect(model.clients).to.be.deep.equal({}); 26 | }) 27 | }) 28 | 29 | describe('must have an addAppointment method to add appointments to that client', function(){ 30 | xit('must be a function', function(){ 31 | expect(model.addAppointment).to.be.a('function'); 32 | }) 33 | xit('must add clients as a properties', function(){ 34 | model.addAppointment('javier', {date:'22/10/2020 16:00'}); 35 | expect(model.clients).to.have.property('javier') 36 | }) 37 | xit('must add clients as an array', function(){ 38 | model.addAppointment('javier', {date:'22/10/2020 16:00'}); 39 | expect(model.clients).to.have.property('javier'); 40 | expect(model.clients.javier instanceof Array).to.be.true; 41 | }) 42 | xit('must be adding multiple appointments in the order as they are added, and must be handling multiple clients', function(){ 43 | model.addAppointment('javier', {date:'22/10/2020 14:00'}); 44 | expect(model.clients.javier[0]).to.have.property('date').to.be.equal('22/10/2020 14:00'); 45 | model.addAppointment('javier', {date:'22/10/2020 16:00'}); 46 | expect(model.clients.javier[1]).to.have.property('date').to.be.equal('22/10/2020 16:00'); 47 | model.addAppointment('alejandro', {date:'22/10/2020 11:00'}); 48 | expect(model.clients.alejandro[0]).to.have.property('date').to.be.equal('22/10/2020 11:00'); 49 | model.addAppointment('alejandro', {date:'22/10/2020 12:00'}); 50 | expect(model.clients.alejandro[1]).to.have.property('date').to.be.equal('22/10/2020 12:00'); 51 | }) 52 | xit('the appointments must have a initial status, and to be `pending`', function(){ 53 | model.addAppointment('javier', {date:'22/10/2020 14:00'}); 54 | model.addAppointment('javier', {date:'22/10/2020 16:00'}); 55 | model.addAppointment('alejandro', {date:'22/10/2020 11:00'}); 56 | model.addAppointment('alejandro', {date:'22/10/2020 12:00'}); 57 | expect(model.clients.javier[0]).to.have.property('status').to.be.equal('pending'); 58 | expect(model.clients.javier[1]).to.have.property('status').to.be.equal('pending'); 59 | expect(model.clients.alejandro[0]).to.have.property('status').to.be.equal('pending'); 60 | expect(model.clients.alejandro[1]).to.have.property('status').to.be.equal('pending'); 61 | }) 62 | }) 63 | 64 | describe('Appointments must be able to change status using the attend, expire and cancel methods.', function(){ 65 | 66 | beforeEach(() => { 67 | if (model.addAppointment) { 68 | model.addAppointment('javier', {date:'22/10/2020 14:00'}); 69 | model.addAppointment('javier', {date:'22/10/2020 16:00'}); 70 | model.addAppointment('alejandro', {date:'22/10/2020 11:00'}); 71 | model.addAppointment('alejandro', {date:'22/10/2020 12:00'}); 72 | } 73 | }); 74 | 75 | xit('they must be functions', function(){ 76 | expect(model.attend).to.be.a('function'); 77 | expect(model.expire).to.be.a('function'); 78 | expect(model.cancel).to.be.a('function'); 79 | }) 80 | xit('`attend` must receive a name and a date, and change the status to `attended`', function(){ 81 | model.attend('javier', '22/10/2020 14:00'); 82 | model.attend('javier', '22/10/2020 16:00'); 83 | model.attend('alejandro', '22/10/2020 11:00'); 84 | model.attend('alejandro', '22/10/2020 12:00'); 85 | expect(model.clients.javier[0]).to.have.property('status').to.be.equal('attended'); 86 | expect(model.clients.javier[1]).to.have.property('status').to.be.equal('attended'); 87 | expect(model.clients.alejandro[0]).to.have.property('status').to.be.equal('attended'); 88 | expect(model.clients.alejandro[1]).to.have.property('status').to.be.equal('attended'); 89 | }) 90 | xit('`expire` must receive a name and a date, and change the status to `expired`', function(){ 91 | model.expire('javier', '22/10/2020 14:00'); 92 | model.expire('javier', '22/10/2020 16:00'); 93 | model.expire('alejandro', '22/10/2020 11:00'); 94 | model.expire('alejandro', '22/10/2020 12:00'); 95 | expect(model.clients.javier[0]).to.have.property('status').to.be.equal('expired'); 96 | expect(model.clients.javier[1]).to.have.property('status').to.be.equal('expired'); 97 | expect(model.clients.alejandro[0]).to.have.property('status').to.be.equal('expired'); 98 | expect(model.clients.alejandro[1]).to.have.property('status').to.be.equal('expired'); 99 | }) 100 | xit('`cancel` must receive a name and a date, and change the status to `cancelled`', function(){ 101 | model.cancel('javier', '22/10/2020 14:00'); 102 | model.cancel('javier', '22/10/2020 16:00'); 103 | model.cancel('alejandro', '22/10/2020 11:00'); 104 | model.cancel('alejandro', '22/10/2020 12:00'); 105 | expect(model.clients.javier[0]).to.have.property('status').to.be.equal('cancelled'); 106 | expect(model.clients.javier[1]).to.have.property('status').to.be.equal('cancelled'); 107 | expect(model.clients.alejandro[0]).to.have.property('status').to.be.equal('cancelled'); 108 | expect(model.clients.alejandro[1]).to.have.property('status').to.be.equal('cancelled'); 109 | }) 110 | xit('must be able to handle multiple appointments with multiple states', function(){ 111 | model.attend('javier', '22/10/2020 16:00'); 112 | model.expire('alejandro', '22/10/2020 11:00'); 113 | model.cancel('alejandro', '22/10/2020 12:00'); 114 | expect(model.clients.javier[0]).to.have.property('status').to.be.equal('pending'); 115 | expect(model.clients.javier[1]).to.have.property('status').to.be.equal('attended'); 116 | expect(model.clients.alejandro[0]).to.have.property('status').to.be.equal('expired'); 117 | expect(model.clients.alejandro[1]).to.have.property('status').to.be.equal('cancelled'); 118 | }) 119 | }) 120 | 121 | describe('must have erase metod for delete appointments', function(){ 122 | beforeEach(() => { 123 | if (model.addAppointment) { 124 | model.addAppointment('javier', {date:'22/10/2020 14:00'}); 125 | model.addAppointment('javier', {date:'22/10/2020 16:00'}); 126 | model.addAppointment('alejandro', {date:'22/10/2020 11:00'}); 127 | model.addAppointment('alejandro', {date:'22/10/2020 12:00'}); 128 | model.attend('javier', '22/10/2020 16:00'); 129 | model.cancel('alejandro', '22/10/2020 11:00'); 130 | model.cancel('alejandro', '22/10/2020 12:00'); 131 | } 132 | }); 133 | 134 | xit('must be a function', function(){ 135 | expect(model.erase).to.be.a('function'); 136 | }) 137 | xit('it must receive a name and if receive a date must erase the appointment with that date', function(){ 138 | model.erase('javier', '22/10/2020 14:00'); 139 | expect(model.clients.javier).to.be.deep.equal([ { date: '22/10/2020 16:00', status: 'attended' } ]); 140 | model.erase('javier', '22/10/2020 16:00'); 141 | expect(model.clients.javier).to.be.deep.equal([]); 142 | model.erase('alejandro', '22/10/2020 11:00'); 143 | expect(model.clients.alejandro).to.be.deep.equal([ { date: '22/10/2020 12:00', status: 'cancelled' } ]); 144 | model.erase('alejandro', '22/10/2020 12:00'); 145 | expect(model.clients.alejandro).to.be.deep.equal([]); 146 | }) 147 | xit('it must receive a name and if receive a status must erase all the appointments whith that status', function(){ 148 | model.erase('javier', 'attended'); 149 | expect(model.clients.javier).to.be.deep.equal([ { date: '22/10/2020 14:00', status: 'pending' } ]); 150 | model.erase('alejandro', 'cancelled'); 151 | expect(model.clients.alejandro).to.be.deep.equal([]); 152 | }) 153 | }) 154 | 155 | describe('must have a metod getAppointments, to view the appointments of a client', function(){ 156 | beforeEach(() => { 157 | if (model.addAppointment) { 158 | model.addAppointment('javier', {date:'22/10/2020 14:00'}); 159 | model.addAppointment('javier', {date:'22/10/2020 16:00'}); 160 | model.addAppointment('alejandro', {date:'22/10/2020 11:00'}); 161 | model.addAppointment('alejandro', {date:'22/10/2020 12:00'}); 162 | model.attend('javier', '22/10/2020 16:00'); 163 | model.expire('alejandro', '22/10/2020 11:00'); 164 | model.cancel('alejandro', '22/10/2020 12:00'); 165 | } 166 | }); 167 | 168 | xit('must be a function', function(){ 169 | expect(model.getAppointments).to.be.a('function'); 170 | }) 171 | xit('must return an a array with the appointments of the client', function(){ 172 | let appointments = model.getAppointments('javier'); 173 | expect(appointments).to.be.deep.equal( 174 | [{ date: '22/10/2020 14:00', status: 'pending' }, 175 | { date: '22/10/2020 16:00', status: 'attended' }] 176 | ); 177 | }) 178 | xit('if a status was passed, should only return the appointments with that status', function(){ 179 | let appointmentsPending = model.getAppointments('javier', 'pending'); 180 | let appointmentsAttended = model.getAppointments('javier', 'attended'); 181 | let appointmentsExpired = model.getAppointments('alejandro', 'expired'); 182 | let appointmentsCancelled = model.getAppointments('alejandro', 'cancelled'); 183 | expect(appointmentsPending).to.be.deep.equal([ { date: '22/10/2020 14:00', status: 'pending' } ]); 184 | expect(appointmentsAttended).to.be.deep.equal([ { date: '22/10/2020 16:00', status: 'attended' } ]); 185 | expect(appointmentsExpired).to.be.deep.equal([ { date: '22/10/2020 11:00', status: 'expired' } ]); 186 | expect(appointmentsCancelled).to.be.deep.equal([ { date: '22/10/2020 12:00', status: 'cancelled' } ]); 187 | }) 188 | }) 189 | 190 | describe('must have a metod getClients', function(){ 191 | xit('must be a function', function(){ 192 | expect(model.getClients).to.be.a('function'); 193 | }) 194 | xit('must return an a array with the names of the clients', function(){ 195 | model.addAppointment('javier', {date:'22/10/2020 14:00'}); 196 | model.addAppointment('alejandro', {date:'22/10/2020 12:00'}); 197 | let ret = model.getClients() 198 | expect(ret instanceof Array).to.be.true; 199 | expect(ret).to.be.deep.equal(['javier', 'alejandro']); 200 | }) 201 | }) 202 | }) 203 | 204 | const agent = session(server); 205 | describe('server', () => { 206 | beforeEach(() => { 207 | if (model.reset && model.addAppointment) { 208 | model.reset(); 209 | model.addAppointment('javier', {date:'22/10/2020 14:00'}); 210 | model.addAppointment('javier', {date:'22/10/2020 16:00'}); 211 | } 212 | }); 213 | 214 | describe('GET /api', function(){ 215 | xit('responds with the object clients', () => { 216 | return agent.get('/api') 217 | .expect(200) 218 | .then((res) => { 219 | expect(res.body).to.be.deep.equal({ 220 | javier: [ 221 | { date: '22/10/2020 14:00', status: 'pending' }, 222 | { date: '22/10/2020 16:00', status: 'pending' }] 223 | }); 224 | }); 225 | }); 226 | }) 227 | 228 | describe('POST /api/Appointments', () => { 229 | xit('responds with a status 400 (bad request) and a string message, if the client was not passed', ()=>{ 230 | return agent.post('/api/Appointments') 231 | .send({Appointment: {date:'22/10/2020 11:00'}}) 232 | .expect(400) 233 | .expect((res) => { 234 | expect(res.text).to.be.equal('the body must have a client property') 235 | }); 236 | }) 237 | xit('responds with a status 400 (bad request) and a string message, if the client was not a string', ()=>{ 238 | return agent.post('/api/Appointments') 239 | .send({client: 5, appointment: {date:'22/10/2020 11:00'}}) 240 | .expect(400) 241 | .expect((res) => { 242 | expect(res.text).to.be.equal('client must be a string') 243 | }); 244 | }) 245 | xit('add a appointment to a client', () => { 246 | return agent.post('/api/Appointments') 247 | .send({client: 'alejandro', appointment: {date:'22/10/2020 11:00'}}) 248 | .expect(200) 249 | .expect(() => { 250 | expect(model.clients.alejandro).to.be.deep.equal([ { date: '22/10/2020 11:00', status: 'pending' } ]) 251 | }); 252 | }); 253 | xit('responds the appointment after the addition', () => { 254 | return agent.post('/api/Appointments') 255 | .send({client: 'alejandro', appointment: {date:'22/10/2020 12:00'}}) 256 | .expect(200) 257 | .expect((res)=>{ 258 | expect(res.body).to.be.deep.equal({ date: '22/10/2020 12:00', status: 'pending' }) 259 | }) 260 | }); 261 | }) 262 | 263 | describe('GET /api/Appointments/:name?date=xxx&option=xxx', () => { 264 | xit('responds with a status 400 (bad request) and a string message, if the client does not exist', ()=>{ 265 | return agent.get('/api/Appointments/pepe?date=22/10/2020%2014:00&option=attend') 266 | .expect(400) 267 | .expect((res) => { 268 | expect(res.text).to.be.equal('the client does not exist') 269 | }) 270 | }) 271 | xit('responds with a status 400 (bad request) and a string message, if the client does not have a appointment for this date', ()=>{ 272 | return agent.get('/api/Appointments/javier?date=23/10/2020%2014:00&option=attend') 273 | .expect(400) 274 | .expect((res) => { 275 | expect(res.text).to.be.equal('the client does not have a appointment for that date') 276 | }) 277 | }) 278 | xit('responds with a status 400 (bad request) and a string message, if the option is not attend, expire or cancel', ()=>{ 279 | return agent.get('/api/Appointments/javier?date=22/10/2020%2014:00&option=wrongOption') 280 | .expect(400) 281 | .expect((res) => { 282 | expect(res.text).to.be.equal('the option must be attend, expire or cancel') 283 | }) 284 | }) 285 | xit('attend a appointment if the option passed by query is `attend`', ()=>{ 286 | return agent.get('/api/Appointments/javier?date=22/10/2020%2014:00&option=attend') 287 | .expect(200) 288 | .expect((res) => { 289 | expect(model.clients.javier[0]) 290 | .to.be.deep.equal({ date: '22/10/2020 14:00', status: 'attended' }) 291 | }) 292 | }) 293 | xit('expire a appointment if the option passed by query is `expire`', ()=>{ 294 | return agent.get('/api/Appointments/javier?date=22/10/2020%2016:00&option=expire') 295 | .expect(200) 296 | .expect((res) => { 297 | expect(model.clients.javier[1]) 298 | .to.be.deep.equal({ date: '22/10/2020 16:00', status: 'expired' }) 299 | }) 300 | }) 301 | xit('cancel a appointment if the option passed by query is `cancel`', ()=>{ 302 | return agent.get('/api/Appointments/javier?date=22/10/2020%2014:00&option=cancel') 303 | .expect(200) 304 | .expect((res) => { 305 | expect(model.clients.javier[0]) 306 | .to.be.deep.equal({ date: '22/10/2020 14:00', status: 'cancelled' }) 307 | }) 308 | }) 309 | xit('respods the modified appointment', ()=>{ 310 | return agent.get('/api/Appointments/javier?date=22/10/2020%2014:00&option=cancel') 311 | .expect(200) 312 | .expect((res) => { 313 | expect(res.body).to.be.deep.equal({ date: '22/10/2020 14:00', status: 'cancelled' }); 314 | }) 315 | }) 316 | }) 317 | 318 | 319 | describe('GET /api/Appointments/:name/erase', function(){ 320 | xit('responds with a status 400 (bad request) and a string message, if the client does not exist', ()=>{ 321 | return agent.get('/api/Appointments/pepe/erase?date=22/10/2020%2014:00') 322 | .expect(400) 323 | .expect((res) => { 324 | expect(res.text).to.be.equal('the client does not exist') 325 | }) 326 | }) 327 | xit('erase a appointment', () => { 328 | return agent.get('/api/Appointments/javier/erase?date=22/10/2020%2014:00') 329 | .expect(200) 330 | .expect((res)=>{ 331 | expect(model.clients.javier).to.be.deep.equal([ { date: '22/10/2020 16:00', status: 'pending' } ]) 332 | }) 333 | }); 334 | xit('erase all appointments of a certain status', () => { 335 | model.expire('javier', '22/10/2020 14:00'); 336 | return agent.get('/api/Appointments/javier/erase?date=expired') 337 | .expect(200) 338 | .expect((res)=>{ 339 | expect(model.clients.javier).to.be.deep.equal([ { date: '22/10/2020 16:00', status: 'pending' } ]) 340 | }) 341 | }); 342 | xit('responds the array of erased appointments', () => { 343 | model.expire('javier', '22/10/2020 14:00'); 344 | return agent.get('/api/Appointments/javier/erase?date=expired') 345 | .expect(200) 346 | .expect((res)=>{ 347 | expect(res.body).to.be.deep.equal([ { date: '22/10/2020 14:00', status: 'expired' } ]) 348 | }) 349 | }); 350 | }) 351 | 352 | describe('GET /api/Appointments/getAppointments/:name', function(){ 353 | xit('responds with the array of appointments with that status', () => { 354 | return agent.get('/api/Appointments/getAppointments/javier?status=pending') 355 | .expect(200) 356 | .then((res) => { 357 | expect(res.body).to.be.deep.equal([ 358 | { date: '22/10/2020 14:00', status: 'pending' }, 359 | { date: '22/10/2020 16:00', status: 'pending' } 360 | ]) 361 | }); 362 | }); 363 | }) 364 | 365 | describe('GET /api/Appointments/clients', function(){ 366 | xit('responds with an array of the list of clients', () => { 367 | return agent.get('/api/Appointments/clients') 368 | .expect(200) 369 | .then((res) => { 370 | expect(res.body).to.be.deep.equal([ 'javier' ]) 371 | }); 372 | }); 373 | }) 374 | 375 | }) --------------------------------------------------------------------------------