Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"chai-http": "^4.4.0",
"babel-eslint": "10.1.0",
"jest": "^29.7.0",
"mocha": "^10.4.0"
"mocha": "^10.4.0",
"node-mocks-http": "^1.0.0"
}
}
58 changes: 51 additions & 7 deletions src/controller/cities.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { findCities, registerCity, modifyCity, removeCity } = require("../service/cities");
const { findCities, findCity, registerCity, modifyCity, removeCity } = require("../service/cities");

const getCities = (async (req, res) => {
const cityList = await findCities();
Expand All @@ -12,7 +12,17 @@ const getCities = (async (req, res) => {
});

const getCity = (async (req, res) => {
const city = await findCity(req.params.city);
const cityId = parseInt(req.params.cityId);

if (!Number.isInteger(cityId)) {
res.status(400).json({
status: 'bad-request',
message: 'cityId is not a valid number'
});
return;
}

const city = await findCity(cityId);

if (city === undefined) {
res.status(404).json({
Expand Down Expand Up @@ -67,16 +77,50 @@ const postCity = (async (req, res) => {
});

const putCity = (async (req, res) => {
await modifyCity(req.params.name, req.body.population, req.body.altitude);
const cityId = parseInt(req.params.cityId);

if (!Number.isInteger(cityId)) {
res.status(400).json({
status: 'bad-request',
message: 'cityId is not a valid number'
});
return;
}

const modified = await modifyCity(cityId, req.body.name, req.body.population, req.body.altitude);

if (!modified) {
res.status(404).json({
status: 'not-found',
message: 'city not found'
});
return;
}

res.status(204).json({});
});

const deleteCity = (async (req, res) => {
// TODO Validaciones y comprobaciones
await removeCity(req.params.name);

res.status(204).json({})
const cityId = parseInt(req.params.cityId);

if (!Number.isInteger(cityId)) {
res.status(400).json({
status: 'bad-request',
message: 'cityId is not a valid number'
});
return;
}

const removed = await removeCity(cityId);
if (!removed) {
res.status(404).json({
status: 'not-found',
message: 'city not found'
});
return;
}

res.status(204).json({});
});

module.exports = {
Expand Down
6 changes: 3 additions & 3 deletions src/route/cities.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ const { getCities, getCity, postCity, putCity, deleteCity } = require('../contro
const router = express.Router();

router.get('/cities', getCities);
router.get('/cities/:city', getCity);
router.get('/cities/:cityId', getCity);
router.post('/cities', postCity);
router.put('/cities/:city', putCity);
router.delete('/cities/:city', deleteCity);
router.put('/cities/:cityId', putCity);
router.delete('/cities/:cityId', deleteCity);

module.exports = router;
17 changes: 9 additions & 8 deletions src/service/cities.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const knex = require('knex');

const { getYearsFromNow } = require('../dateUtils');
const { getDensity } = require('../utils');
const { getYearsFromNow } = require('../utils/dateUtils');
const { getDensity } = require('../utils/cityUtils');
const { config } = require('../config/configuration');

// Configuración de la base de datos: tipo, ubicación y otros parámetros
Expand All @@ -23,8 +23,8 @@ const findCities = (async () => {
return result;
});

const findCity = (async (name) => {
const result = await db('cities').select('*').where({name: name}).first();
const findCity = (async (cityId) => {
const result = await db('cities').select('*').where({id: cityId}).first();

return result;
});
Expand Down Expand Up @@ -60,16 +60,17 @@ const registerCity = (async (name, population, altitude, foundationDate, area) =
return result;
});

const modifyCity = (async (name, population, altitude) => {
const modifyCity = (async (cityId, name, population, altitude) => {
// TODO Modificar el resto de campos
await db('cities').where({ name: name }).update({
return await db('cities').where({ id: cityId }).update({
name: name,
population: population,
altitude: altitude
});
});

const removeCity = (async (name) => {
await db('cities').del().where({name: name});
const removeCity = (async (cityId) => {
return await db('cities').del().where({id: cityId});
});

module.exports = {
Expand Down
63 changes: 63 additions & 0 deletions src/test/unit/cities.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const httpMocks = require('node-mocks-http');
const { describe, it, expect, afterEach } = require('@jest/globals');

jest.mock('../../service/cities');

const cityController = require('../../controller/cities');

const cityService = require('../../service/cities');
const mockedFindCities = jest.spyOn(cityService, 'findCities');
const mockedRegisterCity = jest.spyOn(cityService, "registerCity");
const { mockCityArray, mockCityToPost, mockCityResponse, mockCityToRegister } = require('./mocks/cities');

afterEach(() => {
jest.clearAllMocks();
});

describe('cities', () => {
it('GET /cities should get a city list', async () => {
const response = httpMocks.createResponse();
const request = httpMocks.createRequest();
request.app = {};
request.app.conf = {};
request.path = '/cities';

const mockedCityList = jest.fn(async () => {
return mockCityArray;
});
mockedFindCities.mockImplementation(mockedCityList);

await cityController.getCities(request, response);
expect(mockedFindCities).toHaveBeenCalledTimes(1);
expect(response.statusCode).toEqual(200);
expect(response._isEndCalled()).toBeTruthy();
expect(response._getJSONData().length).toEqual(5);
});

it('POST /cities should register a new city', async () => {
const response = httpMocks.createResponse();
const request = httpMocks.createRequest();
request.app = {};
request.app.conf = {};
request.path = '/cities';
request.body = mockCityToRegister;

const mockedRegisterCityResponse = jest.fn(async () => {
return mockCityResponse;
});
mockedRegisterCity.mockImplementation(mockedRegisterCityResponse);

await cityController.postCity(request, response);
expect(mockedRegisterCity).toHaveBeenCalledTimes(1);
expect(response.statusCode).toEqual(201);
expect(response._isEndCalled()).toBeTruthy();
expect(response._getJSONData().id).toEqual(1);
expect(response._getJSONData().name).toEqual('Zaragoza');
expect(response._getJSONData().population).toEqual(700000);
expect(response._getJSONData().altitude).toEqual(200);
expect(response._getJSONData().age).toEqual(5);
expect(response._getJSONData().area).toEqual(734734);
expect(response._getJSONData().density).toEqual(2373);
expect(response._getJSONData().foundationDate).toEqual('2020-12-01');
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const expect = require('chai').expect;
const { getDensity} = require('../../utils');
const { getDensity} = require('../../utils/cityUtils');

describe('utils', () => {
it('getDensity', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/test/unit/dateUtils.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const expect = require('chai').expect;
const { getDaysFromNow, getDays} = require('../../dateUtils');
const { getDaysFromNow, getDays} = require('../../utils/dateUtils');

beforeAll(() => {
jest.useFakeTimers();
Expand Down
15 changes: 15 additions & 0 deletions src/test/unit/mocks/cities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
exports.mockCityArray = [
{"id":1,"name":"Zaragoza","population":700000,"altitude":200,"age":1000,"area":734734,"density":2373,"foundationDate":"1000-01-01T00:14:44.000Z"},
{"id":2,"name":"Madrid","population":5000000,"altitude":500,"age":800,"area":344734,"density":23473,"foundationDate":"1200-01-01T00:14:44.000Z"},
{"id":3,"name":"cityName","population":100,"altitude":200,"age":20,"area":1000,"density":0.1,"foundationDate":"2005-10-09T22:00:00.000Z"},
{"id":4,"name":"cityName","population":100,"altitude":200,"age":20,"area":1000,"density":0.1,"foundationDate":"2005-10-09T22:00:00.000Z"},
{"id":5,"name":"cityName","population":100,"altitude":200,"age":20,"area":1000,"density":0.1,"foundationDate":"2005-10-09T22:00:00.000Z"}
];

exports.mockCityToRegister = {
"name":"Zaragoza","population":700000,"altitude":200,"area":734734,"foundationDate":"2020-12-01"
};

exports.mockCityResponse = {
"id": 1,"name":"Zaragoza","population":700000,"altitude":200,"age":5,"area":734734,"density":2373,"foundationDate":"2020-12-01"
};
File renamed without changes.
File renamed without changes.