Skip to content

Commit b0ccefa

Browse files
committed
express REST API with cypress tests
0 parents  commit b0ccefa

File tree

11 files changed

+232
-0
lines changed

11 files changed

+232
-0
lines changed

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
node_modules
3+
package-lock.json
4+
.env
5+
6+

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Make Use Of
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

controllers/userControllers.js

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
2+
const users = [];
3+
4+
5+
// Create a new user object and push it into the 'users' array
6+
exports.registerUser = async (req, res) => {
7+
const { username, password } = req.body;
8+
9+
try {
10+
11+
const newUser = { username, password };
12+
users.push(newUser);
13+
14+
res.status(201).send({ message: 'User registered successfully' });
15+
} catch (error) {
16+
console.error(error);
17+
res.status(500).send({ message: 'An error occurred!!' });
18+
}
19+
};
20+
21+
// Retrieve all users
22+
exports.getUsers = async (req, res) => {
23+
try {
24+
25+
res.json(users);
26+
} catch (error) {
27+
console.error(error);
28+
res.status(500).send({ message: 'An error occurred!!' });
29+
}
30+
};
31+
32+
// Find a user with the provided username and password
33+
34+
exports.loginUser = async (req, res) => {
35+
const { username, password } = req.body;
36+
37+
try {
38+
39+
const user = users.find((u) => u.username === username && u.password === password);
40+
41+
if (user) {
42+
res.status(200).send({ message: 'Login successful' });
43+
} else {
44+
res.status(401).send({ message: 'Invalid credentials' });
45+
}
46+
} catch (error) {
47+
console.error(error);
48+
res.status(500).send({ message: 'An error occurred!!' });
49+
}
50+
};
51+

cypress.config.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const { defineConfig } = require("cypress");
2+
3+
module.exports = defineConfig({
4+
chromeWebSecurity: false,
5+
e2e: {
6+
baseUrl: 'http://localhost:5000',
7+
setupNodeEvents(on, config) {
8+
9+
},
10+
},
11+
});
12+
13+

cypress/e2e/user.routes.spec.cy.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
const baseUrl = Cypress.config().baseUrl;
3+
4+
describe('User Routes', () => {
5+
it('registers a new user', () => {
6+
cy.fixture('example').then((testUser) => {
7+
cy.request({
8+
method: 'POST',
9+
url: `${baseUrl}/v1/api/register`,
10+
body: testUser,
11+
}).then((response) => {
12+
expect(response.status).to.eq(201);
13+
expect(response.body.message).to.eq('User registered successfully');
14+
});
15+
});
16+
});
17+
18+
it('gets users data and the username matches test data', () => {
19+
cy.fixture('example').then((expectedUserData) => {
20+
cy.request({
21+
method: 'GET',
22+
url: `${baseUrl}/v1/api/users`,
23+
}).then((response) => {
24+
expect(response.status).to.eq(200);
25+
const username = response.body[0].username;
26+
expect(username).to.eq(expectedUserData.username);
27+
});
28+
});
29+
});
30+
31+
it('logs in a user', () => {
32+
cy.fixture('example').then((loginData) => {
33+
cy.request({
34+
method: 'POST',
35+
url: `${baseUrl}/v1/api/login`,
36+
body: loginData,
37+
}).then((response) => {
38+
expect(response.status).to.eq(200);
39+
});
40+
});
41+
});
42+
});

cypress/fixtures/example.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"username": "testuser",
3+
"password": "password123"
4+
}

cypress/support/commands.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// ***********************************************
2+
// This example commands.js shows you how to
3+
// create various custom commands and overwrite
4+
// existing commands.
5+
//
6+
// For more comprehensive examples of custom
7+
// commands please read more here:
8+
// https://on.cypress.io/custom-commands
9+
// ***********************************************
10+
//
11+
//
12+
// -- This is a parent command --
13+
// Cypress.Commands.add('login', (email, password) => { ... })
14+
//
15+
//
16+
// -- This is a child command --
17+
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
18+
//
19+
//
20+
// -- This is a dual command --
21+
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
22+
//
23+
//
24+
// -- This will overwrite an existing command --
25+
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })

cypress/support/e2e.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// ***********************************************************
2+
// This example support/e2e.js is processed and
3+
// loaded automatically before your test files.
4+
//
5+
// This is a great place to put global configuration and
6+
// behavior that modifies Cypress.
7+
//
8+
// You can change the location of this file or turn off
9+
// automatically serving support files with the
10+
// 'supportFile' configuration option.
11+
//
12+
// You can read more here:
13+
// https://on.cypress.io/configuration
14+
// ***********************************************************
15+
16+
// Import commands.js using ES2015 syntax:
17+
import './commands'
18+
19+
// Alternatively you can use CommonJS syntax:
20+
// require('./commands')

package.json

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "server",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "server.js",
6+
"scripts": {
7+
"test": "npx cypress open"
8+
},
9+
"author": "Gichuhi Wachira",
10+
"license": "ISC",
11+
"dependencies": {
12+
"cors": "^2.8.5",
13+
"express": "^4.18.2"
14+
},
15+
"devDependencies": {
16+
"cypress": "^13.1.0"
17+
}
18+
}

routes/userRoutes.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const express = require('express');
2+
const router = express.Router();
3+
const userControllers = require('../controllers/userControllers');
4+
5+
const baseURL = '/v1/api/';
6+
7+
router.post(baseURL + 'register', userControllers.registerUser);
8+
router.get(baseURL + 'users', userControllers.getUsers);
9+
router.post(baseURL + 'login', userControllers.loginUser);
10+
11+
module.exports = router;

server.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const express = require('express');
2+
const cors = require('cors');
3+
const app = express();
4+
const port = 5000;
5+
6+
7+
app.use(express.json());
8+
app.use(express.urlencoded({ extended: true }));
9+
app.use(cors());
10+
11+
12+
const userRoutes = require('./routes/userRoutes');
13+
14+
app.use('/', userRoutes);
15+
16+
app.listen(port, () => {
17+
console.log(`Server is listening at http://localhost:${port}`);
18+
});
19+
20+
21+
module.exports = app;

0 commit comments

Comments
 (0)