diff --git a/hackyourtemperature/__tests__/app.test.js b/hackyourtemperature/__tests__/app.test.js new file mode 100644 index 000000000..df78180ac --- /dev/null +++ b/hackyourtemperature/__tests__/app.test.js @@ -0,0 +1,68 @@ +import { server } from "../server.js"; +import app from "../app.js"; +import supertest from "supertest"; + +const request = supertest(app); + + +describe("POST /", () => { + it("check if city name is valid", async () => { + const response = await request + .post('/weather') + .send({"cityName": "London"}); + expect(response.status).toBe(200); + }); + + it("check if city name is missing", async () => { + const response = await request + .post('/weather') + .send({"cityName": ""}); + expect(response.status).toBe(400) + }); + + it("check if city name is wrong", async () => { + const response = await request + .post('/weather') + .send({"cityName": "Londondondon"}); + expect(response.body).toEqual({ error: "API error" }); + }); + + it("check if request body is a string", async () => { + const response = await request + .post("/weather") + .send({"cityName": "London"}) + .set("Content-Type", "application/json"); + expect(response.status).toBe(200); + }); + + it("check if the temperature is a number", async () => { + const response = await request + .post('/weather') + .send({"cityName": "London"}); + const fetchApi = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=London&appid=c34f56e7a569f2c2cf3e24aceac5ddc8&units=metric`); + const data = await fetchApi.json(); + expect(typeof data.main.temp).toBe("number"); + }); + + it("check if the temperature is a valid number", async () => { + const response = await request + .post('/weather') + .send({"cityName": "Ondangwa"}); + const fetchApi = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=Ondangwa&appid=c34f56e7a569f2c2cf3e24aceac5ddc8&units=metric`); + const data = await fetchApi.json(); + expect(data.main.temp).toBeGreaterThanOrEqual(-90); + expect(data.main.temp).toBeLessThanOrEqual(57); + }); + + it("check if fetch API is ok", async () => { + const response = await request + .post('/weather') + .send({"cityName": "London"}); + const fetchApi = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=London&appid=c34f56e7a569f2c2cf3e24aceac5ddc8&units=metric`); + expect(fetchApi.status).toBe(200) + }); +}); + +afterAll(() => { + server.close(); +}); \ No newline at end of file diff --git a/hackyourtemperature/app.js b/hackyourtemperature/app.js new file mode 100644 index 000000000..39b2becad --- /dev/null +++ b/hackyourtemperature/app.js @@ -0,0 +1,31 @@ +import express from "express"; +import { keys } from "./sources/keys.js"; +import fetch from "node-fetch"; +import { engine } from "express-handlebars"; + +const app = express(); + +app.use(express.json()) + +app.post('/weather', async (req, res) => { + const cityName = req.body.cityName; + + if(!cityName) { + return res.status(400).json({weatherText: "City is not found!" }) + } + + try { + const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${keys.API_KEY}&units=metric`); + if (!response.ok) { + return res.status(response.status).json({error: "API error"}); + } + const data = await response.json(); + return res.status(200).send(`It is ${data.main.temp}°C in ${cityName}`) + } + catch { + console.error("Error fetching data"); + res.status(500).json({ error: "Internal server error" }); + } +}); + +export default app; \ No newline at end of file diff --git a/hackyourtemperature/babel.config.cjs b/hackyourtemperature/babel.config.cjs new file mode 100644 index 000000000..76f107d0f --- /dev/null +++ b/hackyourtemperature/babel.config.cjs @@ -0,0 +1,13 @@ +module.exports = { + presets: [ + [ + // This is a configuration, here we are telling babel what configuration to use + "@babel/preset-env", + { + targets: { + node: "current", + }, + }, + ], + ], +}; \ No newline at end of file diff --git a/hackyourtemperature/jest.config.js b/hackyourtemperature/jest.config.js new file mode 100644 index 000000000..1686ec392 --- /dev/null +++ b/hackyourtemperature/jest.config.js @@ -0,0 +1,8 @@ +export default { + // Tells jest that any file that has 2 .'s in it and ends with either js or jsx should be run through the babel-jest transformer + transform: { + "^.+\\.jsx?$": "babel-jest", + }, + // By default our `node_modules` folder is ignored by jest, this tells jest to transform those as well + transformIgnorePatterns: [], +}; \ No newline at end of file diff --git a/hackyourtemperature/package.json b/hackyourtemperature/package.json new file mode 100644 index 000000000..3567d621f --- /dev/null +++ b/hackyourtemperature/package.json @@ -0,0 +1,27 @@ +{ + "name": "hackyourtemperature", + "version": "1.0.0", + "main": "server.js", + "type": "module", + "scripts": { + "start": "node server.js", + "dev": "nodemon server.js", + "test": "jest" + }, + "keywords": [], + "author": "", + "license": "ISC", + "description": "", + "dependencies": { + "express": "^4.21.1", + "express-handlebars": "^8.0.1", + "node-fetch": "^3.3.2" + }, + "devDependencies": { + "@babel/preset-env": "^7.26.0", + "babel-jest": "^29.7.0", + "jest": "^29.7.0", + "nodemon": "^3.1.7", + "supertest": "^7.1.0" + } +} diff --git a/hackyourtemperature/server.js b/hackyourtemperature/server.js new file mode 100644 index 000000000..9c647f581 --- /dev/null +++ b/hackyourtemperature/server.js @@ -0,0 +1,7 @@ +import app from './app.js'; + +const port = 3000; + +export const server = app.listen(port, () => { + console.log(`App listening on port ${port}`); +}); diff --git a/hackyourtemperature/sources/keys.js b/hackyourtemperature/sources/keys.js new file mode 100644 index 000000000..e450a5f7f --- /dev/null +++ b/hackyourtemperature/sources/keys.js @@ -0,0 +1 @@ +export const keys = {API_KEY: "c34f56e7a569f2c2cf3e24aceac5ddc8"}; \ No newline at end of file