Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chitter frontend #126

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
bundle.js
62 changes: 62 additions & 0 deletions chitterApi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
class ChitterApi {
fetchPeeps(callback) {
fetch("https://chitter-backend-api-v2.herokuapp.com/peeps")
.then((response) => response.json())
.then(callback);
}

createUser(newUsername, newPassword, callback) {
fetch("https://chitter-backend-api-v2.herokuapp.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user: { handle: newUsername, password: newPassword },
}),
})
.then((response) => response.json())
.then(callback);
}

loginUser(username, password, callback) {
fetch("https://chitter-backend-api-v2.herokuapp.com/sessions", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
session: { handle: username, password: password },
}),
})
.then((response) => response.json())
.then(callback);
}

postPeep(sessionKey, userId, peepBody, callback) {
fetch("https://chitter-backend-api-v2.herokuapp.com/peeps", {
method: "POST",
headers: {
Authorization: `Token token=${sessionKey}`,

Choose a reason for hiding this comment

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

Interesting difference here.

Will also work as 'Token token=' + sessionKey

I don't know which is best.

"Content-Type": "application/json",
},
body: JSON.stringify({
peep: {
user_id: userId,
body: peepBody,
},
}),
})
.then((response) => response.json())
.then(callback);
}

deletePeep(peepId, sessionKey, callback) {
fetch(`https://chitter-backend-api-v2.herokuapp.com/peeps/${peepId}`, {
method: "DELETE",
headers: { Authorization: `Token token=${sessionKey}` },
}).then(callback);
}
}

module.exports = ChitterApi;
88 changes: 88 additions & 0 deletions chitterApi.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const ChitterApi = require("./chitterApi");

require("jest-fetch-mock").enableMocks();

let api,
testPeepsArray,
testUserSessionResponse,
testPostPeepResponse,
testDeletePeepResponse;

describe("ChitterApi class", () => {
beforeEach(() => {
api = new ChitterApi();
testPeepsArray = require("./testPeepsArray");
testUserSessionResponse = require("./testUserSessionResponse");
testPostPeepResponse = require("./testPostPeepResponse");
testDeletePeepResponse = require("./testDeletePeepResponse");
fetch.resetMocks();
Comment on lines +14 to +18

Choose a reason for hiding this comment

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

Overall the tests are logical and beautifully written. Main question is:

Would the tests have achieved the same objectives with 'simple' data rather than the 'real' examples you've used in each of the files?

You could have all of your test data in one json file (test-data.json for example?)

I like that you've used the example data - but if the tests have the same integrity with simplified data then it would be best to simplify.

});

it("gets peeps from chitter", () => {
expect.assertions(4);
fetch.mockResponseOnce(JSON.stringify(testPeepsArray));
api.fetchPeeps((data) => {
expect(data.length).toBe(2);
expect(data[0].id).toBe(1494);
expect(data[1].id).toBe(1461);
expect(fetch.mock.calls[0][0]).toEqual(
"https://chitter-backend-api-v2.herokuapp.com/peeps"
);
});
});

it("creates a new user", () => {
expect.assertions(3);

fetch.mockResponseOnce(JSON.stringify(testUserSessionResponse));
api.createUser("kay", "mypassword", (data) => {
expect(data.handle).toBe("kay");
expect(fetch.mock.calls[0][0]).toEqual(
"https://chitter-backend-api-v2.herokuapp.com/users"
);
expect(fetch.mock.calls[0][1].method).toBe("POST");
});
});

it("logs in a user", () => {
expect.assertions(4);
fetch.mockResponseOnce(
JSON.stringify({
user_id: 1,
session_key: "a_valid_session_key",
})
);
api.loginUser("kay", "mypassword", (data) => {
expect(data.user_id).toBe(1);
expect(data.session_key).toBe("a_valid_session_key");
expect(fetch.mock.calls[0][0]).toEqual(
"https://chitter-backend-api-v2.herokuapp.com/sessions"
);
expect(fetch.mock.calls[0][1].method).toBe("POST");
});
});

it("posts a Peep", () => {
expect.assertions(3);
fetch.mockResponseOnce(JSON.stringify(testPostPeepResponse));
api.postPeep("sessionKey", 1, "my first peep :)", (data) => {
expect(data).toEqual(testPostPeepResponse);
expect(fetch.mock.calls[0][0]).toEqual(
"https://chitter-backend-api-v2.herokuapp.com/peeps"
);
expect(fetch.mock.calls[0][1].method).toBe("POST");
});
});

it("deletes a Peep", () => {
expect.assertions(3);
fetch.mockResponseOnce({}, { status: 204 });
api.deletePeep(1494, "session key", (response) => {
expect(fetch.mock.calls[0][0]).toEqual(
"https://chitter-backend-api-v2.herokuapp.com/peeps/1494"
);
expect(fetch.mock.calls[0][1].method).toBe("DELETE");
expect(response.status).toBe(204);
});
});
});
41 changes: 41 additions & 0 deletions chitterModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
class ChitterModel {
constructor() {
this.peepsArray = [];
this.userId = null;
this.sessionKey = null;
}

setPeeps(peepsArray) {
this.peepsArray = peepsArray;
}

loadPeeps() {
return this.peepsArray;
}

setUserId(userId) {
this.userId = userId;
}

loadUserId() {
return this.userId;
}

resetUserId() {
this.userId = null;
}
Comment on lines +24 to +26

Choose a reason for hiding this comment

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

This method has not been tested in chitterModel.test.js


setSessionKey(sessionKey) {
this.sessionKey = sessionKey;
}

loadSessionKey() {
return this.sessionKey;
}

resetSessionKey() {
this.sessionKey = null;
}
Comment on lines +36 to +38

Choose a reason for hiding this comment

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

This method has not been tested in chitterModel.test.js

}

module.exports = ChitterModel;
25 changes: 25 additions & 0 deletions chitterModel.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const ChitterModel = require("./chitterModel");

let model, peepsArray;

describe("ChitterModel class", () => {
beforeEach(() => {
model = new ChitterModel();
testPeepsArray = require("./testPeepsArray");
});

it("sets and loads Peeps", () => {
model.setPeeps(peepsArray);
expect(model.loadPeeps()).toBe(peepsArray);
});

it("sets the user ID", () => {
model.setUserId(1);
expect(model.loadUserId()).toBe(1);
});

it("sets the session key", () => {
model.setSessionKey("session key");
expect(model.loadSessionKey()).toBe("session key");
});
});
141 changes: 141 additions & 0 deletions chitterView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
class ChitterView {
constructor(model, api, displaySinglePeep) {
this.model = model;
this.api = api;
this.displaySinglePeep = displaySinglePeep;

this.newUsernameInputEl = document.querySelector("input#create-username");
this.newPasswordInputEl = document.querySelector("input#create-password");

// create user button listener
document
.querySelector("#create-user-button")
.addEventListener("click", () => {
this.removeUserCreatedMessages();
this.api.createUser(
this.newUsernameInputEl.value,
this.newPasswordInputEl.value,
(data) => {
this.handleTakenLogic(data);
this.newUsernameInputEl.value = "";
this.newPasswordInputEl.value = "";
}
);
});

this.loginUsernameEl = document.querySelector("#login-username");
this.loginPasswordEl = document.querySelector("#login-password");

// login button listener
document.querySelector("#login-button").addEventListener("click", () => {
this.api.loginUser(
this.loginUsernameEl.value,
this.loginPasswordEl.value,
(data) => {
this.model.setUserId(data.user_id);
this.model.setSessionKey(data.session_key);
this.loginUsernameEl.value = "";
this.loginPasswordEl.value = "";
setTimeout(this.displayPeepsFromApi(), 500);
}
);
});

// logout button listener
document.querySelector("#logout-button").addEventListener("click", () => {
this.model.resetSessionKey();
this.model.resetUserId();
setTimeout(this.displayPeepsFromApi(), 500);
});

this.postPeepBodyEl = document.querySelector("#post-peep-body");

// post peep button listener
document
.querySelector("#post-peep-button")
.addEventListener("click", () => {
this.api.postPeep(
this.model.loadSessionKey(),
this.model.loadUserId(),
this.postPeepBodyEl.value,
() => {
this.createPeepSuccessMesage();
this.postPeepBodyEl.value = "";
setTimeout(this.displayPeepsFromApi(), 500);
}
);
});
}

addDeleteButtonListeners() {
document.querySelectorAll(".delete-peep-button").forEach((element) => {
const peepId = element.id.split("-")[3];
element.addEventListener("click", () => {
this.api.deletePeep(peepId, this.model.loadSessionKey(), (data) => {
setTimeout(this.displayPeepsFromApi(), 500);
});
});
});
}

createPeepSuccessMesage() {
const postPeepSuccessMessageEl = document.createElement("p");
postPeepSuccessMessageEl.id = "post-peep-success-message";
postPeepSuccessMessageEl.textContent = "Peep posted successfully!";
document
.querySelector("div#post-peep-container")
.append(postPeepSuccessMessageEl);
}

removeUserCreatedMessages() {
if (document.querySelector("#handle-taken-message") !== null)
document.querySelector("#handle-taken-message").remove();
if (document.querySelector("#new-user-created-message") !== null)
document.querySelector("#new-user-created-message").remove();
}

handleTakenLogic(data) {
if (data.handle[0] === "has already been taken") {
this.handleTaken();
} else {
this.userCreated();
}
}

handleTaken() {
const handleTakenMessageEl = document.createElement("p");
handleTakenMessageEl.id = "handle-taken-message";
handleTakenMessageEl.textContent = "This handle has been taken";
this.createUserContainerEl.append(handleTakenMessageEl);
}

userCreated() {
const newUserCreatedMessageEl = document.createElement("p");
newUserCreatedMessageEl.textContent = "You have created a new account!";
newUserCreatedMessageEl.id = "new-user-created-message";
this.createUserContainerEl.append(newUserCreatedMessageEl);
}

displayPeeps() {
if (document.querySelectorAll("div.peep").length > 0) {
document
.querySelectorAll("div.peep")
.forEach((element) => element.remove());
}
this.model
.loadPeeps()
.forEach((peep) =>
this.displaySinglePeep.display(peep, this.model.loadUserId())
);
this.addDeleteButtonListeners();
}

displayPeepsFromApi() {
this.api.fetchPeeps((peeps) => {
this.model.setPeeps(peeps);
this.displayPeeps();
});
}
}

module.exports = ChitterView;
Loading