diff --git a/.github/.DS_Store b/.github/.DS_Store new file mode 100644 index 000000000..f29153d3e Binary files /dev/null and b/.github/.DS_Store differ diff --git a/.github/workflows/cypress-tests.yml b/.github/workflows/cypress-tests.yml new file mode 100644 index 000000000..2fe9626b5 --- /dev/null +++ b/.github/workflows/cypress-tests.yml @@ -0,0 +1,28 @@ +name: Cypress Tests +on: [push] +jobs: + cypress-run: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + build: npm run build + + + # Install NPM dependencies, cache them correctly + # and run all Cypress tests + - name: Create mongoDB Docker container + run: sudo docker run -d -p 27017:27017 mongo:latest + - name: start server + uses: cypress-io/github-action@v4.1.0 # use the explicit version number + with: + wait-on: "http://localhost:3030" + config-file: cypress.config.cjs + # build: npm run build + start: npm run start:test + env: + MONGODB_URI: "mongodb://0.0.0.0:27017/" + MONGODB_DATABASE: "acebook_test" + - name: run cypress component test + run: npm run test:unit \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3dc633e98..eba69689a 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,9 @@ typings/ # cypress.io cypress/screenshots cypress/videos + +# Webstorm config folder +.idea + +# DS_STORE FILE +.DS_Store diff --git a/README.md b/README.md index eee74593d..757f6f40a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ It uses: ## Card wall -REPLACE THIS TEXT WITH A LINK TO YOUR CARD WALL +Link to Trello: https://trello.com/b/TpjSuBYO/jam-a-pc ## Quickstart @@ -31,6 +31,17 @@ REPLACE THIS TEXT WITH A LINK TO YOUR CARD WALL nvm install 18 ``` +_Note: you if you get an error when running `nvm install 18`, completeing the following commands might help:_ + +`curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash` + +`source ~/.zshrc` + +`nvm install node` + +`nvm use node` + + ### Set up your project 1. Fork this repository @@ -74,6 +85,9 @@ so that integration tests do not interact with the development server. ### Test +_Note: if at any point you get a 'this is your first time running cypress' message telling you that you need to verify it, enter the following command to verify:_ +`npx cypress verify` + - Run all tests ``` npm test @@ -93,3 +107,47 @@ Some people occasionally experience MongoDB connection errors when running the t - Check that it's running using `brew services list` If you have issues that are not resolved by these tips, please reach out to a coach and, once the issue is resolved, we can add a new tip! + +# General Rules: + +To be used as a guide, will fluctuate day to day as work needs + +1. **0930** - Previous cohort/team standup + 1. shared learning + 2. ideas sharing + 3. shared unblocking + + +2. **1000** - JAMA PC standup + 1. completed items + 2. plans for the day + 3. new items to add + 4. items to remove + 5. any issues? + + +3. **1230-1400** LUNCH + + +5. **1400** - Afternoon catchup + + +7. **1700** - daily roundup + 1. completed items + 2. plans for the day + 3. new items to add + 4. items to remove + 5. any issues? + + +## Quality - for the group is: +- understandable code +- fully functional to the MVP - or above if time +- looks nice as well + +Maybe we need to consider: +- Usability +- Accessibility +- Security +- Testability +- Longevity diff --git a/controllers/posts.js b/controllers/posts.js index 4b521304d..75a20ee86 100644 --- a/controllers/posts.js +++ b/controllers/posts.js @@ -1,28 +1,150 @@ const Post = require("../models/post"); +const Comment = require("../models/comment"); +const User = require("../models/user"); const PostsController = { Index: (req, res) => { - Post.find((err, posts) => { + Post.find((err) => { if (err) { throw err; } - - res.render("posts/index", { posts: posts }); - }); + }).sort({date:-1}).then((post) => { + let collection = []; + async function post_set(post, i) { + await User.findById(post[i].user_id, (err, user) => { + if (err) { + throw err; + } + let regex = /^\w*[^@]/g; + let username = user.email.match(regex); + let isPicture = post[i].picture !== ""; + collection.push({post: post[i], picture: user.picture, username: username, isPicture: isPicture}); + }) + } + async function increment(post) { + for(let i = 0; i < post.length; i++) { + await post_set(post, i); + } + res.render("posts/index", { collection: collection , session_user: req.session.user}); + } + increment(post); + }) }, New: (req, res) => { - res.render("posts/new", {}); + res.render("posts/new", {session_user: req.session.user}); }, Create: (req, res) => { const post = new Post(req.body); - post.save((err) => { + post.date = Date.now(); + post.user_id = req.session.user._id; + if (post.message === "" || post.message.length > 250) { + res.status(201).redirect("/posts/new"); + } else if (post.message[0] === " ") { + const trimmed_post = post.message.trim(); + if (trimmed_post.length != 0) { + post.message = trimmed_post; + post.save((err) => { + if (err) { + throw err; + } + + res.status(201).redirect(`/posts/`); + }); + } else { + res.status(201).redirect(`/posts/new`); + } + } else { + post.save((err) => { + if (err) { + throw err; + } + + res.status(201).redirect("/posts"); + }); + } + }, + + Like: (req, res) => { + const postId = req.params.id; + const userId = req.session.user._id + + Post.findById(postId, (err, post) => { if (err) { throw err; } - - res.status(201).redirect("/posts"); + + const alreadyLiked = post.liked_by.includes(userId); + + if (!alreadyLiked) { + post.likes = post.likes + 1; + post.liked_by.push(userId); + } else { + post.likes = post.likes - 1; + post.liked_by = post.liked_by.filter(id => id !== userId); + } + + post.save((err) => { + if (err) { + throw err; + } + + res.redirect("/posts"); + }); }); }, + + Details: (req, res) => { + const postId = req.params.id; + Post.findById(postId, (err, post) => { + if (err) { + throw err; + } + + return post; + }).then((post) => ( + Comment.find((err, comments) => { + if (err) { + throw err; + } + res.render("posts/details", {comments: comments, post: post, session_user: req.session.user}); + }).where({post_id: postId}) + )); + }, + + CreateComment: (req, res) => { + const postId = req.params.id; + const userId = req.session.user._id + + const comment = new Comment(req.body); + comment.post_id = postId; + comment.user_id = userId; + + if (comment.message === "" || comment.message.length > 250) { + res.status(201).redirect(`/posts/${postId}`); + } else if (comment.message[0] === " ") { + const trimmed = comment.message.trim(); + if (trimmed.length != 0) { + comment.message = trimmed; + comment.save((err) => { + if (err) { + throw err; + } + + res.status(201).redirect(`/posts/${postId}`); + }); + } else { + res.status(201).redirect(`/posts/${postId}`); + } + } else { + comment.save((err) => { + if (err) { + throw err; + } + + res.status(201).redirect(`/posts/${postId}`); + }); + } + } }; module.exports = PostsController; diff --git a/controllers/sessions.js b/controllers/sessions.js index 917e2e14c..d7049c8f9 100644 --- a/controllers/sessions.js +++ b/controllers/sessions.js @@ -2,7 +2,7 @@ const User = require("../models/user"); const SessionsController = { New: (req, res) => { - res.render("sessions/new", {}); + res.render("sessions/new", {error: req.session.error}); }, Create: (req, res) => { @@ -11,9 +11,8 @@ const SessionsController = { const password = req.body.password; User.findOne({ email: email }).then((user) => { - if (!user) { - res.redirect("/sessions/new"); - } else if (user.password != password) { + if (!user || user.password != password) { + req.session.error = "INVALID USERNAME OR PASSWORD"; res.redirect("/sessions/new"); } else { req.session.user = user; diff --git a/controllers/users.js b/controllers/users.js index bdc2ea8f3..3bf1a1b58 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -2,16 +2,123 @@ const User = require("../models/user"); const UsersController = { New: (req, res) => { - res.render("users/new", {}); + res.render("users/new", {error: req.session.error, session_user: req.session.user}); }, Create: (req, res) => { const user = new User(req.body); - user.save((err) => { + + User.findOne({email : user.email}, (err, founduser) => { + if (err) { + throw err; + } + + if (user.email === "" || user.password.length < 8 || founduser != null) { + req.session.error = "INVALID USERNAME OR PASSWORD"; + res.redirect("/users/new"); + } else if (founduser === null) { + user.save((err) => { + if (err) { + throw err; + } + res.status(201).redirect("/sessions/new"); + }); + } + }) + }, + + Details: (req, res) => { + const userId = req.params.id; + const sessionId = req.session.user._id; + + User.findById(userId, (err, user) => { + if (err) { + throw err; + } + + const isSessionUser = userId !== sessionId; + + if(userId != sessionId) { + user.friends = []; + } + + if (user.friends) { + user.friends = user.friends.filter(friend => friend.status === "pending"); + } + + res.render("users/details", { + user: user, + session_user: req.session.user, + is_session_user: isSessionUser + }); + }); + }, + + Request: (req, res) => { + const currentId = req.session.user._id; + const targetId = req.params.id; + + User.findById(targetId, (err, user) => { if (err) { throw err; } - res.status(201).redirect("/posts"); + if (targetId != currentId) + { + if (user.friends.filter(object => object.user_id === currentId).length === 0) { + user.friends.push({user_id: `${currentId}`, status: "pending"}) + + user.save((err) => { + if (err) { + throw err; + } + }); + } + } + res.status(201).redirect(`/users/${targetId}`); + }); + }, + + Confirm: (req, res) => { + const theirId = req.params.id; + const hostId = req.session.user._id; + + User.findOneAndUpdate({"_id": hostId, "friends.user_id": theirId}, {"$set": {"friends.$.status": "confirmed"}}, (err) => { + if (err) { + throw err; + } + res.status(201).redirect(`/users/${hostId}`); + }); + }, + + Deny: (req, res) => { + const theirId = req.params.id; + const hostId = req.session.user._id; + + User.findOneAndUpdate({"_id": hostId, "friends.user_id": theirId}, {"$set": {"friends.$.status": "denied"}}, (err) => { + if (err) { + throw err; + } + res.status(201).redirect(`/users/${hostId}`); + }); + }, + + Picture: (req, res) => { + const hostId = req.params.id; + const currentId = req.session.user._id; + + User.findById(hostId, (err, user) => { + if (currentId === hostId) { + user.save((err) => { + if (err) { + throw err; + } + req.session.user = user; + res.status(201).redirect(`/users/${hostId}`); + }); + } else { + res.status(201).redirect(`/users/${hostId}`); + } + user.picture = req.body.picture; }); }, }; diff --git a/cypress.config.cjs b/cypress.config.cjs new file mode 100644 index 000000000..7bf7bbdbb --- /dev/null +++ b/cypress.config.cjs @@ -0,0 +1,10 @@ +const { defineConfig } = require("cypress"); + +module.exports = defineConfig({ + component: { + devServer: { + framework: "node" + }, + }, + e2e: { + baseUrl: "http://localhost:3030"}}) \ No newline at end of file diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 000000000..02e425437 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/cypress/integration/home_page_spec.js b/cypress/integration/home_page_spec.js index e5fc9fdb9..62897d55b 100644 --- a/cypress/integration/home_page_spec.js +++ b/cypress/integration/home_page_spec.js @@ -1,5 +1,6 @@ describe("Home page", () => { it("has a title", () => { + cy.task("wipe_database"); cy.visit("/"); cy.get(".title").should("contain", "Acebook"); }); diff --git a/cypress/integration/user_can_like_posts_spec.js b/cypress/integration/user_can_like_posts_spec.js new file mode 100644 index 000000000..2a24401a5 --- /dev/null +++ b/cypress/integration/user_can_like_posts_spec.js @@ -0,0 +1,71 @@ +describe("Timeline Likes", () => { + it("can see likes count on a new post", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("tester@email.com"); + cy.get("#password").type("password123"); + cy.get("#submit").click(); + + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("tester@email.com"); + cy.get("#password").type("password123"); + cy.get("#submit").click(); + + // submit a post + cy.visit("/posts"); + cy.contains("New post").click(); + + cy.get("#new-post-form").find('[type="text"]').type("Testing time 1234"); + cy.get("#new-post-form").submit(); + + cy.get(".posts").should("contain", "Testing time 1234"); + + // Assert that we can see the likes count + cy.get(".posts").should("contain", "0 likes"); + cy.get("button").click(); + cy.wait(1000); + // Assert that we can see the updated likes count + cy.get(".posts").should("contain", "1 likes"); + }); + + it("can see likes count on a new post with two existing posts", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("tester@email.com"); + cy.get("#password").type("password123"); + cy.get("#submit").click(); + + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("tester@email.com"); + cy.get("#password").type("password123"); + cy.get("#submit").click(); + + + cy.visit("/posts"); + + // submit first post + cy.contains("New post").click(); + cy.get("#new-post-form").find('[type="text"]').type("Testing time 1"); + cy.get("#new-post-form").submit(); + + cy.get(".posts").should("contain", "Testing time 1"); + + // submit second post + cy.contains("New post").click(); + cy.get("#new-post-form").find('[type="text"]').type("Testing time 2"); + cy.get("#new-post-form").submit(); + + cy.get(".posts").should("contain", "Testing time 2"); + cy.get("button:first").click(); + + // Assert that we can see the likes count + cy.get(".posts").should("contain", "0 likes"); + + // Assert that we can see the updated likes count + cy.get(".posts").should("contain", "1 like"); + }); +}); diff --git a/cypress/integration/user_can_see_posts_count_on_post.js b/cypress/integration/user_can_see_posts_count_on_post.js deleted file mode 100644 index 203897aca..000000000 --- a/cypress/integration/user_can_see_posts_count_on_post.js +++ /dev/null @@ -1,28 +0,0 @@ -describe("Timeline", () => { - it("can see likes count on a new post", () => { - // sign up - cy.visit("/users/new"); - cy.get("#email").type("someone@example.com"); - cy.get("#password").type("password"); - cy.get("#submit").click(); - - // sign in - cy.visit("/sessions/new"); - cy.get("#email").type("someone@example.com"); - cy.get("#password").type("password"); - cy.get("#submit").click(); - - // submit a post - cy.visit("/posts"); - cy.contains("New post").click(); - - cy.get("#new-post-form").find('[type="text"]').type("Hello, world!"); - cy.get("#new-post-form").submit(); - - cy.get(".posts").should("contain", "Hello, world!"); - - // Assert that we can see the likes count - cy.get(".posts").should("contain", "0 likes"); - }); - }); - \ No newline at end of file diff --git a/cypress/integration/user_can_sign_in_spec.js b/cypress/integration/user_can_sign_in_spec.js index 2c2ae6d9a..6d31a3596 100644 --- a/cypress/integration/user_can_sign_in_spec.js +++ b/cypress/integration/user_can_sign_in_spec.js @@ -1,6 +1,7 @@ describe("Authentication", () => { it("A user signs in and is redirected to /posts", () => { // sign up + cy.task("wipe_database"); cy.visit("/users/new"); cy.get("#email").type("someone@example.com"); cy.get("#password").type("password"); diff --git a/cypress/integration/user_can_sign_up_spec.js b/cypress/integration/user_can_sign_up_spec.js index 7863a66e5..152751887 100644 --- a/cypress/integration/user_can_sign_up_spec.js +++ b/cypress/integration/user_can_sign_up_spec.js @@ -1,6 +1,7 @@ describe("Registration", () => { it("A user signs up and is redirected to sign in", () => { // sign up + cy.task("wipe_database"); cy.visit("/users/new"); cy.get("#email").type("someone@example.com"); cy.get("#password").type("password"); @@ -8,4 +9,70 @@ describe("Registration", () => { cy.url().should("include", "/sessions/new"); }); + + it("A user cannot sign up with blank credentials", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#submit").click(); + cy.url().should("include", "/users/new"); + }); + + it("A user cannot sign up with valid email and blank password", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#submit").click(); + cy.url().should("include", "/users/new"); + }); + + it("A user cannot sign up with a valid password and blank email", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + cy.url().should("include", "/users/new"); + }); + + it("A user cannot sign up with a password and an incomplete/invalid email", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("someone"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + cy.url().should("include", "/users/new"); + }); + + it("A user cannot sign up with a duplicate account", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + cy.url().should("include", "/sessions/new"); + + // sign up 2 + cy.visit("/users/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + // this may fail if a redirect is implemented + cy.url().should("include", "/users/new"); + }); + + + it("A user cannot sign up with a valid email and an invalid password", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("pass"); + cy.get("#password").type('{enter}'); + cy.url().should("include", "/users/new"); + }); }); diff --git a/cypress/integration/user_can_submit_comments_spec.js b/cypress/integration/user_can_submit_comments_spec.js new file mode 100644 index 000000000..d1c8adbad --- /dev/null +++ b/cypress/integration/user_can_submit_comments_spec.js @@ -0,0 +1,111 @@ +describe("Comments", () => { + it("user can create post and add comment to it", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // submit a post + cy.visit("/posts"); + cy.contains("New post").click(); + cy.get("#new-post-form").find('[type="text"]').type("Hello, world!"); + cy.get("#new-post-form").submit(); + + // add a comment + cy.contains("More details").click(); + cy.get("body").should("contain", "Hello,"); + cy.get("#message").type("Comment 1"); + cy.contains("Create").click(); + cy.get(".comments li").should("contain", "Comment 1"); + }); + + it("user can't add empty comment to post", () => { + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // attempt to add a comment + cy.contains("More details").click(); + cy.contains("Create").click(); + cy.get(".comments li").should("contain", "Comment 1"); + cy.get(".comments li").should("have.length", 1); + }); + + it("user can't add comment with just spaces to post", () => { + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // attempt to add a comment + cy.contains("More details").click(); + cy.get("#message").type(" "); + cy.contains("Create").click(); + cy.get(".comments li").should("contain", "Comment 1"); + cy.get(".comments li").should("have.length", 1); + }); + + it("user can comment on other user post", () => { + // sign up + cy.visit("/users/new"); + cy.get("#email").type("tester@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("tester@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // attempt to add a comment + cy.contains("More details").click(); + cy.get("#message").type("Comment 2"); + cy.contains("Create").click(); + cy.get(".comments li").should("contain", "Comment 2"); + cy.get(".comments li").should("have.length", 2); + }); + + it("user can navigate back to posts after visiting comments page", () => { + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("tester@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // go to comments page and add comment + cy.contains("More details").click(); + cy.get("#message").type("Comment 3"); + cy.contains("Create").click(); + + // travel back to posts + cy.contains("Posts").click(); + cy.url().should("include", "/posts"); + }); + + it("user comment is added without extra spaces", () => { + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // attempt to add a comment + cy.contains("More details").click(); + cy.get("#message").type(" Comment 4 "); + cy.contains("Create").click(); + cy.get(".comments li").eq(3).should("have.text", "Comment 4"); + cy.get(".comments li").should("have.length", 4); + }); +}); \ No newline at end of file diff --git a/cypress/integration/user_can_submit_posts_spec.js b/cypress/integration/user_can_submit_posts_spec.js index 019075937..38de1d18d 100644 --- a/cypress/integration/user_can_submit_posts_spec.js +++ b/cypress/integration/user_can_submit_posts_spec.js @@ -1,6 +1,7 @@ -describe("Timeline", () => { +describe("Timeline Posts", () => { it("can submit posts, when signed in, and view them", () => { // sign up + cy.task("wipe_database"); cy.visit("/users/new"); cy.get("#email").type("someone@example.com"); cy.get("#password").type("password"); @@ -21,4 +22,74 @@ describe("Timeline", () => { cy.get(".posts").should("contain", "Hello, world!"); }); + + it("cannot submit a blank post", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // DON'T submit a post, but press submit anyway + cy.visit("/posts"); + cy.contains("New post").click(); + cy.get("#new-post-form").submit(); + cy.url().should("include", "/posts/new"); + }); + + it("cannot submit a post as just 'spaces'", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // DON'T submit a post, but press submit anyway + cy.visit("/posts"); + cy.contains("New post").click(); + cy.get("#new-post-form").submit(); + cy.url().should("include", "/posts/new"); + + // Submit a post with just spaces - this should not post + cy.visit("/posts"); + cy.contains("New post").click(); + cy.get("#new-post-form").find('[type="text"]').type(" "); + cy.get('#new-post-form > [type="submit"]').click() + cy.url().should("include", "/posts/new"); + }); + + it("a post with extra spaces will be trimmed", () => { + // sign up + cy.task("wipe_database"); + cy.visit("/users/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + // sign in + cy.visit("/sessions/new"); + cy.get("#email").type("someone@example.com"); + cy.get("#password").type("password"); + cy.get("#submit").click(); + + cy.visit("/posts"); + cy.contains("New post").click(); + cy.get("#new-post-form").find('[type="text"]').type(" Hello, world! "); + cy.get('#new-post-form > [type="submit"]').click() + cy.get('ul').should('contain.text',"Hello, world!"); + }); }); diff --git a/cypress/plugins/index.js b/cypress/plugins/index.js index f6b2b82ce..5943c9007 100644 --- a/cypress/plugins/index.js +++ b/cypress/plugins/index.js @@ -11,7 +11,32 @@ // This function is called when a project is opened or re-opened (e.g. due to // the project's config changing) -module.exports = function() { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config +// module.exports = function() { +// // `on` is used to hook into various events Cypress emits +// // `config` is the resolved Cypress config +// } + +// var mongoose = require("mongoose"); +// require("../../spec/mongodb_helper"); +// + +const User = require("../../models/user") +const Comment = require("../../models/comment") +const Post = require("../../models/post") + +const mongoose = require("mongoose"); + +module.exports = (on) => { + on('task', { + 'wipe_database': async () => { + mongoose.connect("mongodb://0.0.0.0/acebook_test", { + useNewUrlParser: true, + useUnifiedTopology: true, + }); + await Post.deleteMany({}); + await User.deleteMany({}); + await Comment.deleteMany({}); + return null + }, + }) } diff --git a/models/comment.js b/models/comment.js new file mode 100644 index 000000000..a14f9d2c9 --- /dev/null +++ b/models/comment.js @@ -0,0 +1,13 @@ +const mongoose = require("mongoose"); + +const CommentSchema = new mongoose.Schema({ + post_id: String, + user_id: String, + message: String, + date: Date, +}); + +const Comment = mongoose.model("Comment", CommentSchema); + +module.exports = Comment; + diff --git a/models/post.js b/models/post.js index 3ef06ae2d..e10426c8d 100644 --- a/models/post.js +++ b/models/post.js @@ -2,9 +2,14 @@ const mongoose = require("mongoose"); const PostSchema = new mongoose.Schema({ message: String, - likes: { type: Number, default: 0 } + likes: { type: Number, default: 0 }, + liked_by: [], + date: Date, + user_id: String, + picture: { type: String, default: "none" }, }); const Post = mongoose.model("Post", PostSchema); module.exports = Post; + diff --git a/models/user.js b/models/user.js index 27406b498..3fe992e71 100644 --- a/models/user.js +++ b/models/user.js @@ -3,8 +3,10 @@ const mongoose = require("mongoose"); const UserSchema = new mongoose.Schema({ email: String, password: String, + friends: Array, + picture: {type: String, default: "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_1280.png"}, }); const User = mongoose.model("User", UserSchema); -module.exports = User; +module.exports = User; \ No newline at end of file diff --git a/package.json b/package.json index b0b63690e..bf221f63e 100644 --- a/package.json +++ b/package.json @@ -38,5 +38,16 @@ }, "nodemonConfig": { "ext": "js,hbs" - } + }, + "main": "app.js", + "repository": { + "type": "git", + "url": "git+https://github.com/PDyson1400/acebook-node-template.git" + }, + "keywords": [], + "author": "", + "bugs": { + "url": "https://github.com/PDyson1400/acebook-node-template/issues" + }, + "homepage": "https://github.com/PDyson1400/acebook-node-template#readme" } diff --git a/routes/posts.js b/routes/posts.js index d4ec2d937..f358a13bb 100644 --- a/routes/posts.js +++ b/routes/posts.js @@ -6,5 +6,8 @@ const PostsController = require("../controllers/posts"); router.get("/", PostsController.Index); router.post("/", PostsController.Create); router.get("/new", PostsController.New); +router.get("/:id", PostsController.Details); +router.post("/:id/create", PostsController.CreateComment); +router.post("/:id/like", PostsController.Like); module.exports = router; diff --git a/routes/users.js b/routes/users.js index 1203f91bf..328de05d0 100644 --- a/routes/users.js +++ b/routes/users.js @@ -5,5 +5,10 @@ const UsersController = require("../controllers/users"); router.get("/new", UsersController.New); router.post("/", UsersController.Create); +router.get("/:id", UsersController.Details); +router.post("/:id/request", UsersController.Request); +router.post("/:id/confirm", UsersController.Confirm); +router.post("/:id/picture", UsersController.Picture); +router.post("/:id/deny", UsersController.Deny); module.exports = router; diff --git a/spec/models/comment.spec.js b/spec/models/comment.spec.js new file mode 100644 index 000000000..4d47bd6bc --- /dev/null +++ b/spec/models/comment.spec.js @@ -0,0 +1,60 @@ +const mongoose = require("mongoose"); + +require("../mongodb_helper"); +const Comment = require("../../models/comment"); + +describe("User model", () => { + beforeEach((done) => { + mongoose.connection.collections.comments.drop(() => { + done(); + }); + }); + + it("has a post_id", () => { + const comment = new Comment({ + post_id: "63e38f8d190e0f6cef23cc0f", + user_id: "63e4dada71de08c481ac30dd", + message: "Message", + }); + expect(comment.post_id).toEqual("63e38f8d190e0f6cef23cc0f"); + }); + + it("has a user_id", () => { + const comment = new Comment({ + post_id: "63e38f8d190e0f6cef23cc0f", + user_id: "63e4dada71de08c481ac30dd", + message: "Message", + }); + expect(comment.user_id).toEqual("63e4dada71de08c481ac30dd"); + }); + + it("has a message", () => { + const comment = new Comment({ + post_id: "63e38f8d190e0f6cef23cc0f", + user_id: "63e4dada71de08c481ac30dd", + message: "Message", + }); + expect(comment.message).toEqual("Message"); + }); + + it("can save a comment", (done) => { + const comment = new Comment({ + post_id: "63e38f8d190e0f6cef23cc0f", + user_id: "63e4dada71de08c481ac30dd", + message: "Message", + }); + + comment.save((err) => { + expect(err).toBeNull(); + + Comment.find((err, posts) => { + expect(err).toBeNull(); + + expect(posts[0]).toMatchObject({ post_id: "63e38f8d190e0f6cef23cc0f", + user_id: "63e4dada71de08c481ac30dd", + message: "Message", }); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/spec/models/post.spec.js b/spec/models/post.spec.js index 3acfd48ce..4016f08a5 100644 --- a/spec/models/post.spec.js +++ b/spec/models/post.spec.js @@ -15,6 +15,12 @@ describe("Post model", () => { expect(post.message).toEqual("some message"); }); + it("has a liked_by list", () => { + var post = new Post({ message: "some message", liked_by: ["63e3dac27cf776b5b35d5b80"]}); + expect(post.message).toEqual("some message"); + expect(post.liked_by[0]).toEqual("63e3dac27cf776b5b35d5b80"); + }); + it("can list all posts", (done) => { Post.find((err, posts) => { expect(err).toBeNull(); diff --git a/spec/models/user.spec.js b/spec/models/user.spec.js index ed1c93ef5..3c6741fa4 100644 --- a/spec/models/user.spec.js +++ b/spec/models/user.spec.js @@ -26,6 +26,15 @@ describe("User model", () => { expect(user.password).toEqual("password"); }); + it("has friends", () => { + const user = new User({ + email: "someone@example.com", + password: "password", + friends: [{"status":"pending","user_id":"63e4dada71de08c481ac30dd"}] + }); + expect(user.friends[0]).toEqual({"status":"pending","user_id":"63e4dada71de08c481ac30dd"}); + }); + it("can list all users", (done) => { User.find((err, users) => { expect(err).toBeNull(); diff --git a/views/home/index.hbs b/views/home/index.hbs index 7ad30d847..fc1acc8ed 100644 --- a/views/home/index.hbs +++ b/views/home/index.hbs @@ -1,2 +1,4 @@
Welcome to {{title}}
+ +Log In \ No newline at end of file diff --git a/views/layout.hbs b/views/layout.hbs index 17645b71e..068eb6bee 100644 --- a/views/layout.hbs +++ b/views/layout.hbs @@ -5,9 +5,6 @@ - {{{body}}}