Skip to content

Commit

Permalink
e2e
Browse files Browse the repository at this point in the history
  • Loading branch information
ELEF-TQ committed Dec 14, 2024
1 parent 2c764f1 commit bf949c6
Show file tree
Hide file tree
Showing 10 changed files with 2,574 additions and 38 deletions.
9 changes: 0 additions & 9 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
name: Build and Deploy

on:
push:
branches: [ci/cd]
pull_request:
branches: [ci/cd]

env:
MONGODB_URI: ${{ secrets.MONGODB_URI }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
DB_TYPE: ${{ secrets.DB_TYPE }}
HOST_NAME: ${{ secrets.HOST_NAME }}
DOCKER_DB_HOST_NAME: ${{ secrets.DOCKER_DB_HOST_NAME }}
DB_NAME: ${{ secrets.DB_NAME }}

jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2

- name: Install and Test Client
working-directory: ./client
run: |
yarn install
- name: Install and Test Server
working-directory: ./server
run: |
Expand All @@ -36,23 +31,19 @@ jobs:
export HOST_NAME=$HOST_NAME
export DOCKER_DB_HOST_NAME=$DOCKER_DB_HOST_NAME
export DB_NAME=$DB_NAME
- name: Build Client Docker Image
working-directory: ./client
run: |
docker build --no-cache -t eleftq/pfa_fikralabs-client:${{ github.run_number }} .
- name: Build Server Docker Image
working-directory: ./server
run: |
docker build --no-cache -t eleftq/pfa_fikralabs-server:${{ github.run_number }} .
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Push Docker Images to Docker Hub
run: |
docker push eleftq/pfa_fikralabs-client:${{ github.run_number }}
Expand Down
14 changes: 5 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,40 @@
name: Run Tests

on:
push:
branches: [ci/cd]
pull_request:
branches: [ci/cd]

env:
MONGODB_URI: ${{ secrets.MONGODB_URI }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
DB_TYPE: ${{ secrets.DB_TYPE }}
HOST_NAME: ${{ secrets.HOST_NAME }}
DOCKER_DB_HOST_NAME: ${{ secrets.DOCKER_DB_HOST_NAME }}
DB_NAME: ${{ secrets.DB_NAME }}

jobs:
test:
runs-on: ubuntu-latest

steps:
# Step 1: Checkout Code
- name: Checkout Code
uses: actions/checkout@v2

# Step 2: Install and Test Client
- name: Install and Test Client
working-directory: ./client
run: |
yarn install # Install dependencies using Yarn
yarn install
yarn test # Run unit tests with Yarn
# Step 3: Install and Test Server
- name: Install and Test Server
working-directory: ./server
run: |
yarn install # Install dependencies using Yarn
yarn install
export MONGODB_URI=$MONGODB_URI
export JWT_SECRET=$JWT_SECRET
export DB_TYPE=$DB_TYPE
export HOST_NAME=$HOST_NAME
export DOCKER_DB_HOST_NAME=$DOCKER_DB_HOST_NAME
export DB_NAME=$DB_NAME
yarn test # Run unit tests with Yarn
yarn test # Run unit tests with Yarn
5 changes: 5 additions & 0 deletions client/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};

12 changes: 11 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"dev": "vite --host",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
"preview": "vite preview",
"test": "jest"
},
"dependencies": {
"@emotion/react": "^11.11.4",
Expand Down Expand Up @@ -45,18 +46,22 @@
"react-spinners": "^0.13.8",
"react-time-picker": "^6.6.0",
"react-toastify": "^10.0.5",
"selenium-webdriver": "^4.27.0",
"styled-components": "^6.1.8",
"sweetalert2": "^11.10.5",
"toastify-react": "^4.3.1",
"tw-elements": "^1.1.0"
},
"devDependencies": {
"@types/crypto-js": "^4.2.2",
"@types/jest": "^29.5.14",
"@types/js-cookie": "^3.0.6",
"@types/mocha": "^10.0.10",
"@types/react": "^18.2.56",
"@types/react-datepicker": "^6.0.3",
"@types/react-dom": "^18.2.19",
"@types/react-modal": "^3.16.3",
"@types/selenium-webdriver": "^4.1.27",
"@typescript-eslint/eslint-plugin": "^7.0.2",
"@typescript-eslint/parser": "^7.0.2",
"@vitejs/plugin-react-swc": "^3.5.0",
Expand All @@ -65,8 +70,13 @@
"eslint": "^8.56.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.5",
"jest": "^29.7.0",
"mocha": "^11.0.1",
"postcss": "^8.4.35",
"tailwindcss": "^3.4.1",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"tsx": "^4.19.2",
"typescript": "^5.2.2",
"vite": "^5.1.4"
}
Expand Down
50 changes: 50 additions & 0 deletions client/tests/e2e/login.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Builder, By, until } from 'selenium-webdriver';
import { Key } from 'selenium-webdriver';

describe('Login Page', () => {
let driver: any;

beforeAll(async () => {
driver = await new Builder().forBrowser('chrome').build();
});

afterAll(async () => {
await driver.quit();
});

it('should login successfully with valid credentials', async () => {
await driver.get('http://localhost:5173/login');

await driver.wait(until.elementLocated(By.id('email')), 5000);
const emailInput = await driver.findElement(By.id('email'));
await emailInput.sendKeys('testuser@example.com');

const passwordInput = await driver.findElement(By.id('password'));
await passwordInput.sendKeys('password123');

const loginButton = await driver.findElement(By.css('button[type="submit"]'));
await loginButton.click();

await driver.wait(until.elementLocated(By.css('h1')), 5000);
const currentUrl = await driver.getCurrentUrl();
expect(currentUrl).toBe('http://localhost:5173/dashboard');
});

it('should display error message with invalid credentials', async () => {
await driver.get('http://localhost:5173/login');

await driver.wait(until.elementLocated(By.id('email')), 5000);
const emailInput = await driver.findElement(By.id('email'));
await emailInput.sendKeys('invaliduser@example.com');

const passwordInput = await driver.findElement(By.id('password'));
await passwordInput.sendKeys('wrongpassword');

const loginButton = await driver.findElement(By.css('button[type="submit"]'));
await loginButton.click();

await driver.wait(until.elementLocated(By.css('.error-message')), 5000); // Update with your error element's class
const errorMessage = await driver.findElement(By.css('.error-message')).getText();
expect(errorMessage).toBe('Invalid email or password');
});
});
34 changes: 34 additions & 0 deletions client/tests/e2e/logout.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Builder, By, until } from 'selenium-webdriver';
import Swal from 'sweetalert2';

describe('Logout Functionality', () => {
let driver: any;

beforeAll(async () => {
driver = await new Builder().forBrowser('chrome').build();
});

afterAll(async () => {
await driver.quit();
});

it('should show a logout confirmation and logout the user', async () => {
// Simulate logged-in state
await driver.get('http://localhost:5173/');
const userProfileButton = await driver.findElement(By.css('.sidebar__logo'));
await userProfileButton.click();

// Click on the logout button
const logoutButton = await driver.findElement(By.css('button.logout'));
await logoutButton.click();

// Simulate the confirmation dialog (you can customize this part based on your Swal implementation)
const confirmButton = await driver.findElement(By.css('.swal2-confirm'));
await confirmButton.click();

// Verify redirection to login page after logout
await driver.wait(until.urlContains('/login'), 5000);
const currentUrl = await driver.getCurrentUrl();
expect(currentUrl).toBe('http://localhost:5173/login');
});
});
58 changes: 58 additions & 0 deletions client/tests/e2e/navbar.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Builder, By, until } from 'selenium-webdriver';

describe('Navbar Navigation', () => {
let driver: any;

beforeAll(async () => {
driver = await new Builder().forBrowser('chrome').build();
});

afterAll(async () => {
await driver.quit();
});

it('should navigate to login page', async () => {
await driver.get('http://localhost:5173/');

const loginLink = await driver.findElement(By.linkText('Connexion'));
await loginLink.click();

await driver.wait(until.urlContains('/login'), 5000);
const currentUrl = await driver.getCurrentUrl();
expect(currentUrl).toBe('http://localhost:5173/login');
});

it('should navigate to signup page', async () => {
await driver.get('http://localhost:5173/');

const signupLink = await driver.findElement(By.linkText('S’inscrire'));
await signupLink.click();

await driver.wait(until.urlContains('/signup'), 5000);
const currentUrl = await driver.getCurrentUrl();
expect(currentUrl).toBe('http://localhost:5173/signup');
});

it('should navigate to evaluation page when user is not logged in', async () => {
await driver.get('http://localhost:5173/');

const evaluationLink = await driver.findElement(By.linkText('Évaluation'));
await evaluationLink.click();

await driver.wait(until.urlContains('/evaluation'), 5000);
const currentUrl = await driver.getCurrentUrl();
expect(currentUrl).toBe('http://localhost:5173/evaluation');
});

it('should navigate to profile page when user is logged in', async () => {
await driver.get('http://localhost:5173/');

const user = { role: 'ADMIN' }; // Simulate a logged-in user
const userProfileLink = await driver.findElement(By.linkText(user.role.toLowerCase()));
await userProfileLink.click();

await driver.wait(until.urlContains(`/${user.role.toLowerCase()}/profile`), 5000);
const currentUrl = await driver.getCurrentUrl();
expect(currentUrl).toBe(`http://localhost:5173/${user.role.toLowerCase()}/profile`);
});
});
34 changes: 34 additions & 0 deletions client/tests/e2e/password-visibility.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Builder, By, until } from 'selenium-webdriver';

describe('Show Password Functionality', () => {
let driver: any;

beforeAll(async () => {
driver = await new Builder().forBrowser('chrome').build();
});

afterAll(async () => {
await driver.quit();
});

it('should toggle password visibility when clicked', async () => {
await driver.get('http://localhost:3000/login');

await driver.wait(until.elementLocated(By.id('password')), 5000);
const passwordInput = await driver.findElement(By.id('password'));

let inputType = await passwordInput.getAttribute('type');
expect(inputType).toBe('password');

const showPasswordButton = await driver.findElement(By.css('button[type="button"]'));
await showPasswordButton.click();

inputType = await passwordInput.getAttribute('type');
expect(inputType).toBe('text'); // Password should be visible after clicking

await showPasswordButton.click(); // Toggle back

inputType = await passwordInput.getAttribute('type');
expect(inputType).toBe('password');
});
});
4 changes: 3 additions & 1 deletion client/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"esModuleInterop": true,


/* Bundler mode */
"moduleResolution": "bundler",
Expand All @@ -20,6 +22,6 @@
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
},
"include": ["src"],
"include": ["src","tests"],
"references": [{ "path": "./tsconfig.node.json" }]
}
Loading

0 comments on commit bf949c6

Please sign in to comment.