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
@@ -0,0 +1,3 @@
node_modules
bundle.js
.DS_Store
112 changes: 112 additions & 0 deletions ChitterFrontendDesign.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Chitter Frontend web application design recipe

To build a front-end single-page-app to interface with the API

## 1. Describe the problem

- Creating users
- Logging in
- Posting peeps
- Viewing all Peeps

## 2. Design classes

- To visualise the frame work of the application

1. client to fetch API
2. model to be bundled and loaded by the web page
3. View class to reflect model's data on the page by dynamically creating HTML elements

## 3. API class

- fetch API to make an HTTP request to back-end server

```javascript
class chitterClient {
loadPeeps() {
// GET all peeps data
}

createUser(userId, passowrd) {
// POST to create a new user
}

newSession(userId, password) {
// POST to create a new log in session
}

addPeep(uerId, sessionKey, newPeep) {
// POST to add new peep
}
}
```

## 4. Model class

- To create and add new user

```javascript
class PeepModel {
getPeeps() {
// returns the list of peeps
}

addPeep(peep) {
// adds new peep
}

setPeeps() {
// retrieve peeps from the API
}
}
```

- To create and add new messages

```javascript
class UserModel {
getUser() {
// returns user object with userId and handle
}

setUser(UserId, userHandle) {
// retrieve user data from the API after creating a new user
}

getSession() {
// get session to start a new session
}

setSession(userId, sessionKey) {
// retrieve user session data from the API
}

resetSession() {
// reset the session
}
}
```

## 5. View class

- To interact with html page, loading the data from model class.

```javascript
class ChitterView {
addNewPeep(newPeep) {
// add peeps into the peepModel
}

displayPeeps() {
// display all peeps added
}

displayPeepsFromApi() {
// display all peeps data from Api
}

signUp() {}

logIn() {}
}
```
28 changes: 11 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
# Chitter API Frontend Challenge

* Feel free to use Google, your notes, books, etc. but work on your own
* If you refer to the solution of another coach or student, please put a link to that in your README
* If you have a partial solution, **still check in a partial solution**
* You must submit a pull request to this repo with your code by 9am Monday morning

Challenge:
-------
## Challenge:

As usual please start by forking this repo.

Expand All @@ -18,20 +12,20 @@ Your task is to build a front-end single-page-app to interface with this API. Yo

Here are some interactions the API supports. Implement as many as you see fit.

* Creating Users
* Logging in
* Posting Peeps
* Viewing all Peeps *(I suggest you start here)*
* Viewing individual Peeps
* Deleting Peeps
* Liking Peeps
* Unliking Peeps
- Creating Users
- Logging in
- Posting Peeps
- Viewing all Peeps _(I suggest you start here)_
- Viewing individual Peeps
- Deleting Peeps
- Liking Peeps
- Unliking Peeps

We are looking for well tested, easy to read, easy to change code. This is more important than the number of interactions you implement.

Note that others may be doing the same task at the same time, so the data may change as you are using it.

## Utilities you might find useful

* [The Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) for making requests.
* [Postman](https://www.getpostman.com/) or [Insomnia](https://insomnia.rest/) for exploring the API.
- [The Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) for making requests.
- [Postman](https://www.getpostman.com/) or [Insomnia](https://insomnia.rest/) for exploring the API.
77 changes: 77 additions & 0 deletions __tests__/chitterClient.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
const ChitterClient = require('../src/chitterClient');

require('jest-fetch-mock').enableMocks()

describe('Client class', () => {
beforeEach(() => {
fetch.resetMocks();
});

it('calls fetch and loads all peeps', (done) => {
const client = new ChitterClient();
fetch.mockResponseOnce(JSON.stringify({
"id": 3,
"body": "my first peep :)"
}));

client.loadPeeps((returnedData) => {
expect(returnedData).toEqual({
"id": 3,
"body": "my first peep :)"
});

done();
});
})

it('calls fetch and create a new user', (done) => {
const client = new ChitterClient();
fetch.mockResponseOnce(JSON.stringify({
"id": 1,
"handle": "newUser"
}));

client.createUser('newUser', 'password123', (returnedData) => {
expect(returnedData).toEqual({
"id": 1,
"handle": "newUser"
});

done();
});
})

it('calls fetch and creates a new session for logging in', (done) => {
const client = new ChitterClient();
fetch.mockResponseOnce(JSON.stringify({
"user_id": 1,
"session_key": "a_valid_session_key"
}));

client.newSession('maker', 'password123', (returnedData) => {
expect(returnedData).toEqual({
"user_id": 1,
"session_key": "a_valid_session_key"
});

done();
});
})

it('calls fetch and create a new peep', (done) => {
const client = new ChitterClient();
fetch.mockResponseOnce(JSON.stringify({
"id": 3,
"body": "This is a new peep"
}));

client.addPeep(1, "a_valid_session_key", 'This is a new peep', (returnedData) => {
expect(returnedData).toEqual({
"id": 3,
"body": "This is a new peep"
});

done();
});
})
});
146 changes: 146 additions & 0 deletions __tests__/chitterView.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/**
* @jest-environment jsdom
*/

const fs = require('fs');
const PeepModel = require('../src/models/peepModel');
const UserModel = require('../src/models/userModel');
const ChitterView = require('../src/views/chitterView');

describe('Chitter view', () => {
beforeEach(() => {
document.body.innerHTML = fs.readFileSync('./index.html');
})

it('displays a peep', () => {
const model = new PeepModel();
const view = new ChitterView(model);
this.mockedData = [{
"id": 3,
"body": "my first peep :)",
"created_at": "2022-10-28T13:21:23.317Z",
"updated_at": "2022-10-28T13:21:23.317Z",
"user": { "id": 1, "handle": "maker" },
"likes": [{ "user": { "id": 1, "handle": "maker" } }]
}]

model.addPeep(this.mockedData[0]);

view.displayPeeps();

expect(document.querySelectorAll('.peep').length).toBe(1);
expect(document.querySelectorAll('.peep-body')[0].textContent).toBe('my first peep :) @maker');
})

it('displays the list of peeps', () => {
const model = new PeepModel();
const view = new ChitterView(model);

model.addPeep(this.mockedData[0]);
model.addPeep({
"id": 4,
"body": "Hello",
"created_at": "2022-10-28T13:21:23.317Z",
"updated_at": "2022-10-28T13:21:23.317Z",
"user": { "id": 1, "handle": "stranger" },
"likes": [{ "user": { "id": 1, "handle": "stranger" } }]
});

view.displayPeeps();

expect(document.querySelectorAll('.peep').length).toBe(2);
expect(document.querySelectorAll('.peep-body')[1].textContent).toBe('Hello @stranger');

})

it('displays the list of peeps from API', () => {
const mockedApi = {
loadPeeps: (cb) => {
cb(this.mockedData)
}
}
const model = new PeepModel();
const view = new ChitterView(model, mockedApi);

view.displayPeepsFromAPI();

expect(document.querySelectorAll('.peep').length).toBe(1);
expect(document.querySelectorAll('.peep-body')[0].textContent).toBe('my first peep :) @maker');
})

it('clicks the sign up button and creates a new user', () => {
const mockedApi = {
createUser: (username, password, cb) => {
cb({ "id" : 1, "handle" : "maker"})
}
}
const model = new PeepModel();
const user = new UserModel();
const view = new ChitterView(model, mockedApi, user);

const userNameInput = document.querySelector('#new-username-input');
userNameInput.value = 'maker';
const passwordInput = document.querySelector('#new-password-input');
passwordInput.value = 'password123';

const signupButton = document.querySelector('#sign-up-btn');
signupButton.click();

view.signUp();
const signupMessage = document.querySelector('.sign-up-message').textContent;
expect(signupMessage).toBe('Welcome maker, thanks for joining us!')
})

it('clicks the log in button and start a new session', () => {
const mockedApi = {
newSession: (username, password, cb) => {
cb({ "user_id": 1, "session_key": "a_valid_session_key" })
}
}

const model = new PeepModel();
const user = new UserModel();
const view = new ChitterView(model, mockedApi, user);

const userNameInput = document.querySelector('#username-input');
userNameInput.value = 'maker';
const passwordInput = document.querySelector('#password-input');
passwordInput.value = 'password123';

const loginButton = document.querySelector('#log-in-btn');
loginButton.click();

view.logIn();
const loginMessage = document.querySelector('.log-in-message').textContent;
expect(loginMessage).toBe('Hello maker! Make your peep')
})

it('clicks the peep button and create a new peep', () => {
const mockedApi = {
addPeep: (userId, sessionKey, newPeep, cb) => {
cb({
"id": 3,
"body": "Hello",
"created_at": "2022-10-30T13:21:23.317Z",
"updated_at": "2022-10-30T13:21:23.317Z",
"user": { "id": 1, "handle": "maker" },
"likes": [{ "user": { "id": 1, "handle": "maker" } }]
})
}
}

const model = new PeepModel();
const user = new UserModel();
const view = new ChitterView(model, mockedApi, user);

view.createPeep();
const newPeepInput = document.querySelector('#peep-input');
newPeepInput.value = 'Hello';

const peepButton = document.querySelector('#add-peep-btn');
peepButton.click();

const peepEl = document.querySelector('.peep-body');
expect(peepEl.textContent).toBe('Hello @maker');
})
})
Loading