diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..68c5d18 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,5 @@ +node_modules/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/src/package-lock.json b/src/package-lock.json index e83b5c8..6ffaa2f 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -9,6 +9,26 @@ "bootstrap": "^5.3.3", "http-server": "^14.1.1", "lz-string": "^1.5.0" + }, + "devDependencies": { + "@playwright/test": "^1.48.0", + "@types/node": "^22.7.5" + } + }, + "node_modules/@playwright/test": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.0.tgz", + "integrity": "sha512-W5lhqPUVPqhtc/ySvZI5Q8X2ztBOUgZ8LbAFy0JQgrXZs2xaILrUcNO3rQjwbLPfGK13+rZsDa1FpG+tqYkT5w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.48.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" } }, "node_modules/@popperjs/core": { @@ -22,6 +42,16 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -212,6 +242,21 @@ } } }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -458,6 +503,38 @@ "opener": "bin/opener-bin.js" } }, + "node_modules/playwright": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.0.tgz", + "integrity": "sha512-qPqFaMEHuY/ug8o0uteYJSRfMGFikhUysk8ZvAtfKmUK3kc/6oNl/y3EczF8OFGYIi/Ex2HspMfzYArk6+XQSA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.48.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.0.tgz", + "integrity": "sha512-RBvzjM9rdpP7UUFrQzRwR8L/xR4HyC1QXMzGYTbf1vjw25/ya9NRAVnXi/0fvFopjebvyPzsmoK58xxeEOaVvA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/portfinder": { "version": "1.0.32", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", @@ -558,6 +635,13 @@ "node": ">=8" } }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, "node_modules/union": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", diff --git a/src/package.json b/src/package.json index a3b579a..1c59230 100644 --- a/src/package.json +++ b/src/package.json @@ -1,14 +1,19 @@ { - "dependencies": { - "bootstrap": "^5.3.3", - "http-server": "^14.1.1", - "lz-string": "^1.5.0" - }, - "scripts": { - "postinstall": "sudo npm install -g sass", - "build": "sass --style compressed scss/custom.scss:../dist/css/bootstrap.min.css && cp node_modules/lz-string/libs/lz-string.min.js ../dist/js/lz-string.min.js", - "setup:certs": "mkdir -p certs; mkcert -cert-file certs/cert.pem -key-file certs/cert.key localhost 127.0.0.1", - "start": "node node_modules/http-server/bin/http-server ../dist -c-1", - "local-secure-start": "node node_modules/http-server/bin/http-server ../dist -c-1 -C certs/cert.pem -K certs/cert.key -S -p 8443" - } + "dependencies": { + "bootstrap": "^5.3.3", + "http-server": "^14.1.1", + "lz-string": "^1.5.0" + }, + "scripts": { + "postinstall": "sudo npm install -g sass", + "build": "sass --style compressed scss/custom.scss:../dist/css/bootstrap.min.css && cp node_modules/lz-string/libs/lz-string.min.js ../dist/js/lz-string.min.js", + "test": "npx playwright test", + "setup:certs": "mkdir -p certs; mkcert -cert-file certs/cert.pem -key-file certs/cert.key localhost 127.0.0.1", + "start": "node node_modules/http-server/bin/http-server ../dist -c-1", + "local-secure-start": "node node_modules/http-server/bin/http-server ../dist -c-1 -C certs/cert.pem -K certs/cert.key -S -p 8443" + }, + "devDependencies": { + "@playwright/test": "^1.48.0", + "@types/node": "^22.7.5" + } } diff --git a/src/playwright.config.ts b/src/playwright.config.ts new file mode 100644 index 0000000..c7446da --- /dev/null +++ b/src/playwright.config.ts @@ -0,0 +1,99 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests', + /* Run tests in files in parallel */ + 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 */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* 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', + + /* 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'], + permissions: ['clipboard-read', 'clipboard-write'], + viewport: { + width: 1920, + height: 1080, + }, + }, + }, + + { + name: 'firefox', + use: { + ...devices['Desktop Firefox'], + viewport: { + width: 1920, + height: 1080, + }, + }, + }, + + { + name: 'webkit', + use: { + ...devices['Desktop Safari'], + permissions: ['clipboard-read'], + viewport: { + width: 1920, + height: 1080, + }, + }, + }, + + /* 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, + // }, +}); diff --git a/src/tests/.gitignore b/src/tests/.gitignore new file mode 100644 index 0000000..6bfb121 --- /dev/null +++ b/src/tests/.gitignore @@ -0,0 +1,2 @@ +# This file contains a private dataset used for testing real world use cases +real-world-functional.spec.ts diff --git a/src/tests/deep-functional.spec.ts b/src/tests/deep-functional.spec.ts new file mode 100644 index 0000000..e42b300 --- /dev/null +++ b/src/tests/deep-functional.spec.ts @@ -0,0 +1,192 @@ +import { test, expect } from '@playwright/test'; + +async function getClipboardText(page) { + return page.evaluate(async () => { + return await navigator.clipboard.readText(); + }); +} + +test('Deep Functional Test', async ({ page }) => { + // The goal of this test is to identify any weird interdependencies or issues that may arise + // from doing a variety of actions on one page load. It's meant to emulate a complex human + // user interaction often with steps that don't make sense. + // This does a little of everything: + // - Manual Network Input + // - Subnet splitting/joining + // - Colors + // - Sharable URLs + // - AWS/Azure Mode + // - Import Reddit Example Config + // - Change Network Size + await page.goto('https://127.0.0.1:8443/'); + // Change 10.0.0.0/8 -> 172.16.0.0/12 + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').press('Shift+Home'); + await page.getByLabel('Network Address').fill('172.16.0.0'); + await page.getByLabel('Network Size').fill('12'); + await page.getByRole('button', { name: 'Go' }).click(); + // Do a bunch of splitting + await page.getByText('/12', { exact: true }).click(); + await page.getByLabel('172.24.0.0/13', { exact: true }).getByText('/13', { exact: true }).click(); + await page.getByLabel('172.24.0.0/14', { exact: true }).getByText('/14', { exact: true }).click(); + await page.getByLabel('172.26.0.0/15', { exact: true }).getByText('/15', { exact: true }).click(); + await page.getByLabel('172.26.0.0/16', { exact: true }).getByText('/16', { exact: true }).click(); + await page.getByRole('cell', { name: '/15 Split' }).click(); + await page.getByRole('cell', { name: '172.24.0.0/16 Split' }).click(); + await page.getByRole('cell', { name: '172.25.0.0/16 Split' }).click(); + await page.getByRole('cell', { name: '/14 Split' }).click(); + await page.getByRole('cell', { name: '172.30.0.0/15 Split' }).click(); + await page.getByRole('cell', { name: '172.31.0.0/16 Split' }).click(); + await page.getByLabel('172.31.128.0/17', { exact: true }).getByText('/17', { exact: true }).click(); + await page.getByLabel('172.31.192.0/18', { exact: true }).getByText('/18', { exact: true }).click(); + await page.getByLabel('172.31.224.0/19', { exact: true }).getByText('/19', { exact: true }).click(); + await page.getByLabel('172.31.192.0/19', { exact: true }).getByText('/19', { exact: true }).click(); + await page.getByRole('textbox', { name: '172.31.240.0/20 Note' }).click(); + await page.getByRole('textbox', { name: '172.31.240.0/20 Note' }).fill('Test A'); + await page.getByRole('textbox', { name: '172.31.224.0/20 Note' }).click(); + await page.getByRole('textbox', { name: '172.31.224.0/20 Note' }).fill('Test B'); + await page.getByRole('cell', { name: '172.31.240.0/20 Split' }).click(); + await page.getByRole('textbox', { name: '172.31.240.0/21 Note' }).click(); + await page.getByRole('textbox', { name: '172.31.240.0/21 Note' }).fill('Test A - 1'); + await page.getByRole('cell', { name: '172.31.248.0/21 Note' }).click(); + await page.getByRole('textbox', { name: '172.31.248.0/21 Note' }).fill('Test A - 2'); + await page.getByLabel('172.31.248.0/21', { exact: true }).getByText('/21', { exact: true }).click(); + await page.getByLabel('172.31.252.0/22', { exact: true }).getByText('/22', { exact: true }).click(); + await page.getByRole('cell', { name: '/21 Split' }).click(); + await page.getByRole('textbox', { name: '172.31.240.0/22 Note' }).click(); + await page.getByRole('textbox', { name: '172.31.240.0/22 Note' }).fill('Test A - 1A'); + await page.getByRole('textbox', { name: '172.31.244.0/22 Note' }).click(); + await page.getByRole('textbox', { name: '172.31.244.0/22 Note' }).fill('Test A - 1B'); + // Join a subnet + await page.getByLabel('172.31.240.0/21 Join').click(); + // Change some colors and do some more splitting + await page.getByText('Change Colors »').click(); + await page.getByLabel('Color 4').click(); + await page.getByRole('cell', { name: '172.26.128.0/17 Usable IPs' }).click(); + await page.getByText('« Stop Changing Colors').click(); + await page.getByRole('cell', { name: '172.26.128.0/17 Split' }).click(); + await page.getByRole('cell', { name: '172.26.192.0/18 Split' }).click(); + await page.getByText('Change Colors »').click(); + await page.getByLabel('Color 8').click(); + await page.getByRole('cell', { name: '172.26.128.0/18 Usable IPs' }).click(); + await page.getByText('« Stop Changing Colors').click(); + // Make sure we're still not changing colors + await page.getByRole('cell', { name: '172.26.128.0/18 Split' }).click(); + // Check a bunch of specific items + await expect(page.getByLabel('Network Address')).toHaveValue('172.16.0.0'); + await expect(page.getByLabel('Network Size')).toHaveValue('12'); + await expect(page.getByRole('textbox', { name: '172.31.254.0/23 Note' })).toHaveValue('Test A - 2'); + await expect(page.getByRole('textbox', { name: '172.31.252.0/23 Note' })).toHaveValue('Test A - 2'); + await expect(page.getByRole('textbox', { name: '/22 Note' })).toHaveValue('Test A - 2'); + await expect(page.getByRole('textbox', { name: '/21 Note' })).toBeEmpty(); + await expect(page.getByRole('textbox', { name: '172.31.224.0/20 Note' })).toHaveValue('Test B'); + await expect(page.getByLabel('172.16.0.0/13', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/13'); + await expect(page.getByLabel('172.24.0.0/17', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/17'); + await expect(page.getByLabel('172.26.128.0/19', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/19'); + await expect(page.getByLabel('172.27.0.0/16', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/16'); + await expect(page.getByLabel('172.28.0.0/15', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/15'); + await expect(page.getByLabel('172.30.0.0/16', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/16'); + await expect(page.getByLabel('172.31.0.0/17', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/17'); + await expect(page.getByLabel('172.31.128.0/18', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/18'); + await expect(page.getByLabel('172.31.192.0/20', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/20'); + await expect(page.getByLabel('172.31.240.0/21', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/21'); + await expect(page.getByLabel('172.31.248.0/22', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/22'); + await expect(page.getByLabel('172.31.252.0/23', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/23'); + await expect(page.getByLabel('/12 Join')).toContainText('/12'); + await expect(page.getByLabel('/13 Join')).toContainText('/13'); + await expect(page.getByLabel('172.26.128.0/17 Join')).toContainText('/17'); + await expect(page.getByLabel('172.31.128.0/17 Join')).toContainText('/17'); + await expect(page.getByLabel('172.31.192.0/19 Join')).toContainText('/19'); + await expect(page.getByLabel('172.31.224.0/19 Join')).toContainText('/19'); + await expect(page.getByLabel('/21 Join')).toContainText('/21'); + await expect(page.getByLabel('/22 Join')).toContainText('/22'); + await expect(page.getByRole('row', { name: '172.26.128.0/19' })).toHaveCSS('background-color', 'rgb(255, 198, 255)'); + await expect(page.getByRole('row', { name: '172.26.160.0/19' })).toHaveCSS('background-color', 'rgb(255, 198, 255)'); + await expect(page.getByRole('row', { name: '172.26.192.0/19' })).toHaveCSS('background-color', 'rgb(202, 255, 191)'); + await expect(page.getByRole('row', { name: '172.26.224.0/19' })).toHaveCSS('background-color', 'rgb(202, 255, 191)'); + // Check the Shareable URL + await page.getByText('Copy Shareable URL').click(); + let clipboardUrl = await getClipboardText(page); + expect(clipboardUrl).toContain('/index.html?c=1N4IgbiBcIEwgNCARlEBGA7DAdGgbNgAxED0aciAzlKIQMY0iEAmNAvomq5KDAKaMALADNGADgDmjfAAt2nDHJ5sOIAJxSe6MUuCq0a3StUBWUVrSFNvQkcQw0ukIJgBLcYIBWjBtADEwsJ0eIEgqmIm3lq+IAFBIaIqiIIAzO5aYnhRoDF+dACGgUiJiGIY2SC5BUWJxpxo1nUgKQJaIfIgGOagaIKNnCbWzbYdKY6MeG4deGnSMFmMMCYwANYdSylryvow5YsmglugAHaoACp8lAAuAAQAQmH2JiZHICaWADaMp9AIlaiPN5oNBfCyEGAwAC233Ol1uAEEbgBaG5wfTglLQrQwQiCPA-E6w643REotH2XEYAkgH4gC7E0mosLGFmsthAA'); + // Check the Export + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Import / Export' }).click(); + await expect(page.getByLabel('Import/Export Content')).toHaveValue('{\n "config_version": "2",\n "base_network": "172.16.0.0/12",\n "subnets": {\n "172.16.0.0/12": {\n "172.16.0.0/13": {},\n "172.24.0.0/13": {\n "172.24.0.0/14": {\n "172.24.0.0/15": {\n "172.24.0.0/16": {\n "172.24.0.0/17": {},\n "172.24.128.0/17": {}\n },\n "172.25.0.0/16": {\n "172.25.0.0/17": {},\n "172.25.128.0/17": {}\n }\n },\n "172.26.0.0/15": {\n "172.26.0.0/16": {\n "172.26.0.0/17": {},\n "172.26.128.0/17": {\n "172.26.128.0/18": {\n "172.26.128.0/19": {\n "_color": "#ffc6ff"\n },\n "172.26.160.0/19": {\n "_color": "#ffc6ff"\n }\n },\n "172.26.192.0/18": {\n "172.26.192.0/19": {\n "_color": "#caffbf"\n },\n "172.26.224.0/19": {\n "_color": "#caffbf"\n }\n }\n }\n },\n "172.27.0.0/16": {}\n }\n },\n "172.28.0.0/14": {\n "172.28.0.0/15": {},\n "172.30.0.0/15": {\n "172.30.0.0/16": {},\n "172.31.0.0/16": {\n "172.31.0.0/17": {},\n "172.31.128.0/17": {\n "172.31.128.0/18": {},\n "172.31.192.0/18": {\n "172.31.192.0/19": {\n "172.31.192.0/20": {},\n "172.31.208.0/20": {}\n },\n "172.31.224.0/19": {\n "172.31.224.0/20": {\n "_note": "Test B"\n },\n "172.31.240.0/20": {\n "172.31.240.0/21": {\n "_note": "",\n "_color": ""\n },\n "172.31.248.0/21": {\n "172.31.248.0/22": {\n "_note": "Test A - 2"\n },\n "172.31.252.0/22": {\n "172.31.252.0/23": {\n "_note": "Test A - 2"\n },\n "172.31.254.0/23": {\n "_note": "Test A - 2"\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n }\n}'); + await page.getByLabel('Import/Export', { exact: true }).getByText('Close').click(); + // Set to AWS Mode + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - AWS' }).click(); + // Check AWS Mode Settings + await expect(page.getByLabel('172.31.254.0/23', { exact: true }).getByLabel('Usable IPs (AWS)')).toContainText('172.31.254.4 - 172.31.255.254'); + await expect(page.getByLabel('172.31.254.0/23', { exact: true }).getByLabel('Hosts')).toContainText('507'); + await page.getByText('Copy Shareable URL').click(); + clipboardUrl = await getClipboardText(page); + expect(clipboardUrl).toContain('/index.html?c=1N4IgbiBcIEwgNCARlEBGA7DAdGgbNgAxED0aciAtqgIIDqAygiAM5SiEDG7IhAJuwC+iNAMigYAUx4AWAGY8AHAHMe+ABZCRGTeMHCQATlXj0i3cANpDF-QYCsC02kImJhW4hhoLIGTABLJRkAKx5uaABiOTlOPBiQA0V7MNMIkGjY+IV9RBkAZiDTRTxU0HTIzgBDGKQcxEUMMpAK6tqcuxE0N06QfOlTeK0QDCdQNBkekXs3Po9h-J8ePEDhvEK1GFKeGHsYAGth3fzDvSsYJp37GVPQADtUABVJFgAXAAIAIUSve3tbkD2FwAGx4D2gzHSP0BaDQoOchBgMGopnBIGeb3eNHeAFp3nArIj8ij3DI8OD7k8Xh9sXiCV5CDIMBSQGiMTTcfjEnYebzBEA'); + // Set to Azure Mode + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - Azure' }).click(); + // Check Azure Mode Settings + await expect(page.getByLabel('172.31.254.0/23', { exact: true }).getByLabel('Usable IPs (Azure)')).toContainText('172.31.254.4 - 172.31.255.254'); + await expect(page.getByLabel('172.31.254.0/23', { exact: true }).getByLabel('Hosts')).toContainText('507'); + await page.getByText('Copy Shareable URL').click(); + clipboardUrl = await getClipboardText(page); + expect(clipboardUrl).toContain('/index.html?c=1N4IgbiBcIEwgNCARlEBGA7DAdGgbNgAxED0aciAtqgIIBaAqgEoCiCIAzlKIQMbchCAE24BfRGhGRQMAKYCALADMBADgDmA-AAsxEjLumjxIAJybp6VYeAm0pm8ZMBWFZbSELMwo8Qw0NiAKMACWagoAVgL80ADESkq8eAkgJqrOUZYxIPGJySrGiAoAzGGWqniZoNmxvACGCUgFiKoYVSA19Y0FThJoXr0gxfKWyXogGG6gaAoDEs5eQz7jxQECeKHjeKVaMJUCMM4wANbjh8WnRnYwbQfOCpegAHaoACqyHAAuAAQAQql+ZzOR4gZweAA2Ahe0HY2QBoLQaEh7kIMBg1Es0JA7y+3xo3wAtN84HZUcUMd4FHhoc83h8fviiSS-IQFBgaSAsTiGYTiaknALBaIgA'); + // Import Default Reddit Config + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Import / Export' }).click(); + await page.getByLabel('Import/Export Content').click(); + await page.getByLabel('Import/Export Content').press('ControlOrMeta+a'); + await page.getByLabel('Import/Export Content').fill('{\n "config_version": "2",\n "base_network": "10.0.0.0/20",\n "subnets": {\n "10.0.0.0/20": {\n "10.0.0.0/21": {\n "10.0.0.0/22": {\n "10.0.0.0/23": {\n "10.0.0.0/24": {\n "_note": "Data Center - Virtual Servers",\n "_color": "#9bf6ff"\n },\n "10.0.1.0/24": {\n "_note": "Data Center - Virtual Servers",\n "_color": "#9bf6ff"\n }\n },\n "10.0.2.0/23": {\n "10.0.2.0/24": {\n "_note": "Data Center - Virtual Servers",\n "_color": "#9bf6ff"\n },\n "10.0.3.0/24": {\n "_note": "Data Center - Physical Servers",\n "_color": "#a0c4ff"\n }\n }\n },\n "10.0.4.0/22": {\n "10.0.4.0/23": {\n "_note": "Building A - Wifi",\n "_color": "#ffd6a5"\n },\n "10.0.6.0/23": {\n "_note": "Building A - LAN",\n "_color": "#ffd6a5"\n }\n }\n },\n "10.0.8.0/21": {\n "10.0.8.0/22": {\n "10.0.8.0/23": {\n "10.0.8.0/24": {\n "_note": "Building A - Printers",\n "_color": "#ffd6a5"\n },\n "10.0.9.0/24": {\n "_note": "Building A - Voice",\n "_color": "#ffd6a5"\n }\n },\n "10.0.10.0/23": {\n "_note": "Building B - Wifi",\n "_color": "#fdffb6"\n }\n },\n "10.0.12.0/22": {\n "10.0.12.0/23": {\n "_note": "Building B - LAN",\n "_color": "#fdffb6"\n },\n "10.0.14.0/23": {\n "10.0.14.0/24": {\n "_note": "Building B - Printers",\n "_color": "#fdffb6"\n },\n "10.0.15.0/24": {\n "_note": "Building B - Voice",\n "_color": "#fdffb6"\n }\n }\n }\n }\n }\n }\n}'); + await page.getByRole('button', { name: 'Import' }).click(); + // Do all the Reddit Default Checks + await expect(page.getByLabel('Network Address')).toHaveValue('10.0.0.0'); + await expect(page.getByLabel('Network Size')).toHaveValue('20'); + await expect(page.getByLabel('10.0.0.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.0.0/24'); + await expect(page.getByLabel('10.0.1.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.1.0/24'); + await expect(page.getByLabel('10.0.2.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.2.0/24'); + await expect(page.getByLabel('10.0.3.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.3.0/24'); + await expect(page.getByLabel('10.0.4.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.4.0/23'); + await expect(page.getByLabel('10.0.6.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.6.0/23'); + await expect(page.getByLabel('10.0.8.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.8.0/24'); + await expect(page.getByLabel('10.0.9.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.9.0/24'); + await expect(page.getByLabel('10.0.10.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.10.0/23'); + await expect(page.getByLabel('10.0.12.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.12.0/23'); + await expect(page.getByLabel('10.0.14.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.14.0/24'); + await expect(page.getByLabel('10.0.15.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.15.0/24'); + await expect(page.getByRole('textbox', { name: '10.0.0.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.1.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.2.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.3.0/24 Note' })).toHaveValue('Data Center - Physical Servers'); + await expect(page.getByRole('textbox', { name: '10.0.4.0/23 Note' })).toHaveValue('Building A - Wifi'); + await expect(page.getByRole('textbox', { name: '10.0.6.0/23 Note' })).toHaveValue('Building A - LAN'); + await expect(page.getByRole('textbox', { name: '10.0.8.0/24 Note' })).toHaveValue('Building A - Printers'); + await expect(page.getByRole('textbox', { name: '10.0.9.0/24 Note' })).toHaveValue('Building A - Voice'); + await expect(page.getByRole('textbox', { name: '10.0.10.0/23 Note' })).toHaveValue('Building B - Wifi'); + await expect(page.getByRole('textbox', { name: '10.0.12.0/23 Note' })).toHaveValue('Building B - LAN'); + await expect(page.getByRole('textbox', { name: '10.0.14.0/24 Note' })).toHaveValue('Building B - Printers'); + await expect(page.getByRole('textbox', { name: '10.0.15.0/24 Note' })).toHaveValue('Building B - Voice'); + await expect(page.getByRole('row', { name: '10.0.0.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.1.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.2.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.3.0/24' })).toHaveCSS('background-color', 'rgb(160, 196, 255)'); + await expect(page.getByRole('row', { name: '10.0.4.0/23' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.6.0/23' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.8.0/24' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.9.0/24' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.10.0/23' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.12.0/23' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.14.0/24' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.15.0/24' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + // Now change the whole network address + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').press('ControlOrMeta+a'); + await page.getByLabel('Network Address').fill('192.168.0.0'); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.getByLabel('192.168.0.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('192.168.0.0/24'); +}); + + + +//test('Test', async ({ page }) => { +// await page.goto('https://127.0.0.1:8443/'); +//}); diff --git a/src/tests/default-homepage.spec.ts b/src/tests/default-homepage.spec.ts new file mode 100644 index 0000000..16efed4 --- /dev/null +++ b/src/tests/default-homepage.spec.ts @@ -0,0 +1,22 @@ +import { test, expect } from '@playwright/test'; + +test('Default Homepage Rendering', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await expect(page).toHaveTitle(/Visual Subnet Calculator/); + await expect(page.getByRole('heading')).toContainText('Visual Subnet Calculator'); + await expect(page.getByLabel('Network Address')).toHaveValue('10.0.0.0'); + await expect(page.getByLabel('Network Size')).toHaveValue('16'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.0.0/16'); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Range of Addresses')).toContainText('10.0.0.0 - 10.0.255.255'); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Usable IPs')).toContainText('10.0.0.1 - 10.0.255.254'); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Hosts')).toContainText('65534'); + await expect(page.getByRole('textbox', { name: '10.0.0.0/16 Note' })).toBeEmpty(); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/16'); + // This "default no color" check could maybe be improved. May not be reliable cross-browser. + await expect(page.getByRole('row', { name: '10.0.0.0/16' })).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)'); + await expect(page.getByLabel('Change Colors').locator('span')).toContainText('Change Colors »'); + await expect(page.locator('#copy_url')).toContainText('Copy Shareable URL'); +}); + + diff --git a/src/tests/import-export.spec.ts b/src/tests/import-export.spec.ts new file mode 100644 index 0000000..9075747 --- /dev/null +++ b/src/tests/import-export.spec.ts @@ -0,0 +1,47 @@ +import { test, expect } from '@playwright/test'; + +test('Default Export Content', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Import / Export' }).click(); + await expect(page.locator('#importExportModalLabel')).toContainText('Import/Export'); + await expect(page.getByLabel('Import/Export', { exact: true })).toContainText('Close'); + await expect(page.locator('#importBtn')).toContainText('Import'); + await expect(page.getByLabel('Import/Export Content')).toHaveValue('{\n "config_version": "2",\n "base_network": "10.0.0.0/16",\n "subnets": {\n "10.0.0.0/16": {}\n }\n}'); +}); + +test('Default (AWS) Export Content', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - AWS' }).click(); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Import / Export' }).click(); + await expect(page.getByLabel('Import/Export Content')).toHaveValue('{\n "config_version": "2",\n "operating_mode": "AWS",\n "base_network": "10.0.0.0/16",\n "subnets": {\n "10.0.0.0/16": {}\n }\n}'); +}); + +test('Default (Azure) Export Content', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - Azure' }).click(); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Import / Export' }).click(); + await expect(page.getByLabel('Import/Export Content')).toHaveValue('{\n "config_version": "2",\n "operating_mode": "AZURE",\n "base_network": "10.0.0.0/16",\n "subnets": {\n "10.0.0.0/16": {}\n }\n}'); + await page.getByLabel('Import/Export', { exact: true }).getByText('Close').click(); +}); + +test('Import 192.168.0.0/24', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Import / Export' }).click(); + await page.getByLabel('Import/Export Content').click(); + await page.getByLabel('Import/Export Content').fill('{\n "config_version": "2",\n "base_network": "192.168.0.0/24",\n "subnets": {\n "192.168.0.0/24": {}\n }\n}'); + await page.getByRole('button', { name: 'Import' }).click(); + await expect(page.getByLabel('Network Address')).toHaveValue('192.168.0.0'); + await expect(page.getByLabel('Network Size')).toHaveValue('24'); + await expect(page.getByLabel('192.168.0.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('192.168.0.0/24'); +}); + +//test('Test', async ({ page }) => { +// await page.goto('https://127.0.0.1:8443/'); +//}); + diff --git a/src/tests/real-world-functional.spec.ts.gpg b/src/tests/real-world-functional.spec.ts.gpg new file mode 100644 index 0000000..1717240 Binary files /dev/null and b/src/tests/real-world-functional.spec.ts.gpg differ diff --git a/src/tests/subnet-basic.spec.ts b/src/tests/subnet-basic.spec.ts new file mode 100644 index 0000000..6cf12e2 --- /dev/null +++ b/src/tests/subnet-basic.spec.ts @@ -0,0 +1,174 @@ +import { test, expect } from '@playwright/test'; + +async function getClipboardText(page) { + return page.evaluate(async () => { + return await navigator.clipboard.readText(); + }); +} + +test('Renders Max Depth /0 to /32', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').press('Shift+Home'); + await page.getByLabel('Network Address').fill('0.0.0.0'); + await page.getByLabel('Network Address').press('Tab'); + await page.getByLabel('Network Size').fill('0'); + await page.getByRole('button', { name: 'Go' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/0 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/1 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/2 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/3 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/4 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/5 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/6 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/7 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/8 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/9 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/10 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/11 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/12 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/13 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/14 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/15 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/16 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/17 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/18 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/19 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/20 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/21 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/22 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/23 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/24 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/25 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/26 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/27 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/28 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/29 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/30 Split' }).click(); + await page.getByRole('cell', { name: '0.0.0.0/31 Split' }).click(); + await expect(page.getByLabel('0.0.0.0/32', { exact: true }).getByLabel('Subnet Address')).toContainText('0.0.0.0/32'); + await expect(page.getByLabel('0.0.0.0/32', { exact: true }).getByLabel('Range of Addresses')).toContainText('0.0.0.0'); + await expect(page.getByLabel('0.0.0.0/32', { exact: true }).getByLabel('Usable IPs')).toContainText('0.0.0.0'); + await expect(page.getByLabel('0.0.0.0/32', { exact: true }).getByLabel('Hosts')).toContainText('1'); + await expect(page.getByLabel('0.0.0.0/32', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/32'); + await expect(page.getByLabel('/31 Join')).toContainText('/31'); + await expect(page.getByLabel('128.0.0.0/1', { exact: true }).getByLabel('Subnet Address')).toContainText('128.0.0.0/1'); +}); + +test('Change To 192.168.0.0/24', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').fill('192.168.0.0'); + await page.getByLabel('Network Size').click(); + await page.getByLabel('Network Size').fill('24'); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.getByLabel('192.168.0.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('192.168.0.0/24'); + await expect(page.getByLabel('192.168.0.0/24', { exact: true }).getByLabel('Range of Addresses')).toContainText('192.168.0.0 - 192.168.0.255'); + await expect(page.getByLabel('192.168.0.0/24', { exact: true }).getByLabel('Usable IPs')).toContainText('192.168.0.1 - 192.168.0.254'); + await expect(page.getByLabel('192.168.0.0/24', { exact: true }).getByLabel('Hosts')).toContainText('254'); + await expect(page.getByLabel('192.168.0.0/24', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/24'); + await expect(page.getByRole('textbox', { name: '192.168.0.0/24 Note' })).toBeEmpty(); +}); + +test('Deep /32 Split', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByText('/16', { exact: true }).click(); + await page.getByLabel('10.0.128.0/17', { exact: true }).getByText('/17', { exact: true }).click(); + await page.getByLabel('10.0.128.0/18', { exact: true }).getByText('/18', { exact: true }).click(); + await page.getByLabel('10.0.160.0/19', { exact: true }).getByText('/19', { exact: true }).click(); + await page.getByLabel('10.0.176.0/20', { exact: true }).getByText('/20', { exact: true }).click(); + await page.getByLabel('10.0.184.0/21', { exact: true }).getByText('/21', { exact: true }).click(); + await page.getByLabel('10.0.176.0/21', { exact: true }).getByText('/21', { exact: true }).click(); + await page.getByLabel('10.0.176.0/22', { exact: true }).getByText('/22', { exact: true }).click(); + await page.getByLabel('10.0.176.0/23', { exact: true }).getByText('/23', { exact: true }).click(); + await page.getByLabel('10.0.176.0/24', { exact: true }).getByText('/24', { exact: true }).click(); + await page.getByLabel('10.0.176.0/25', { exact: true }).getByText('/25', { exact: true }).click(); + await page.getByLabel('10.0.176.0/26', { exact: true }).getByText('/26', { exact: true }).click(); + await page.getByLabel('10.0.176.0/27', { exact: true }).getByText('/27', { exact: true }).click(); + await page.getByLabel('10.0.176.0/28', { exact: true }).getByText('/28', { exact: true }).click(); + await page.getByLabel('10.0.176.0/29', { exact: true }).getByText('/29', { exact: true }).click(); + await page.getByLabel('10.0.176.0/30', { exact: true }).getByText('/30', { exact: true }).click(); + await page.getByLabel('10.0.176.0/31', { exact: true }).getByText('/31', { exact: true }).click(); + await page.getByRole('textbox', { name: '10.0.176.0/32 Note' }).click(); + await page.getByRole('textbox', { name: '10.0.176.0/32 Note' }).fill('Test Text'); + await page.getByText('Change Colors »').click(); + await page.locator('#palette_picker_6').click(); + await page.getByRole('cell', { name: '10.0.176.0/32 Subnet Address' }).click(); + await page.getByText('« Stop Changing Colors').click(); + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').fill('99.0.0.0'); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.getByLabel('99.0.176.0/32', { exact: true }).getByLabel('Subnet Address')).toContainText('99.0.176.0/32'); + await expect(page.getByLabel('99.0.176.0/32', { exact: true }).getByLabel('Hosts')).toContainText('1'); + await expect(page.getByRole('textbox', { name: '99.0.176.0/32 Note' })).toHaveValue('Test Text'); + await expect(page.getByLabel('99.0.176.0/32', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/32'); +}); + +test('Usable IPs - Standard', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - Standard' }).click(); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Usable IPs')).toContainText('10.0.0.1 - 10.0.255.254'); +}); + +test('Usable IPs - AWS', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - AWS' }).click(); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Usable IPs')).toContainText('10.0.0.4 - 10.0.255.254'); +}); + +test('Usable IPs - Azure', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - Azure' }).click(); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Usable IPs')).toContainText('10.0.0.4 - 10.0.255.254'); +}); + +test('Note Splitting', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Note Split/Join').click(); + await page.getByLabel('Note Split/Join').fill('This should be duplicated!'); + await page.getByRole('cell', { name: '/16 Split' }).click(); + await expect(page.getByRole('textbox', { name: '10.0.0.0/17 Note' })).toHaveValue('This should be duplicated!'); + await expect(page.getByRole('textbox', { name: '10.0.128.0/17 Note' })).toHaveValue('This should be duplicated!'); +}); + +test('Note Joining Same', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9GgGwIgDOUoGA5hSBgBa0B2qAKvQJakAEp9A9gFcANgBNuSAKbdRggA7COAYwCGAF0miAhCAC+iNI0igW0dl14CR4qTPmLVG7Xt2ugA'); + await page.getByLabel('/16 Join').click(); + await expect(page.getByLabel('Note Split/Join')).toHaveValue('This should be duplicated!'); +}); + +test('Note Joining Different', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9GgGwIgDOUoGA5hSBgBa0B2qAKvQJakAEp9A9gFcANgBNuSAKbdRggA7COAYwCGAF0miAhNwCCIAL6I0jSKBbR2XXgJHipM+YtUbt3AEKGD3oA'); + await page.getByLabel('/16 Join').click(); + await expect(page.getByLabel('Note Split/Join')).toBeEmpty(); +}); + +test('Color Splitting', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByText('Change Colors »').click(); + await page.getByLabel('Color 5').click(); + await page.getByRole('cell', { name: '/16 Subnet Address' }).click(); + await page.getByText('« Stop Changing Colors').click(); + await page.getByText('/16', { exact: true }).click(); + await expect(page.getByRole('row', { name: '10.0.0.0/17' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.128.0/17' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); +}); + +test('Color Joining Same', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9GgGwIgDOUoGA5hSBgBa0DGqAxAJxIBmhXXIAX0RpGkUC2gduvfgLkCgA'); + await page.getByLabel('/16 Join').click(); + await expect(page.getByRole('row', { name: '10.0.0.0/16' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); +}); + +test('Color Joining Different', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9GgGwIgDOUoGA5hSBgBa0DGqAxAJxIBmhXXIAX0RpGkUC2isuAEz5JiAxQKA'); + await page.getByLabel('/16 Join').click(); + await expect(page.getByRole('row', { name: '10.0.0.0/16' })).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)'); +}); + +//test('Test', async ({ page }) => { +// await page.goto('https://127.0.0.1:8443/'); +//}); diff --git a/src/tests/ui-error-handling.spec.ts b/src/tests/ui-error-handling.spec.ts new file mode 100644 index 0000000..fc17d17 --- /dev/null +++ b/src/tests/ui-error-handling.spec.ts @@ -0,0 +1,76 @@ +import { test, expect } from '@playwright/test'; + +test('Bad Network Address', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').fill('1'); + await page.locator('html').click(); + await expect(page.locator('#network')).toHaveClass(/error/i); + await expect(page.getByText('Must be a valid IPv4 Address')).toBeVisible(); +}); + +test('Bad Network Size', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Network Size').click(); + await page.getByLabel('Network Size').fill('33'); + await page.locator('html').click(); + await expect(page.locator('#netsize')).toHaveClass(/error/i); + await expect(page.getByText('Smallest size is /32')).toBeVisible(); +}); + +test('Prevent Go on Bad Input', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Network Size').click(); + await page.getByLabel('Network Size').fill('33'); + await page.locator('html').click(); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.locator('#notifyModalLabel')).toContainText('Warning!'); + await expect(page.locator('#notifyModalDescription')).toContainText('Please correct the errors in the form!'); +}); + + +test('Network Boundary Correction', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').fill('123.45.67.89'); + await page.getByLabel('Network Size').click(); + await page.getByLabel('Network Size').fill('20'); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.locator('#notifyModalLabel')).toContainText('Warning!'); + await expect(page.locator('#notifyModalDescription')).toContainText('Your network input is not on a network boundary for this network size. It has been automatically changed:'); + await expect(page.locator('#notifyModalDescription')).toContainText('123.45.67.89 -> 123.45.64.0'); + await page.getByLabel('Warning!').getByLabel('Close').click(); + await expect(page.getByLabel('Network Address')).toHaveValue('123.45.64.0'); + await page.getByLabel('Network Size').click(); + await expect(page.getByRole('cell', { name: '123.45.64.0/20 Subnet Address' })).toContainText('123.45.64.0/20'); + await page.getByRole('cell', { name: '/20 Split' }).click(); + await page.getByLabel('/20 Join').click(); + await expect(page.getByLabel('123.45.64.0/20', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/20'); +}); + +test('Subnet Too Small for AWS Mode', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - AWS' }).click(); + await page.getByLabel('Network Size').click(); + await page.getByLabel('Network Size').fill('29'); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.locator('#notifyModalLabel')).toContainText('Warning!'); + await expect(page.locator('#notifyModalDescription')).toContainText('Please correct the errors in the form!'); + await expect(page.getByText('AWS Mode - Smallest size is /28')).toBeVisible(); +}); + +test('Subnet Too Small for Azure Mode', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - Azure' }).click(); + await page.getByLabel('Network Size').click(); + await page.getByLabel('Network Size').fill('30'); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.locator('#notifyModalLabel')).toContainText('Warning!'); + await expect(page.locator('#notifyModalDescription')).toContainText('Please correct the errors in the form!'); + await expect(page.getByText('Azure Mode - Smallest size is /29')).toBeVisible(); +}); + diff --git a/src/tests/ui-usage.spec.ts b/src/tests/ui-usage.spec.ts new file mode 100644 index 0000000..ee7031a --- /dev/null +++ b/src/tests/ui-usage.spec.ts @@ -0,0 +1,168 @@ +import { test, expect } from '@playwright/test'; + +test('CIDR Input Typing', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').press('End'); + await page.getByLabel('Network Address').press('Shift+Home'); + await page.getByLabel('Network Address').press('Delete'); + await page.keyboard.type('192.168.0.0/24'); + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.getByRole('cell', { name: '192.168.0.0/24 Subnet Address' })).toContainText('192.168.0.0/24'); +}); + +test('CIDR Input Paste', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByLabel('Network Address').click(); + await page.getByLabel('Network Address').press('End'); + await page.getByLabel('Network Address').press('Shift+Home'); + // From: https://github.com/microsoft/playwright/issues/2511 + await page.locator('#network').evaluate((formEl) => { + const data = `172.16.0.0/12`; + const clipboardData = new DataTransfer(); + const dataType = 'text/plain'; + clipboardData.setData(dataType, data); + const clipboardEvent = new ClipboardEvent('paste', { + clipboardData, + dataType, + data + }); + formEl.dispatchEvent(clipboardEvent); + }); + + await page.getByRole('button', { name: 'Go' }).click(); + await expect(page.getByRole('cell', { name: '172.16.0.0/12 Subnet Address' })).toContainText('172.16.0.0/12'); +}); + +test('About Dialog', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.locator('#info_icon').click(); + await expect(page.locator('#aboutModalLabel')).toContainText('About Visual Subnet Calculator'); + await expect(page.getByLabel('About Visual Subnet Calculator')).toContainText('Design Tenets'); + await expect(page.getByLabel('About Visual Subnet Calculator')).toContainText('Credits'); + await expect(page.getByLabel('About Visual Subnet Calculator').getByText('Close')).toBeVisible(); +}); + +test('GitHub Link', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + const page1Promise = page.waitForEvent('popup'); + await page.getByLabel('GitHub').click(); + const page1 = await page1Promise; + await expect(page1.locator('#repository-container-header')).toContainText('ckabalan / visualsubnetcalc Public'); +}); + +test('Table Header Standard Mode', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); +}); + +test('Table Header AWS Mode', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - AWS' }).click(); + await expect(page.getByRole('cell', { name: 'Usable IPs', exact: true })).toContainText('Usable IPs (AWS)'); + await page.getByRole('link', { name: 'AWS' }).hover() + await expect(page.getByText('AWS reserves 5 addresses in')).toBeVisible(); +}); + +test('Table Header Azure Mode', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - Azure' }).click(); + await expect(page.getByRole('cell', { name: 'Usable IPs', exact: true })).toContainText('Usable IPs (Azure)'); + await page.getByRole('link', { name: 'Azure' }).hover() + await expect(page.getByText('Azure reserves 5 addresses in')).toBeVisible(); +}); + + +test('Table Header AWS then Standard', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - AWS' }).click(); + await expect(page.getByRole('cell', { name: 'Usable IPs', exact: true })).toContainText('Usable IPs (AWS)'); + await page.getByRole('button', { name: 'Tools' }).click(); + await page.getByRole('link', { name: 'Mode - Standard' }).click(); + await expect(page.getByRole('cell', { name: 'Usable IPs', exact: true })).toContainText('Usable IPs'); + await expect(page.getByRole('cell', { name: 'Usable IPs', exact: true })).not.toContainText('(AWS)'); +}); + +test('Color Palette', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await expect(page.getByLabel('Change Colors').locator('span')).toContainText('Change Colors »'); + await page.getByText('Change Colors »').click(); + await expect(page.getByLabel('Color 1', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 2', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 3', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 4', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 5', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 6', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 7', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 8', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 9', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Color 10', { exact: true })).toBeVisible(); + await expect(page.getByLabel('Stop Changing Colors').locator('span')).toContainText('« Stop Changing Colors'); + await page.getByText('« Stop Changing Colors').click(); + await expect(page.getByLabel('Change Colors').locator('span')).toContainText('Change Colors »'); +}); + +test('Test Default Colors', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9GgGwIgDOUoGA5hSBgBa0YCWTAVkwNYUC+ia3SMB590HIbEHDEAZikjRaVhJjjQAFnmIArPNEy1IQlpAB2PSP6MVyjYYAcJgJx6dhzCbQDelkDNtG7jCecj6Ipu6avPy6PgoiQA'); + await page.getByText('Change Colors »').click(); + // Set the top 10 rows to the default colors and check that they are correct + await page.getByLabel('Color 1', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.0.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.0.0/20' })).toHaveCSS('background-color', 'rgb(255, 173, 173)'); + await page.getByLabel('Color 2', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.16.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.16.0/20' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await page.getByLabel('Color 3', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.32.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.32.0/20' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await page.getByLabel('Color 4', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.48.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.48.0/20' })).toHaveCSS('background-color', 'rgb(202, 255, 191)'); + await page.getByLabel('Color 5', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.64.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.64.0/20' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await page.getByLabel('Color 6', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.80.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.80.0/20' })).toHaveCSS('background-color', 'rgb(160, 196, 255)'); + await page.getByLabel('Color 7', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.96.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.96.0/20' })).toHaveCSS('background-color', 'rgb(189, 178, 255)'); + await page.getByLabel('Color 8', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.112.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.112.0/20' })).toHaveCSS('background-color', 'rgb(255, 198, 255)'); + await page.getByLabel('Color 9', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.128.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.128.0/20' })).toHaveCSS('background-color', 'rgb(230, 230, 230)'); + await page.getByLabel('Color 10', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.144.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.144.0/20' })).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + // Set rows 11 and 12 to Colors 1 and 2 respectively and check that they are correct + await page.getByLabel('Color 1', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.160.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.160.0/20' })).toHaveCSS('background-color', 'rgb(255, 173, 173)'); + await page.getByLabel('Color 2', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.176.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.176.0/20' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + // Set rows 11 and 12 to Color 10 (white) to make sure you can change colors later + await page.getByLabel('Color 10', { exact: true }).click(); + await page.getByRole('cell', { name: '10.0.160.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.160.0/20' })).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + await page.getByRole('cell', { name: '10.0.176.0/20 Subnet Address' }).click(); + await expect(page.getByRole('row', { name: '10.0.176.0/20' })).toHaveCSS('background-color', 'rgb(255, 255, 255)'); + await page.getByText('« Stop Changing Colors').click(); + // Make sure when you're not in color change mode you cannot change colors + await page.getByRole('cell', { name: '10.0.0.0/20 Subnet Address' }).click(); + // Should still be the old color instead of white (the last palette color selected) + await expect(page.getByRole('row', { name: '10.0.0.0/20' })).toHaveCSS('background-color', 'rgb(255, 173, 173)'); +}); + + + + + diff --git a/src/tests/url-sharing.spec.ts b/src/tests/url-sharing.spec.ts new file mode 100644 index 0000000..44fd975 --- /dev/null +++ b/src/tests/url-sharing.spec.ts @@ -0,0 +1,134 @@ +import { test, expect } from '@playwright/test'; + +async function getClipboardText(page) { + return page.evaluate(async () => { + return await navigator.clipboard.readText(); + }); +} + +test('Default URL Share', async ({ page }) => { + await page.goto('https://127.0.0.1:8443/'); + await page.getByText('Copy Shareable URL').click(); + const clipboardUrl = await getClipboardText(page); + expect(clipboardUrl).toContain('/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9GgGwIgDOUoGA5hQL71A'); +}); + +test('Default URL Render', async ({ page }) => { + // This should match default-homepage.spec.ts + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9GgGwIgDOUoGA5hQL71A'); + await expect(page).toHaveTitle(/Visual Subnet Calculator/); + await expect(page.getByRole('heading')).toContainText('Visual Subnet Calculator'); + await expect(page.getByLabel('Network Address')).toHaveValue('10.0.0.0'); + await expect(page.getByLabel('Network Size')).toHaveValue('16'); + await expect(page.locator('#useableHeader')).toContainText('Usable IPs'); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.0.0/16'); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Range of Addresses')).toContainText('10.0.0.0 - 10.0.255.255'); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Usable IPs')).toContainText('10.0.0.1 - 10.0.255.254'); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Hosts')).toContainText('65534'); + await expect(page.getByRole('textbox', { name: '10.0.0.0/16 Note' })).toBeEmpty(); + await expect(page.getByLabel('10.0.0.0/16', { exact: true }).getByLabel('Split', { exact: true })).toContainText('/16'); + // This "default no color" check could maybe be improved. May not be reliable cross-browser. + await expect(page.getByRole('row', { name: '10.0.0.0/16' })).toHaveCSS('background-color', 'rgba(0, 0, 0, 0)'); + await expect(page.getByLabel('Change Colors').locator('span')).toContainText('Change Colors »'); + await expect(page.locator('#copy_url')).toContainText('Copy Shareable URL'); +}); + +test('Reddit Example URL Render (URL v1 - Config v1)', async ({ page }) => { + // This is great to make sure older URLs still load and render properly + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIIwgNCAzlUMAMA6LOD0AmdVWHbbAuSNUvffYjM2gZgZvPwBZiB9AOyggAIgEMALiIAEAYQCmfMbIBOkgLSSAagEslYgK4iANpIDKysMpSIeAY0EBiAJwAjAGYA2V65ABfRIywYDm4qEH5BUQkZeUUVdW1dA2MzJQslKzC7aCc3T28fPxIyfA5WUIDMEvQCENBw6EipOQVlNU0dfSNTc0sETIcXDy9ff1JmYN4BBvEmmNb1AAUACwBPJC0bLpS0jNsHEXQbTmGCworODnpy0gvq-DK6qZAAIT0tQwATLT4Ac0kAQTaAHUtK4tH09tkvB93CIAKwjIpYdylSaCV7vL6-AFtAAy-wAchCsiB7NDYQjTqMyAAODiUai0y5sJl3B5IzB0u61MJPDGfb5-QGLJTfWK7Elk1ww+GIiqOCaheovN4C7HCzQAew2smJDnJsoK1MCLDR0H5WL+z2BoPB1kl0q8zncvjOpBgVQIV0ZgU99zNKsxgsk1vU+KJ9v1HydLrdZBgtwI7IqCcVj3RqstIbaC1FLXSeqh0dczrl7rhad5GaD2NDWp1hdJjpLsdOpyAA'); + await expect(page.getByLabel('Network Address')).toHaveValue('10.0.0.0'); + await expect(page.getByLabel('Network Size')).toHaveValue('20'); + await expect(page.getByLabel('10.0.0.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.0.0/24'); + await expect(page.getByLabel('10.0.1.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.1.0/24'); + await expect(page.getByLabel('10.0.2.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.2.0/24'); + await expect(page.getByLabel('10.0.3.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.3.0/24'); + await expect(page.getByLabel('10.0.4.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.4.0/23'); + await expect(page.getByLabel('10.0.6.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.6.0/23'); + await expect(page.getByLabel('10.0.8.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.8.0/24'); + await expect(page.getByLabel('10.0.9.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.9.0/24'); + await expect(page.getByLabel('10.0.10.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.10.0/23'); + await expect(page.getByLabel('10.0.12.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.12.0/23'); + await expect(page.getByLabel('10.0.14.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.14.0/24'); + await expect(page.getByLabel('10.0.15.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.15.0/24'); + await expect(page.getByRole('textbox', { name: '10.0.0.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.1.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.2.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.3.0/24 Note' })).toHaveValue('Data Center - Physical Servers'); + await expect(page.getByRole('textbox', { name: '10.0.4.0/23 Note' })).toHaveValue('Building A - Wifi'); + await expect(page.getByRole('textbox', { name: '10.0.6.0/23 Note' })).toHaveValue('Building A - LAN'); + await expect(page.getByRole('textbox', { name: '10.0.8.0/24 Note' })).toHaveValue('Building A - Printers'); + await expect(page.getByRole('textbox', { name: '10.0.9.0/24 Note' })).toHaveValue('Building A - Voice'); + await expect(page.getByRole('textbox', { name: '10.0.10.0/23 Note' })).toHaveValue('Building B - Wifi'); + await expect(page.getByRole('textbox', { name: '10.0.12.0/23 Note' })).toHaveValue('Building B - LAN'); + await expect(page.getByRole('textbox', { name: '10.0.14.0/24 Note' })).toHaveValue('Building B - Printers'); + await expect(page.getByRole('textbox', { name: '10.0.15.0/24 Note' })).toHaveValue('Building B - Voice'); + await expect(page.getByRole('row', { name: '10.0.0.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.1.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.2.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.3.0/24' })).toHaveCSS('background-color', 'rgb(160, 196, 255)'); + await expect(page.getByRole('row', { name: '10.0.4.0/23' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.6.0/23' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.8.0/24' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.9.0/24' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.10.0/23' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.12.0/23' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.14.0/24' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.15.0/24' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); +}); + +test('Reddit Example URL Conversion (URL v1 - Config v1 to v2)', async ({ page }) => { + // Basically if a user loads a URL (say v1), we load it, but then only produce the latest version URL (v2) when they copy the URL + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIIwgNCAzlUMAMA6LOD0AmdVWHbbAuSNUvffYjM2gZgZvPwBZiB9AOyggAIgEMALiIAEAYQCmfMbIBOkgLSSAagEslYgK4iANpIDKysMpSIeAY0EBiAJwAjAGYA2V65ABfRIywYDm4qEH5BUQkZeUUVdW1dA2MzJQslKzC7aCc3T28fPxIyfA5WUIDMEvQCENBw6EipOQVlNU0dfSNTc0sETIcXDy9ff1JmYN4BBvEmmNb1AAUACwBPJC0bLpS0jNsHEXQbTmGCworODnpy0gvq-DK6qZAAIT0tQwATLT4Ac0kAQTaAHUtK4tH09tkvB93CIAKwjIpYdylSaCV7vL6-AFtAAy-wAchCsiB7NDYQjTqMyAAODiUai0y5sJl3B5IzB0u61MJPDGfb5-QGLJTfWK7Elk1ww+GIiqOCaheovN4C7HCzQAew2smJDnJsoK1MCLDR0H5WL+z2BoPB1kl0q8zncvjOpBgVQIV0ZgU99zNKsxgsk1vU+KJ9v1HydLrdZBgtwI7IqCcVj3RqstIbaC1FLXSeqh0dczrl7rhad5GaD2NDWp1hdJjpLsdOpyAA'); + await page.getByText('Copy Shareable URL').click(); + const clipboardUrl = await getClipboardText(page); + expect(clipboardUrl).toContain('/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9DBgiAM5SgYDW5IGANjRgLaMB2jA9je9ACICGAF34ACAMIBTVoIkAnEQFoRANQCWswQFd+dEQGU5YOWUQBjVAGIAnEgBmANlu2QAX0RoukUDxADh4qRl5JTUNbV0DWSNZExBzaGs7R2cXN3QeUBhPb1Q-UUlpOUUVdS0dfUNjYniQRIcnV0QAZmyQHzyAwuCRAAUACwBPElVTcsjo2JqLfgxTABYG1LS0Fi9YDLbUACFNVToAE1VWAHMRAEFigHVVW1Vqyyd9+34AVkaQJo2fHb3Dk-PigAZM4AOXuCUezzeS3cDDWMFWoDmGwAHK1vrsDkdThclD1ZEcgpMHrYnq93lZ0dtMX8ccVlBwRhJwbVIeTUogXl9qb9sSItlcbnczA99k4kPZXGkmoiQPZudAflj-gKlMCwSKIWLbBL3gB2DZoOZUxU0vmq3oErrErXiyXLF4mkBK2n8+mM0zMzWs7W6pb+oA'); +}); + +test('Reddit Example URL Render (URL v1 - Config v2)', async ({ page }) => { + // This is great to make sure older URLs still load and render properly + await page.goto('https://127.0.0.1:8443/index.html?c=1N4IgbiBcIEwgNCARlEBGADAOm7g9DBgiAM5SgYDW5IGANjRgLaMB2jA9je9ACICGAF34ACAMIBTVoIkAnEQFoRANQCWswQFd+dEQGU5YOWUQBjVAGIAnEgBmANlu2QAX0RoukUDxADh4qRl5JTUNbV0DWSNZExBzaGs7R2cXN3QeUBhPb1Q-UUlpOUUVdS0dfUNjYniQRIcnV0QAZmyQHzyAwuCRAAUACwBPElVTcsjo2JqLfgxTABYG1LS0Fi9YDLbUACFNVToAE1VWAHMRAEFigHVVW1Vqyyd9+34AVkaQJo2fHb3Dk-PigAZM4AOXuCUezzeS3cDDWMFWoDmGwAHK1vrsDkdThclD1ZEcgpMHrYnq93lZ0dtMX8ccVlBwRhJwbVIeTUogXl9qb9sSItlcbnczA99k4kPZXGkmoiQPZudAflj-gKlMCwSKIWLbBL3gB2DZoOZUxU0vmq3oErrErXiyXLF4mkBK2n8+mM0zMzWs7W6pb+oA'); + await expect(page.getByLabel('Network Address')).toHaveValue('10.0.0.0'); + await expect(page.getByLabel('Network Size')).toHaveValue('20'); + await expect(page.getByLabel('10.0.0.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.0.0/24'); + await expect(page.getByLabel('10.0.1.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.1.0/24'); + await expect(page.getByLabel('10.0.2.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.2.0/24'); + await expect(page.getByLabel('10.0.3.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.3.0/24'); + await expect(page.getByLabel('10.0.4.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.4.0/23'); + await expect(page.getByLabel('10.0.6.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.6.0/23'); + await expect(page.getByLabel('10.0.8.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.8.0/24'); + await expect(page.getByLabel('10.0.9.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.9.0/24'); + await expect(page.getByLabel('10.0.10.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.10.0/23'); + await expect(page.getByLabel('10.0.12.0/23', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.12.0/23'); + await expect(page.getByLabel('10.0.14.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.14.0/24'); + await expect(page.getByLabel('10.0.15.0/24', { exact: true }).getByLabel('Subnet Address')).toContainText('10.0.15.0/24'); + await expect(page.getByRole('textbox', { name: '10.0.0.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.1.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.2.0/24 Note' })).toHaveValue('Data Center - Virtual Servers'); + await expect(page.getByRole('textbox', { name: '10.0.3.0/24 Note' })).toHaveValue('Data Center - Physical Servers'); + await expect(page.getByRole('textbox', { name: '10.0.4.0/23 Note' })).toHaveValue('Building A - Wifi'); + await expect(page.getByRole('textbox', { name: '10.0.6.0/23 Note' })).toHaveValue('Building A - LAN'); + await expect(page.getByRole('textbox', { name: '10.0.8.0/24 Note' })).toHaveValue('Building A - Printers'); + await expect(page.getByRole('textbox', { name: '10.0.9.0/24 Note' })).toHaveValue('Building A - Voice'); + await expect(page.getByRole('textbox', { name: '10.0.10.0/23 Note' })).toHaveValue('Building B - Wifi'); + await expect(page.getByRole('textbox', { name: '10.0.12.0/23 Note' })).toHaveValue('Building B - LAN'); + await expect(page.getByRole('textbox', { name: '10.0.14.0/24 Note' })).toHaveValue('Building B - Printers'); + await expect(page.getByRole('textbox', { name: '10.0.15.0/24 Note' })).toHaveValue('Building B - Voice'); + await expect(page.getByRole('row', { name: '10.0.0.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.1.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.2.0/24' })).toHaveCSS('background-color', 'rgb(155, 246, 255)'); + await expect(page.getByRole('row', { name: '10.0.3.0/24' })).toHaveCSS('background-color', 'rgb(160, 196, 255)'); + await expect(page.getByRole('row', { name: '10.0.4.0/23' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.6.0/23' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.8.0/24' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.9.0/24' })).toHaveCSS('background-color', 'rgb(255, 214, 165)'); + await expect(page.getByRole('row', { name: '10.0.10.0/23' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.12.0/23' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.14.0/24' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); + await expect(page.getByRole('row', { name: '10.0.15.0/24' })).toHaveCSS('background-color', 'rgb(253, 255, 182)'); +}); + + +//test('Test', async ({ page }) => { +// await page.goto('https://127.0.0.1:8443/'); +//}); +