Skip to content

Commit

Permalink
Issue 71 - add e2e (#72)
Browse files Browse the repository at this point in the history
* adding cypress

* adding test route

* updated test route

* Adding build status & license to readme

* adding badges for readme

* remove frontend test badge until we fix lint errors on frontend?

* running cypress

* added cypress

* updated readme to reflect cypress stuff

* added prod url to main readme

* changed link to prod

* ok fixed frontend linting

* ok added frontend badge to readme and fixed frontend lint
  • Loading branch information
MicahMartin authored Feb 5, 2024
1 parent 0ae25a2 commit da9820c
Show file tree
Hide file tree
Showing 16 changed files with 2,384 additions and 1,250 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[![Frontend Tests](https://github.com/wadedesir/notes-app/actions/workflows/backend_checks.yml/badge.svg)](https://github.com/wadedesir/notes-app/actions/workflows/backend_checks.yml) [![Backend Tests](https://github.com/wadedesir/notes-app/actions/workflows/frontend_checks.yml/badge.svg)](https://github.com/wadedesir/notes-app/actions/workflows/frontend_checks.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

# 📝 Notes App
Welcome to the **Notes App**, a simple and user-friendly application for managing notes. The application is powered by a backend API and a frontend interface. Explore the details of each component below:
Welcome to [**Notes.app**](http://18.116.34.64:8420/), a simple and user-friendly application for managing notes. The application is powered by a backend API and a frontend interface. Explore the details of each component below:

## 🌐 Frontend

Expand All @@ -21,4 +23,4 @@ A key objective of this project was learning and implementing tests. The READMEs
4. Explore, manage your notes, and enjoy using the Notes App!

## Made with love,
Jose, Kai, Sarah, Wade, & Zrybea ✨
Jose, Kai, Sarah, Wade, & Zrybea ✨
1 change: 1 addition & 0 deletions backend/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ services:
DB_NAME: my_db
TEST_DB_NAME: jest_test_db
SECRET: foobar
NODE_ENV: ${NODE_ENV}
depends_on:
- mongo_db

Expand Down
8 changes: 6 additions & 2 deletions backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import cors from 'cors'
import NoteRouter from './routes/NoteRouter.js'
import UserRouter from './routes/UserRouter.js'
import LoginRouter from './routes/LoginRouter.js'
import TestRouter from './routes/TestRouter.js'

import { initDb } from './util/db_util.js'
import { logInfo } from './util/logger.js'
Expand All @@ -15,7 +16,7 @@ import {
} from './util/middleware.js'

// Init mongoDB and create the server.
logInfo('Server starting')
logInfo(`server starting, NODE_ENV=${process.env.NODE_ENV}`)
initDb()
const Server = express()

Expand All @@ -29,7 +30,10 @@ Server.use(requestLogger)
Server.use('/v1/notes', NoteRouter)
Server.use('/v1/users', UserRouter)
Server.use('/v1/login', LoginRouter)

// Only on dev!!!!
if (process.env.NODE_ENV === 'e2e') {
Server.use('/v1/test', TestRouter)
}
// Set up post-request middleware
Server.use(errorHandler)
Server.use(unknownEndpointHandler)
Expand Down
22 changes: 22 additions & 0 deletions backend/routes/TestRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import express from 'express'
import Note from '../models/Note.js'
import User from '../models/User.js'

/**
* Express router for handling test-related HTTP requests.
* DONT EXPOSE ON PROD PLS :)
* @type {express.Router}
*/
const TestingRouter = express.Router()

/**
* Route to delete everything out the db.
*/
TestingRouter.get('/reset', async (req, res) => {
await Note.deleteMany({})
await User.deleteMany({})

res.status(204).end()
})

export default TestingRouter
4 changes: 3 additions & 1 deletion frontend/.eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = {
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
ignorePatterns: ['dist', '.eslintrc.cjs', 'cypress*', '*.test.js', 'coverage'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],
Expand All @@ -16,5 +16,7 @@ module.exports = {
'warn',
{ allowConstantExport: true },
],
"react/prop-types": "off",
"react/no-unescaped-entities": "off",
},
}
3 changes: 2 additions & 1 deletion frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
cypress/screenshots/
src/coverage
coverage
coverage
19 changes: 17 additions & 2 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,22 @@ Welcome to the **Notes App Frontend**. Powered by React, Vite.js, and Tailwind C
### 🧪 Testing & Linting
Whenever a new PR is made, tests are run automatically through GitHub Actions (check out the .github/workflows folder at the root of the repo).

NEED MORE DOCUMENTATION HERE
## 🔚 End To End Tests
End-to-end testing for the Notes App is conducted using Cypress, a modern testing framework for web applications. Cypress provides a powerful set of tools for writing, running, and debugging tests, making it ideal for ensuring the application works as expected from a user's perspective.

## 🚀 Running End to End Tests
To run the Cypress end-to-end tests locally, follow these steps:

1. Make sure the frontend & backend servers are running. If not, start it by running `npm run dev` in the `frontend` directory & `export NODE_ENV=e2e && docker-compose up` in the `backend` directory.
2. Navigate to frontend directory & run Cypress by executing the command `npm run cypress:open` to run the e2e tests visually or `npm run test:e2e` to run them in headless mode.

## 🧪 End to End Test Coverage
The Cypress end-to-end tests cover various scenarios to ensure the functionality and integrity of the Notes App. Here's an overview of what the tests cover:

- **Front Page Interaction**: Verifies that the front page can be opened and the login form is accessible.
- **Login Functionality**: Tests the login form's functionality, ensuring users can log in successfully.
- **Note Management**: Validates that users can create new notes, mark notes as important, and perform other note-related actions.
- **User Authentication**: Ensures that login fails with incorrect credentials.

### 🗂 Frontend File Structure
```
Expand Down Expand Up @@ -55,4 +70,4 @@ The Login page includes a login form for users to authenticate. It also provides
The SignUp page includes a signup form for users to create a new account. It also provides a link to the login page for existing users.

### 💻 App
The App component sets up the routing for the application using react-router-dom. It includes routes for the home page, login, and signup pages.
The App component sets up the routing for the application using react-router-dom. It includes routes for the home page, login, and signup pages.
9 changes: 9 additions & 0 deletions frontend/cypress.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineConfig } from "cypress";

export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});
60 changes: 60 additions & 0 deletions frontend/cypress/e2e/note_app.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
describe('Notes App', function() {
// Before each function, we should hard reset everything in the database
beforeEach(function() {
cy.request('GET','http://localhost:8420/v1/test/reset')
const user = {
name: 'test_user',
username: 'test_user',
password: 'test_password'
}
cy.request('POST', 'http://localhost:8420/v1/users', user)
cy.visit('http://localhost:5173')
})

// Front page should be the log in page at this point
it('front page can be opened', function() {
cy.contains('Sign up')
})

it('login form can be opened', function() {
cy.get('input:first').type('test_user')
cy.get('input:last').type('test_password')
cy.contains('Login').click()

// if we see the 'ADD' button, that means we've logged in.
cy.contains('Add')
})

describe('when logged in', function() {
beforeEach(function() {
cy.login({ username: 'test_user', password: 'test_password' })
})

it('a new note can be created', function() {
cy.get('input:first').type('jobava london is fun')
cy.contains('Add').click()
cy.contains('jobava london is fun')
})

describe('and a note exists', function () {
beforeEach(function () {
cy.createNote({ content: 'Kings indian samisch variation is fun', important: false})
cy.createNote({ content: 'Modern scandi is fun', important: false})
cy.createNote({ content: 'portugese / icelandic gambit is fun', important: false})
})

it('one of those can be made important', function () {
cy.contains('samisch').parent().trigger('mouseover')
cy.get('#pin_button').click()
})
})
})

// it('login fails with wrong password', function() {
// cy.get('input:first').type('test_user')
// cy.get('input:last').type('test_ass_word')
// cy.contains('Login').click()

// // We dont have an error message yet 🥲
// })
})
5 changes: 5 additions & 0 deletions frontend/cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "[email protected]",
"body": "Fixtures are a great way to mock data for responses to routes"
}
47 changes: 47 additions & 0 deletions frontend/cypress/support/commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

Cypress.Commands.add('login', ({ username, password }) => {
cy.request('POST', 'http://localhost:8420/v1/login', {
username, password
}).then(({ body }) => {
localStorage.setItem('token', body.token)
cy.visit('http://localhost:5173/home')
})
})

Cypress.Commands.add('createNote', ({ content, important }) => {
cy.request({
url: 'http://localhost:8420/v1/notes',
method: 'POST',
body: { content, important },
headers: {
'Authorization': `Bearer ${localStorage.token}`
}
})

cy.visit('http://localhost:5173/home')
})
20 changes: 20 additions & 0 deletions frontend/cypress/support/e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/e2e.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************

// Import commands.js using ES2015 syntax:
import './commands'

// Alternatively you can use CommonJS syntax:
// require('./commands')
Loading

0 comments on commit da9820c

Please sign in to comment.