mirror of
https://github.com/hiteshchoudhary/apihub.git
synced 2025-12-05 18:46:17 -06:00
feat: add test cases for health check and todo app
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -134,6 +134,7 @@ logs
|
||||
|
||||
/tmp
|
||||
/.vscode
|
||||
/.idea
|
||||
|
||||
# ignore the image files uploaded in the public/images folder
|
||||
/public/images/*
|
||||
|
||||
139
e2e/apps/todos.test.js
Normal file
139
e2e/apps/todos.test.js
Normal file
@@ -0,0 +1,139 @@
|
||||
import { test, expect, request } from "@playwright/test";
|
||||
import { getApiContext } from "../common.js";
|
||||
let apiContext;
|
||||
|
||||
let todoId = null;
|
||||
|
||||
test.beforeAll(async ({ playwright }) => {
|
||||
apiContext = await getApiContext(playwright);
|
||||
});
|
||||
|
||||
test.afterAll(async ({}) => {
|
||||
await apiContext.dispose();
|
||||
});
|
||||
|
||||
test.describe("GET:/api/v1/todos - Get All Todos", () => {
|
||||
test("should return all todos", async () => {
|
||||
const res = await apiContext.get(`/api/v1/todos`);
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(200);
|
||||
expect(json.data.length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("POST:/api/v1/todos - Create Todo", () => {
|
||||
test("should create todo with valid data", async () => {
|
||||
const todo = {
|
||||
title: "test-todo-title",
|
||||
description: "test-todo-description",
|
||||
};
|
||||
const res = await apiContext.post(`/api/v1/todos`, {
|
||||
data: todo,
|
||||
});
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(201);
|
||||
expect(json.statusCode).toEqual(201);
|
||||
expect(json.data).toMatchObject(todo);
|
||||
todoId = json.data._id;
|
||||
});
|
||||
|
||||
test("should return a 422 with title error when `title` is not provided", async () => {
|
||||
const todo = {};
|
||||
const res = await apiContext.post(`/api/v1/todos`, {
|
||||
data: todo,
|
||||
});
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(422);
|
||||
expect(json.statusCode).toEqual(422);
|
||||
expect(json.errors).toContainEqual(
|
||||
expect.objectContaining({ title: expect.anything() })
|
||||
);
|
||||
});
|
||||
|
||||
test("should return a 422 with title and description error when `title` and `description` is empty", async () => {
|
||||
const todo = { title: "", description: "" };
|
||||
const res = await apiContext.post(`/api/v1/todos`, {
|
||||
data: todo,
|
||||
});
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(422);
|
||||
expect(json.statusCode).toEqual(422);
|
||||
expect(json.errors).toContainEqual(
|
||||
expect.objectContaining({ title: expect.anything() })
|
||||
);
|
||||
expect(json.errors).toContainEqual(
|
||||
expect.objectContaining({ description: expect.anything() })
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("PATCH:/api/v1/todos/:id - Update Todo", () => {
|
||||
const todo = {
|
||||
title: "update-test-todo-title",
|
||||
description: "update-test-todo-description",
|
||||
};
|
||||
|
||||
test("should update todo with valid data", async () => {
|
||||
const res = await apiContext.patch(`/api/v1/todos/${todoId}`, {
|
||||
data: todo,
|
||||
});
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(200);
|
||||
expect(json.statusCode).toEqual(200);
|
||||
expect(json.data).toMatchObject(todo);
|
||||
});
|
||||
|
||||
test("should return a 422 with title and description error when `title` and `description` is empty", async () => {
|
||||
const todo = { title: "", description: "" };
|
||||
const res = await apiContext.patch(`/api/v1/todos/${todoId}`, {
|
||||
data: todo,
|
||||
});
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(422);
|
||||
expect(json.statusCode).toEqual(422);
|
||||
expect(json.errors).toContainEqual(
|
||||
expect.objectContaining({ title: expect.anything() })
|
||||
);
|
||||
expect(json.errors).toContainEqual(
|
||||
expect.objectContaining({ description: expect.anything() })
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("PATCH:/api/v1/todos/toggle/status/:id - Toggle todo status", () => {
|
||||
test("should toggle todo status", async () => {
|
||||
const res = await apiContext.patch(`/api/v1/todos/toggle/status/${todoId}`);
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(200);
|
||||
expect(json.statusCode).toEqual(res.status());
|
||||
expect(json.data.isComplete).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("GET:/api/v1/todos - Get All Todos", () => {
|
||||
test("should return todo when valid id passed", async () => {
|
||||
const res = await apiContext.get(`/api/v1/todos/${todoId}`);
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(200);
|
||||
expect(json.statusCode).toEqual(res.status());
|
||||
});
|
||||
|
||||
test("should return 422 with todoId error when invalid id passed", async () => {
|
||||
const res = await apiContext.get(`/api/v1/todos/__1`);
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(422);
|
||||
expect(json.statusCode).toEqual(res.status());
|
||||
expect(json.errors).toContainEqual(
|
||||
expect.objectContaining({ todoId: expect.anything() })
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe("DELETE:/api/v1/todos/:id - Delete Todo", () => {
|
||||
test("should delete todo", async () => {
|
||||
const res = await apiContext.delete(`/api/v1/todos/${todoId}`);
|
||||
const json = await res.json();
|
||||
expect(res.status()).toEqual(200);
|
||||
expect(json.statusCode).toEqual(res.status());
|
||||
});
|
||||
});
|
||||
12
e2e/common.js
Normal file
12
e2e/common.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import dotenv from "dotenv";
|
||||
|
||||
dotenv.config({
|
||||
path: "../.env",
|
||||
});
|
||||
|
||||
export const URL = `http://localhost:${process.env.PORT || 8080}`;
|
||||
|
||||
export const getApiContext = async (playwright) =>
|
||||
playwright.request.newContext({
|
||||
baseURL: URL,
|
||||
});
|
||||
17
e2e/healthcheck.test.js
Normal file
17
e2e/healthcheck.test.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
import { getApiContext, URL } from "./common.js";
|
||||
|
||||
let apiContext;
|
||||
|
||||
test.beforeAll(async ({ playwright }) => {
|
||||
apiContext = await getApiContext(playwright);
|
||||
});
|
||||
|
||||
test.afterAll(async ({}) => {
|
||||
await apiContext.dispose();
|
||||
});
|
||||
|
||||
test("should return ok", async ({ page }) => {
|
||||
const res = await apiContext.get(`/api/v1/healthcheck`);
|
||||
expect(res.ok()).toBeTruthy();
|
||||
});
|
||||
62
e2e/test-server.js
Normal file
62
e2e/test-server.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import dotenv from "dotenv";
|
||||
import { httpServer } from "../src/app.js";
|
||||
import mongoose from "mongoose";
|
||||
import { MongoMemoryServer } from "mongodb-memory-server";
|
||||
|
||||
dotenv.config({
|
||||
path: "../.env",
|
||||
});
|
||||
|
||||
let mongoServer = null;
|
||||
let dbInstance = undefined;
|
||||
const PORT = process.env.PORT || 8080;
|
||||
|
||||
const connectDB = async () => {
|
||||
try {
|
||||
await mongoose.disconnect();
|
||||
mongoServer = await MongoMemoryServer.create();
|
||||
dbInstance = await mongoose.connect(`${mongoServer.getUri()}`);
|
||||
await clearDB();
|
||||
} catch (error) {
|
||||
console.log("MongoDB connection error: ", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
export const clearDB = async () => {
|
||||
const collections = mongoose.connection.collections;
|
||||
|
||||
for (const key in collections) {
|
||||
const collection = collections[key];
|
||||
await collection.deleteMany({});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Starting from Node.js v14 top-level await is available and it is only available in ES modules.
|
||||
* This means you can not use it with common js modules or Node version < 14.
|
||||
*/
|
||||
const majorNodeVersion = +process.env.NODE_VERSION?.split(".")[0] || 0;
|
||||
|
||||
const startServer = () => {
|
||||
httpServer.listen(PORT, () => {
|
||||
console.info(`📑 Visit the documentation at: http://localhost:${PORT}`);
|
||||
console.log("⚙️ Server is running on port: " + PORT);
|
||||
});
|
||||
};
|
||||
|
||||
if (majorNodeVersion >= 14) {
|
||||
try {
|
||||
await connectDB();
|
||||
startServer();
|
||||
} catch (err) {
|
||||
console.log("Mongo db connect error: ", err);
|
||||
}
|
||||
} else {
|
||||
connectDB()
|
||||
.then(() => {
|
||||
startServer();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("Mongo db connect error: ", err);
|
||||
});
|
||||
}
|
||||
@@ -8,7 +8,9 @@
|
||||
"start": "nodemon -r dotenv/config --experimental-json-modules src/index.js",
|
||||
"pre-commit": "lint-staged",
|
||||
"prepare": "node prepare.js",
|
||||
"test": "NODE_OPTIONS=--experimental-vm-modules npx jest"
|
||||
"test": "NODE_OPTIONS=--experimental-vm-modules npx jest",
|
||||
"start:test-server": "node -r dotenv/config --experimental-json-modules e2e/test-server.js",
|
||||
"test:playwright": "set NODE_OPTIONS=--experimental-vm-modules && npx playwright test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -41,6 +43,7 @@
|
||||
"express-validator": "^7.0.1",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"mailgen": "^2.0.27",
|
||||
"mongodb-memory-server": "^9.1.6",
|
||||
"mongoose": "^7.4.0",
|
||||
"mongoose-aggregate-paginate-v2": "^1.0.6",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
|
||||
@@ -13,7 +13,7 @@ import { defineConfig, devices } from "@playwright/test";
|
||||
export default defineConfig({
|
||||
testDir: "./e2e",
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
// fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
@@ -25,54 +25,54 @@ export default defineConfig({
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
// baseURL: 'http://127.0.0.1:3000',
|
||||
// baseURL: `http://127.0.0.1:${process.env.PORT || 8080}`,
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
|
||||
{
|
||||
name: "firefox",
|
||||
use: { ...devices["Desktop Firefox"] },
|
||||
},
|
||||
|
||||
{
|
||||
name: "webkit",
|
||||
use: { ...devices["Desktop Safari"] },
|
||||
},
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
// projects: [
|
||||
// {
|
||||
// name: "chromium",
|
||||
// use: { ...devices["Desktop Chrome"] },
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// name: "firefox",
|
||||
// use: { ...devices["Desktop Firefox"] },
|
||||
// },
|
||||
//
|
||||
// {
|
||||
// name: "webkit",
|
||||
// use: { ...devices["Desktop Safari"] },
|
||||
// },
|
||||
//
|
||||
// /* Test against mobile viewports. */
|
||||
// // {
|
||||
// // name: 'Mobile Chrome',
|
||||
// // use: { ...devices['Pixel 5'] },
|
||||
// // },
|
||||
// // {
|
||||
// // name: 'Mobile Safari',
|
||||
// // use: { ...devices['iPhone 12'] },
|
||||
// // },
|
||||
//
|
||||
// /* Test against branded browsers. */
|
||||
// // {
|
||||
// // name: 'Microsoft Edge',
|
||||
// // use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// // },
|
||||
// // {
|
||||
// // name: 'Google Chrome',
|
||||
// // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// // },
|
||||
// ],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
// webServer: {
|
||||
// command: 'npm run start',
|
||||
// url: 'http://127.0.0.1:3000',
|
||||
// reuseExistingServer: !process.env.CI,
|
||||
// },
|
||||
webServer: {
|
||||
command: "npm run start:test-server",
|
||||
url: `http://localhost:${process.env.PORT || 8080}`,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user