Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.DS_Store
bin
sources
assignments-solution
node_modules
npm-debug.log
Expand All @@ -8,3 +9,5 @@ yarn-error.log
*.bkp

week3/prep-exercise/server-demo/
assignments/hackyourtemperature/sources/keys.js

1 change: 1 addition & 0 deletions assignments/config-files/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
console.log("Jest config loaded");
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: {
Expand Down
65 changes: 65 additions & 0 deletions assignments/hackyourtemperature/__tests__/app.test.js

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good test suite, well done! One small thing you could change is the order and grouping of the tests. You can put multiple tests into one describe block, which makes it easier to see which tests belong together, and cleans up your test logs a bit. It's also good to pick an order for tests, group them by end point and then either start with the happy path test and then error cases, or the other way around.

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import app from "../app.js";
import supertest from "supertest";
import fetch from "node-fetch";

jest.mock("node-fetch");
const request = supertest(app);

describe("POST /", () => {
it("Quick test", () => {
expect(1).toBe(1);
});
});

describe("Test GET /", () => {
test("Send hello to backend", async () => {
const res = await request.get("/");

expect(res.statusCode).toBe(200);
expect(res.text).toBe("hello from backend to frontend!");
});
});

describe("Test POST /weather", () => {
test("Return city name is required.", async () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like how this test is using the AAA principle. This makes it very readable, great!

const city = " ";

const res = await request.post("/weather").send({ cityName: city });

expect(res.statusCode).toBe(400);
expect(res.body).toEqual({ msg: "City name is required." });
});
});

//test the happy path: when the user sends a valid city name, the API returns weather data.
describe("Test POST /weather", () => {
test("Return temperature data", async () => {
const city = "amsterdam";
fetch.mockResolvedValue({
ok: true,
json: async () => ({
name: "Amsterdam",
main: { temp: 286.78 },
}),
});
const res = await request.post("/weather").send({ cityName: city });

expect(res.statusCode).toBe(200);
expect(res.body.main.temp).toBe(286.78);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also test for the city name here, to make sure we get all the correct data.

});
});

describe("Test POST /weather", () => {
test("Return city not found", async () => {
const city = "amsterddam";

fetch.mockResolvedValue({
ok: false,
json: async () => ({}),
});
const res = await request.post("/weather").send({ cityName: city });

expect(res.statusCode).toBe(400);
expect(res.body).toEqual({ weatherText: "City is not found!" });
});
});
36 changes: 36 additions & 0 deletions assignments/hackyourtemperature/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import express from "express";
import fetch from "node-fetch";
import { keys } from "./sources/keys.js";

const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.get("/", (req, res) => {
res.status(200).send(`hello from backend to frontend!`);
});

app.post("/weather", async (req, res) => {
const { cityName } = req.body;
if (!cityName || cityName.trim() === "") {
return res.status(400).json({ msg: "City name is required." });

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice guard clause!

}

const url = `https://api.openweathermap.org/data/2.5/weather?q=${encodeURIComponent(
cityName.trim()
)}&appid=${keys.API_KEY}`;

try {
const response = await fetch(url);
if (!response.ok) {
return res.status(400).json({ weatherText: "City is not found!" });

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we're already in a try-catch we could also throw here.

}
const data = await response.json();

return res.json({ main: data.main });
} catch (error) {
res.send(error);
}
});

export default app;
13 changes: 13 additions & 0 deletions assignments/hackyourtemperature/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -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",
},
},
],
],
};
8 changes: 8 additions & 0 deletions assignments/hackyourtemperature/jest.config.js
Original file line number Diff line number Diff line change
@@ -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: [],
};
28 changes: 28 additions & 0 deletions assignments/hackyourtemperature/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "hackyourtemperature",
"version": "1.0.0",
"main": "server.js",
"type": "module",
"scripts": {
"test": "jest",
"start": "node server.js",
"dev": "nodemon server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"express": "^5.1.0",
"express-handlebars": "^8.0.1",
"node-fetch": "^3.3.2"
},
"devDependencies": {
"@babel/core": "^7.28.5",
"@babel/preset-env": "^7.28.5",
"babel-jest": "^30.2.0",
"jest": "^30.2.0",
"nodemon": "^3.1.10",
"supertest": "^7.1.4"
}
}
7 changes: 7 additions & 0 deletions assignments/hackyourtemperature/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import app from "./app.js";

const port = 3000;

app.listen(port, () => {
console.log(`server is running on port ${port}`);
});