first commit
This commit is contained in:
commit
c1fc6907f7
11 changed files with 3656 additions and 0 deletions
3
.env.sample
Normal file
3
.env.sample
Normal file
|
@ -0,0 +1,3 @@
|
|||
URL=https://192.168.1.1
|
||||
ADMIN_USER=<username>
|
||||
ADMIN_PASS=<password>
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
/playwright/.auth
|
||||
.idea/
|
||||
.env
|
21
README.md
Normal file
21
README.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Difuse - Playwright
|
||||
|
||||
[](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
3353
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
30
package.json
Normal file
30
package.json
Normal 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
48
playwright.config.cjs
Normal 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
14
tests/auth.setup.js
Normal 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 });
|
||||
});
|
47
tests/dashboards/router.spec.js
Normal file
47
tests/dashboards/router.spec.js
Normal 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();
|
||||
});
|
39
tests/dashboards/telephony.spec.js
Normal file
39
tests/dashboards/telephony.spec.js
Normal 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();
|
||||
});
|
48
tests/network/guest-lan.spec.js
Normal file
48
tests/network/guest-lan.spec.js
Normal 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
45
utils/utils.js
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue