first commit

This commit is contained in:
hayzam 2024-02-07 05:32:43 +05:30
commit c1fc6907f7
Signed by: hayzam
GPG key ID: 13B4C5B544B53947
11 changed files with 3656 additions and 0 deletions

3
.env.sample Normal file
View file

@ -0,0 +1,3 @@
URL=https://192.168.1.1
ADMIN_USER=<username>
ADMIN_PASS=<password>

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth
.idea/
.env

21
README.md Normal file
View file

@ -0,0 +1,21 @@
# Difuse - Playwright
[![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg)](https://github.com/standard/semistandard)
This repo contains tests for the Difuse project using Playwright.
## Install
Make sure you have Node.js installed. Then run:
```bash
npm install
```
Copy the `.env.sample` file to `.env` and fill in the required values.
## Test
```bash
npm run test
```

3353
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

30
package.json Normal file
View file

@ -0,0 +1,30 @@
{
"name": "difuse-playwright",
"version": "1.0.0",
"description": "Playwright tests for Difuse devices",
"main": "index.js",
"type": "module",
"scripts": {
"lint": "semistandard --fix tests/**/*.js",
"test": "playwright test"
},
"husky": {
"hooks": {
"pre-commit": "npm run lint"
}
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@playwright/test": "^1.41.2",
"@types/node": "^20.11.16",
"semistandard": "^17.0.0"
},
"dependencies": {
"dotenv": "^16.4.1",
"husky": "^9.0.10",
"ip-address": "^9.0.5",
"ip-cidr": "^4.0.0"
}
}

48
playwright.config.cjs Normal file
View file

@ -0,0 +1,48 @@
// import { defineConfig, devices } from '@playwright/test';
//
// await import('dotenv/config');
const { defineConfig, devices } = require('@playwright/test');
require('dotenv').config();
module.exports = defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
use: {
ignoreHTTPSErrors: true,
baseURL: process.env.URL,
trace: 'on-first-retry'
},
projects: [
{ name: 'setup', testMatch: /.*\.setup\.js/ },
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
storageState: 'playwright/.auth/user.json'
},
dependencies: ['setup']
},
{
name: 'firefox',
use: {
...devices['Desktop Firefox'],
storageState: 'playwright/.auth/user.json'
},
dependencies: ['setup']
},
{
name: 'webkit',
use: {
...devices['Desktop Safari'],
storageState: 'playwright/.auth/user.json'
},
dependencies: ['setup']
}
]
});

14
tests/auth.setup.js Normal file
View file

@ -0,0 +1,14 @@
import { test, expect } from '@playwright/test';
const authFile = 'playwright/.auth/user.json';
test('Authenticate', async ({ page }) => {
await page.goto('/login');
await page.waitForSelector('input[name="user"]', { timeout: 3000 });
await page.fill('input[name="user"]', process.env.ADMIN_USER);
await page.fill('input[name="password"]', process.env.ADMIN_PASS);
await page.click('#subBut');
await page.waitForSelector('span:has-text("Quick Actions")', { timeout: 3000 });
expect(await page.title()).toBe('Difuse - Dashboard - Router');
await page.context().storageState({ path: authFile });
});

View file

@ -0,0 +1,47 @@
import { test, expect } from '@playwright/test';
test('Title', async ({ page }) => {
await page.goto('/');
const title = await page.title();
expect(title).toBe('Difuse - Dashboard - Router');
});
test('Top Cards', async ({ page }) => {
await page.goto('/');
const lanClients = await page.$('h4:has-text("LAN Clients")');
const wifiClients = await page.$('h4:has-text("5 GHz Clients")');
const wgEndpoints = await page.$('h4:has-text("Peers")');
expect(lanClients && wifiClients && wgEndpoints).toBeTruthy();
});
test('Basic System Information', async ({ page }) => {
await page.goto('/');
const cells = (await page.$$('.tabulator-cell')).filter(async (cell) => {
const field = await cell.getAttribute('tabulator-field');
return field === 'value';
});
const currentYear = new Date().getFullYear();
let foundFw = false;
let foundUptime = false;
for (let i = 0; i < cells.length; i++) {
const text = await cells[i].textContent();
if (text.includes('difos')) {
foundFw = true;
} else if (text.includes(currentYear.toString())) {
foundUptime = true;
}
}
expect(foundFw && foundUptime).toBe(true);
});
test('Network Information', async ({ page }) => {
await page.goto('/');
const networkInfo = await page.$('th:has-text("Network Information")');
expect(networkInfo).toBeTruthy();
});

View file

@ -0,0 +1,39 @@
import { test, expect } from '@playwright/test';
test('Title', async ({ page }) => {
await page.goto('/telephony');
const title = await page.title();
expect(title).toBe('Difuse - Dashboard - Telephony');
});
test('Top Cards', async ({ page }) => {
await page.goto('/telephony');
const sipExtensions = await page.$('h3:has-text("SIP Extensions")');
const sipTrunks = await page.$('h3:has-text("SIP Trunks")');
const currentChannels = await page.$('h3:has-text("Current Channels")');
const completedCalls = await page.$('h3:has-text("Completed Calls")');
expect(sipExtensions && sipTrunks && currentChannels && completedCalls).toBeTruthy();
});
test('Endpoint Table', async ({ page }) => {
await page.goto('/telephony');
await page.waitForSelector('.tabulator-header', { timeout: 5000 });
expect(await page.$('.tabulator-header')).toBeTruthy();
});
test('PBX Information', async ({ page }) => {
await page.goto('/telephony');
const yearRegex = /\b\d{4}\b/;
const coreReloadText = await page.textContent('td:has-text("Core Last Reload") + td');
expect(yearRegex.test(coreReloadText)).toBeTruthy();
const asteriskVersionText = await page.textContent('td:has-text("Asterisk Version") + td');
const versionRegex = /^\d+\.\d+\.\d+$/;
expect(versionRegex.test(asteriskVersionText.replaceAll(/\s/g, ''))).toBeTruthy();
const coreStartupTimeText = await page.textContent('#core-startup-time');
expect(yearRegex.test(coreStartupTimeText)).toBeTruthy();
});

View file

@ -0,0 +1,48 @@
import { test, expect } from '@playwright/test';
import { isValidMacAddress, isValidCidr } from '../../utils/utils.js';
test.beforeEach(async ({ page }) => {
await page.goto('/network/guest-lan');
await page.waitForTimeout(2500);
});
test('Title', async ({ page }) => {
const title = await page.title();
expect(title).toBe('Difuse - Network - Guest LAN');
});
test('Info Table', async ({ page }) => {
await page.waitForSelector('td:has-text("Static Address")', { timeout: 5000 });
await page.waitForTimeout(2500);
const rows = await page.$$('table > tbody > tr');
for (const row of rows) {
const cells = await row.$$('td');
if (cells.length === 2) {
const label = await cells[0].textContent();
const value = await cells[1].textContent();
if (label === 'Protocol') {
expect(value).toBe('Static Address');
} else if (label === 'Uptime') {
expect(typeof parseInt(value)).toBe('number');
} else if (label === 'MAC') {
expect(isValidMacAddress(value)).toBeTruthy();
} else if (label === 'RX' || label === 'TX') {
expect(typeof parseInt(value)).toBe('number');
} else if (label === 'IPv4') {
expect(isValidCidr(value)).toBeTruthy();
}
}
}
});
test('Bad IPv4 Form Submits', async ({ page }) => {
await page.waitForSelector('#ipAddress', {timeout: 5000})
await page.fill('#ipAddress', '111.111.111.111.111');
await page.click('button[type="submit"]');
const errorPopup = await page.waitForSelector('.swal2-popup', { state: 'visible' });
const errorText = await errorPopup.textContent();
expect(errorText).toContain('Invalid IP Address');
});

45
utils/utils.js Normal file
View file

@ -0,0 +1,45 @@
import IPCIDR from 'ip-cidr';
import IPAddress from 'ip-address';
export function isValidMacAddress (mac) {
try {
const regex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
return regex.test(mac);
} catch (error) {
return false;
}
}
export function isValidCidr (cidr, type = 0) {
let [isV4, isV6] = [false, false];
let tempCidr = null;
try {
if (type === 4) {
tempCidr = new IPCIDR(cidr);
if (tempCidr.address.v4) {
isV4 = true;
}
}
if (type === 6) {
tempCidr = new IPAddress.Address6(cidr);
if (!tempCidr.address.v4) {
isV6 = true;
}
}
if (type === 0) {
tempCidr = new IPCIDR(cidr);
if (tempCidr.address.v4) {
isV4 = true;
} else {
isV6 = true;
}
}
return isV4 || isV6;
} catch (error) {
return false;
}
}