-
+
{intl.getMessage('logout')}
diff --git a/client_v2/src/components/Settings/LogsConfig/Form.tsx b/client_v2/src/components/Settings/LogsConfig/Form.tsx
index 024e0b42..e86f7eec 100644
--- a/client_v2/src/components/Settings/LogsConfig/Form.tsx
+++ b/client_v2/src/components/Settings/LogsConfig/Form.tsx
@@ -131,7 +131,7 @@ export const Form = ({ initialValues, processing, processingReset, onSubmit, onR
-
+
{t('sign_in')}
diff --git a/client_v2/tests/e2e/control-panel.spec.ts b/client_v2/tests/e2e/control-panel.spec.ts
index 9a4cace1..88694bf9 100644
--- a/client_v2/tests/e2e/control-panel.spec.ts
+++ b/client_v2/tests/e2e/control-panel.spec.ts
@@ -4,31 +4,20 @@ import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
test.describe('Control Panel', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login.html');
- await page.getByTestId('username').click();
- await page.getByTestId('username').fill(ADMIN_USERNAME);
- await page.getByTestId('password').click();
- await page.getByTestId('password').fill(ADMIN_PASSWORD);
+ await page.locator('#username').click();
+ await page.locator('#username').fill(ADMIN_USERNAME);
+ await page.locator('#password').click();
+ await page.locator('#password').fill(ADMIN_PASSWORD);
await page.keyboard.press('Tab');
- await page.getByTestId('sign_in').click();
+ await page.locator('#sign_in').click();
await page.waitForURL((url) => !url.href.endsWith('/login.html'));
});
test('should sign out successfully', async ({ page }) => {
- await page.getByTestId('sign_out').click();
+ await page.locator('#sign_out').click();
await page.waitForURL((url) => url.href.endsWith('/login.html'));
- await expect(page.getByTestId('sign_in')).toBeVisible();
- });
-
- test('should change theme to dark and then light', async ({ page }) => {
- await page.getByTestId('theme_dark').click();
-
- await expect(page.locator('body[data-theme="dark"]')).toBeVisible();
-
-
- await page.getByTestId('theme_light').click();
-
- await expect(page.locator('body:not([data-theme="dark"])')).toBeVisible();
+ await expect(page.locator('#sign_in')).toBeVisible();
});
});
diff --git a/client_v2/tests/e2e/dhcp.spec.ts b/client_v2/tests/e2e/dhcp.spec.ts
deleted file mode 100644
index 1c5465e2..00000000
--- a/client_v2/tests/e2e/dhcp.spec.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import { test, expect } from '@playwright/test';
-import { ADMIN_PASSWORD, ADMIN_USERNAME } from '../constants';
-import { getDHCPConfig } from '../helpers/network';
-
-const dhcpConfig = getDHCPConfig();
-const INTERFACE_NAME = dhcpConfig.interfaceName;
-const RANGE_START = dhcpConfig.rangeStart;
-const RANGE_END = dhcpConfig.rangeEnd;
-const SUBNET_MASK = dhcpConfig.subnetMask;
-const LEASE_TIME = '86400';
-
-test.describe('DHCP Configuration', () => {
- test.beforeEach(async ({ page }) => {
- await page.goto('/login.html');
- await page.getByTestId('username').click();
- await page.getByTestId('username').fill(ADMIN_USERNAME);
- await page.getByTestId('password').click();
- await page.getByTestId('password').fill(ADMIN_PASSWORD);
- await page.keyboard.press('Tab');
- await page.getByTestId('sign_in').click();
- await page.waitForURL((url) => !url.href.endsWith('/login.html'));
- await page.goto(`/#dhcp`);
- });
-
- test('should select the correct DHCP interface', async ({ page }) => {
- await page.getByTestId('interface_name').selectOption(INTERFACE_NAME);
- expect(await page.locator('select[name="interface_name"]').inputValue()).toBe(INTERFACE_NAME);
- });
-
- test('should configure DHCP IPv4 settings correctly', async ({ page }) => {
- await page.getByTestId('interface_name').selectOption(INTERFACE_NAME);
- await page.getByTestId('v4_gateway_ip').click();
- await page.getByTestId('v4_gateway_ip').fill('192.168.1.99');
- await page.getByTestId('v4_subnet_mask').click();
- await page.getByTestId('v4_subnet_mask').fill(SUBNET_MASK);
- await page.getByTestId('v4_range_start').click();
- await page.getByTestId('v4_range_start').fill(RANGE_START);
- await page.getByTestId('v4_range_end').click();
- await page.getByTestId('v4_range_end').fill(RANGE_END);
- await page.getByTestId('v4_lease_duration').click();
- await page.getByTestId('v4_lease_duration').fill(LEASE_TIME);
- await page.getByTestId('v4_save').click();
- });
-
- test('should show error for invalid DHCP IPv4 range', async ({ page }) => {
- await page.getByTestId('interface_name').selectOption(INTERFACE_NAME);
- await page.getByTestId('v4_range_start').click();
- await page.getByTestId('v4_range_start').fill(RANGE_END);
- await page.getByTestId('v4_range_end').click();
- await page.getByTestId('v4_range_end').fill(RANGE_START);
- await page.keyboard.press('Tab');
-
- expect(await page.getByText('Must be greater than range').isVisible()).toBe(true);
- });
-
- test('should show error for invalid DHCP IPv4 address', async ({ page }) => {
- await page.getByTestId('interface_name').selectOption(INTERFACE_NAME);
- await page.getByTestId('v4_gateway_ip').click();
- await page.getByTestId('v4_gateway_ip').fill('192.168.1.200s');
- await page.keyboard.press('Tab');
-
- expect(await page.getByText('Invalid IPv4 address').isVisible()).toBe(true);
- });
-});
diff --git a/client_v2/tests/e2e/dns-settings.spec.ts b/client_v2/tests/e2e/dns-settings.spec.ts
deleted file mode 100644
index e1094bd2..00000000
--- a/client_v2/tests/e2e/dns-settings.spec.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { test, expect, type Page } from '@playwright/test';
-import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
-
-test.describe('DNS Settings', () => {
- test.beforeEach(async ({ page }) => {
- // Login before each test
- await page.goto('/login.html');
- await page.getByTestId('username').click();
- await page.getByTestId('username').fill(ADMIN_USERNAME);
- await page.getByTestId('password').click();
- await page.getByTestId('password').fill(ADMIN_PASSWORD);
- await page.keyboard.press('Tab');
- await page.getByTestId('sign_in').click();
- await page.waitForURL((url) => !url.href.endsWith('/login.html'));
- });
-
- const runDNSSettingsTest = async (page: Page, address: string) => {
- await page.goto('/#dns');
-
- const currentDns = await page.getByTestId('upstream_dns').inputValue();
-
- await page.getByTestId('upstream_dns').fill(address);
- await page.getByTestId('dns_upstream_test').click();
-
- await page.waitForTimeout(2000);
-
- await expect(page.getByTestId('upstream_dns')).toHaveValue(address);
-
- await page.getByTestId('upstream_dns').fill(currentDns);
- await page.getByTestId('dns_upstream_save').click({ force: true });
- };
-
- test('test for Default DNS', async ({ page }) => {
- await runDNSSettingsTest(page, 'https://dns10.quad9.net/dns-query');
- });
-
- test('test for Plain DNS', async ({ page }) => {
- await runDNSSettingsTest(page, '94.140.14.140');
- });
-
- test('test for DNS-over-HTTPS', async ({ page }) => {
- await runDNSSettingsTest(page, 'https://unfiltered.adguard-dns.com/dns-query');
- });
-
- test('test for DNS-over-TLS', async ({ page }) => {
- await runDNSSettingsTest(page, 'tls://unfiltered.adguard-dns.com');
- });
-
- test('test for DNS-over-QUIC', async ({ page }) => {
- await runDNSSettingsTest(page, 'quic://unfiltered.adguard-dns.com');
- });
-});
diff --git a/client_v2/tests/e2e/filtering.spec.ts b/client_v2/tests/e2e/filtering.spec.ts
deleted file mode 100644
index 49bec97a..00000000
--- a/client_v2/tests/e2e/filtering.spec.ts
+++ /dev/null
@@ -1,73 +0,0 @@
-import { test, expect, type Page } from '@playwright/test';
-import { execSync } from 'child_process';
-import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
-
-test.describe('Filtering', () => {
- test.beforeEach(async ({ page }) => {
- // Login before each test
- await page.goto('/login.html');
- await page.getByTestId('username').click();
- await page.getByTestId('username').fill(ADMIN_USERNAME);
- await page.getByTestId('password').click();
- await page.getByTestId('password').fill(ADMIN_PASSWORD);
- await page.keyboard.press('Tab');
- await page.getByTestId('sign_in').click();
- await page.waitForURL((url) => !url.href.endsWith('/login.html'));
- });
-
- const runTerminalCommand = (command: string) => {
- try {
- console.info(`Executing command: ${command}`);
-
- const output = execSync(command, { encoding: 'utf-8', stdio: 'pipe' }).trim();
-
- console.info('Command executed successfully.');
- console.debug(`Command output:\n${output}`);
-
- return output;
- } catch (error: any) {
- console.error(`Command execution failed with error:\n${error.message}`);
- throw new Error(`Failed to execute command: ${command}\nError: ${error.message}`);
- }
- }
-
- const runCustomRuleTest = async (page: Page, domain_to_block: string) => {
- await page.goto('/#custom_rules');
-
- await page.getByTestId('custom_rule_textarea').fill(domain_to_block);
- await page.getByTestId('apply_custom_rule').click();
-
- const nslookupBlockedResult = await runTerminalCommand(`nslookup ${domain_to_block} 127.0.0.1`).toString();
-
- console.info(`nslookup blocked CNAME result: '${nslookupBlockedResult}'`);
-
- const currentRules = await page.getByTestId('custom_rule_textarea').inputValue();
- console.debug(`Current rules before removal:\n${currentRules}`);
-
- if (currentRules.includes(domain_to_block)) {
- const updatedRules = currentRules
- .split('\n')
- .filter((line) => line.trim() !== domain_to_block.trim())
- .join('\n');
-
- await page.getByTestId('custom_rule_textarea').fill(updatedRules);
- console.info(`Rule '${domain_to_block}' removed successfully.`);
-
- console.info('Applying the updated filtering rules after removal.');
- await page.getByTestId('apply_custom_rule').click();
-
- await page.waitForLoadState('domcontentloaded');
-
- console.info(`Filtering rules successfully updated after removing '${domain_to_block}'.`);
- } else {
- console.warn(`Rule '${domain_to_block}' not found. No changes were made.`);
- }
-
- const nslookupUnblockedResult = await runTerminalCommand(`nslookup ${domain_to_block} 127.0.0.1`).toString();
- console.info(`nslookup unblocked CNAME result: '${nslookupUnblockedResult}'`);
- };
-
- test('Test blocking rule for apple.com', async ({ page }) => {
- await runCustomRuleTest(page, 'apple.com');
- });
-});
diff --git a/client_v2/tests/e2e/general-settings.spec.ts b/client_v2/tests/e2e/general-settings.spec.ts
index ff23a687..348fb8d8 100644
--- a/client_v2/tests/e2e/general-settings.spec.ts
+++ b/client_v2/tests/e2e/general-settings.spec.ts
@@ -5,19 +5,19 @@ import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
test.describe('General Settings', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login.html');
- await page.getByTestId('username').click();
- await page.getByTestId('username').fill(ADMIN_USERNAME);
- await page.getByTestId('password').click();
- await page.getByTestId('password').fill(ADMIN_PASSWORD);
+ await page.locator('#username').click();
+ await page.locator('#username').fill(ADMIN_USERNAME);
+ await page.locator('#password').click();
+ await page.locator('#password').fill(ADMIN_PASSWORD);
await page.keyboard.press('Tab');
- await page.getByTestId('sign_in').click();
+ await page.locator('#sign_in').click();
await page.waitForURL((url) => !url.href.endsWith('/login.html'));
});
test('should toggle browsing security feature and verify DNS changes', async ({ page }) => {
await page.goto('/#settings');
- const browsingSecurity = await page.getByTestId('safebrowsing');
+ const browsingSecurity = await page.locator('#safebrowsing');
const browsingSecurityLabel = await browsingSecurity.locator('xpath=following-sibling::*[1]');
const initialState = await browsingSecurity.isChecked();
@@ -45,7 +45,7 @@ test.describe('General Settings', () => {
test('should toggle parental control feature and verify DNS changes', async ({ page }) => {
await page.goto('/#settings');
- const parentalControl = page.getByTestId('parental');
+ const parentalControl = page.locator('#parental');
const parentalControlLabel = await parentalControl.locator('xpath=following-sibling::*[1]');
const initialState = await parentalControl.isChecked();
@@ -73,7 +73,7 @@ test.describe('General Settings', () => {
test('should toggle safe search feature', async ({ page }) => {
await page.goto('/#settings');
- const safeSearch = page.getByTestId('safesearch');
+ const safeSearch = page.locator('#safesearch');
const safeSearchLabel = await safeSearch.locator('xpath=following-sibling::*[1]');
const initialState = await safeSearch.isChecked();
diff --git a/client_v2/tests/e2e/globalSetup.ts b/client_v2/tests/e2e/globalSetup.ts
index 3d56b53e..14e55e0c 100644
--- a/client_v2/tests/e2e/globalSetup.ts
+++ b/client_v2/tests/e2e/globalSetup.ts
@@ -10,16 +10,16 @@ async function globalSetup(config: FullConfig) {
try {
await page.goto('/');
- await page.getByTestId('install_get_started').click();
- await page.getByTestId('install_web_port').fill(PORT.toString());
- await page.getByTestId('install_next').click();
- await page.getByTestId('install_username').fill(ADMIN_USERNAME);
- await page.getByTestId('install_password').fill(ADMIN_PASSWORD);
- await page.getByTestId('install_confirm_password').click();
- await page.getByTestId('install_confirm_password').fill(ADMIN_PASSWORD);
- await page.getByTestId('install_next').click();
- await page.getByTestId('install_next').click();
- await page.getByTestId('install_open_dashboard').click();
+ await page.locator('#install_get_started').click();
+ await page.locator('#install_web_port').fill(PORT.toString());
+ await page.locator('#install_next').click();
+ await page.locator('#install_username').fill(ADMIN_USERNAME);
+ await page.locator('#install_password').fill(ADMIN_PASSWORD);
+ await page.locator('#install_confirm_password').click();
+ await page.locator('#install_confirm_password').fill(ADMIN_PASSWORD);
+ await page.locator('#install_next').click();
+ await page.locator('#install_next').click();
+ await page.locator('#install_open_dashboard').click();
await page.waitForURL((url) => !url.href.endsWith('/install.html'));
} catch (error) {
console.error('Error during global setup:', error);
diff --git a/client_v2/tests/e2e/login.spec.ts b/client_v2/tests/e2e/login.spec.ts
index 776e9145..e17db69f 100644
--- a/client_v2/tests/e2e/login.spec.ts
+++ b/client_v2/tests/e2e/login.spec.ts
@@ -5,12 +5,12 @@ import { ADMIN_PASSWORD, ADMIN_USERNAME } from '../constants';
test.describe('Login', () => {
test('should successfully log in with valid credentials', async ({ page }) => {
await page.goto('/login.html');
- await page.getByTestId('username').click();
- await page.getByTestId('username').fill(ADMIN_USERNAME);
- await page.getByTestId('password').click();
- await page.getByTestId('password').fill(ADMIN_PASSWORD);
+ await page.locator('#username').click();
+ await page.locator('#username').fill(ADMIN_USERNAME);
+ await page.locator('#password').click();
+ await page.locator('#password').fill(ADMIN_PASSWORD);
await page.keyboard.press('Tab');
- await page.getByTestId('sign_in').click();
+ await page.locator('#sign_in').click();
await page.waitForURL((url) => !url.href.endsWith('/login.html'));
});
});
diff --git a/client_v2/tests/e2e/querylog.spec.ts b/client_v2/tests/e2e/querylog.spec.ts
deleted file mode 100644
index 37b2591d..00000000
--- a/client_v2/tests/e2e/querylog.spec.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { test, expect } from '@playwright/test';
-import { ADMIN_USERNAME, ADMIN_PASSWORD } from '../constants';
-
-test.describe('QueryLog', () => {
- test.beforeEach(async ({ page }) => {
- await page.goto('/login.html');
- await page.getByTestId('username').click();
- await page.getByTestId('username').fill(ADMIN_USERNAME);
- await page.getByTestId('password').click();
- await page.getByTestId('password').fill(ADMIN_PASSWORD);
- await page.keyboard.press('Tab');
- await page.getByTestId('sign_in').click();
- await page.waitForURL((url) => !url.href.endsWith('/login.html'));
- });
-
- test('Search of queryLog should work correctly', async ({ page }) => {
- await page.route('/control/querylog', async (route) => {
- await route.fulfill({
- status: 200,
- contentType: 'application/json',
- body: JSON.stringify(
- {
- "data": [
- {
- "answer": [
- {
- "type": "A",
- "value": "77.88.44.242",
- "ttl": 294
- },
- {
- "type": "A",
- "value": "5.255.255.242",
- "ttl": 294
- },
- {
- "type": "A",
- "value": "77.88.55.242",
- "ttl": 294
- }
- ],
- "answer_dnssec": false,
- "cached": false,
- "client": "127.0.0.1",
- "client_info": {
- "whois": {},
- "name": "localhost",
- "disallowed_rule": "127.0.0.1",
- "disallowed": false
- },
- "client_proto": "",
- "elapsedMs": "78.163167",
- "question": {
- "class": "IN",
- "name": "ya.ru",
- "type": "A"
- },
- "reason": "NotFilteredNotFound",
- "rules": [],
- "status": "NOERROR",
- "time": "2024-07-17T16:02:37.500662+02:00",
- "upstream": "https://dns10.quad9.net:443/dns-query"
- },
- {
- "answer": [
- {
- "type": "A",
- "value": "77.88.55.242",
- "ttl": 351
- },
- {
- "type": "A",
- "value": "77.88.44.242",
- "ttl": 351
- },
- {
- "type": "A",
- "value": "5.255.255.242",
- "ttl": 351
- }
- ],
- "answer_dnssec": false,
- "cached": false,
- "client": "127.0.0.1",
- "client_info": {
- "whois": {},
- "name": "localhost",
- "disallowed_rule": "127.0.0.1",
- "disallowed": false
- },
- "client_proto": "",
- "elapsedMs": "5051.070708",
- "question": {
- "class": "IN",
- "name": "ya.ru",
- "type": "A"
- },
- "reason": "NotFilteredNotFound",
- "rules": [],
- "status": "NOERROR",
- "time": "2024-07-17T16:02:37.4983+02:00",
- "upstream": "https://dns10.quad9.net:443/dns-query"
- }
- ],
- "oldest": "2024-07-17T16:02:37.4983+02:00"
- }
- ),
- });
- });
-
- await page.goto('/#logs');
-
- await page.getByTestId('querylog_search').fill('127.0.0.1');
-
- const [request] = await Promise.all([
- page.waitForRequest((req) => req.url().includes('/control/querylog')),
- ]);
-
- if (request) {
- expect(request.url()).toContain('search=127.0.0.1');
- expect(await page.getByTestId('querylog_cell').first().isVisible()).toBe(true);
- }
- });
-});
diff --git a/client_v2/webpack.common.js b/client_v2/webpack.common.js
index 0e3b7a7a..96b2bd9f 100644
--- a/client_v2/webpack.common.js
+++ b/client_v2/webpack.common.js
@@ -5,6 +5,7 @@ import { CleanWebpackPlugin } from 'clean-webpack-plugin';
import CopyPlugin from 'copy-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import * as url from 'url';
+// eslint-disable-next-line import/extensions
import { BUILD_ENVS } from './constants.js';
// eslint-disable-next-line no-underscore-dangle
diff --git a/client_v2/webpack.dev.js b/client_v2/webpack.dev.js
index aa9b4c5c..82f5cef3 100644
--- a/client_v2/webpack.dev.js
+++ b/client_v2/webpack.dev.js
@@ -1,7 +1,9 @@
import { merge } from 'webpack-merge';
import yaml from 'js-yaml';
import fs from 'fs';
+// eslint-disable-next-line import/extensions
import { BASE_URL } from './constants.js';
+// eslint-disable-next-line import/extensions
import common from './webpack.common.js';
const ZERO_HOST = '0.0.0.0';
diff --git a/client_v2/webpack.prod.js b/client_v2/webpack.prod.js
index 0d678616..49b93f09 100644
--- a/client_v2/webpack.prod.js
+++ b/client_v2/webpack.prod.js
@@ -1,4 +1,5 @@
import { merge } from 'webpack-merge';
+/* eslint-disable-next-line import/extensions */
import common from './webpack.common.js';
export default merge(common, {