diff --git a/app/components/form/fields/SubnetListbox.tsx b/app/components/form/fields/SubnetListbox.tsx index 5d81c188b..549d4b9a8 100644 --- a/app/components/form/fields/SubnetListbox.tsx +++ b/app/components/form/fields/SubnetListbox.tsx @@ -55,7 +55,7 @@ export function SubnetListbox< items={subnets.map(({ name }) => ({ value: name, label: name }))} disabled={!vpcExists} control={control} - placeholder="Select a subnet" + placeholder="Select a VPC subnet" noItemsPlaceholder={vpcName ? 'No subnets found' : 'Select a VPC to see subnets'} /> ) diff --git a/app/forms/network-interface-create.tsx b/app/forms/network-interface-create.tsx index fb2e1614d..0694e5f29 100644 --- a/app/forms/network-interface-create.tsx +++ b/app/forms/network-interface-create.tsx @@ -136,7 +136,7 @@ export function CreateNetworkInterfaceForm({ /> @@ -175,7 +175,7 @@ export function CreateNetworkInterfaceForm({ {(ipStackType === 'v6' || ipStackType === 'dual_stack') && ( diff --git a/app/forms/subnet-create.tsx b/app/forms/subnet-create.tsx index 071eabb54..ddfe14501 100644 --- a/app/forms/subnet-create.tsx +++ b/app/forms/subnet-create.tsx @@ -64,7 +64,7 @@ export default function CreateSubnetForm() { createSubnet.mutate({ diff --git a/app/forms/subnet-edit.tsx b/app/forms/subnet-edit.tsx index c34e9667e..8b5bcb61d 100644 --- a/app/forms/subnet-edit.tsx +++ b/app/forms/subnet-edit.tsx @@ -79,7 +79,7 @@ export default function EditSubnetForm() { { updateSubnet.mutate({ diff --git a/app/forms/vpc-router-route-common.tsx b/app/forms/vpc-router-route-common.tsx index 6258ae79c..4043f5f49 100644 --- a/app/forms/vpc-router-route-common.tsx +++ b/app/forms/vpc-router-route-common.tsx @@ -66,7 +66,7 @@ const targetTypes: Record, string const destinationValuePlaceholder: Record = { ip: 'Enter an IP', ip_net: 'Enter an IP network', - subnet: 'Select a subnet', + subnet: 'Select a VPC subnet', vpc: undefined, } diff --git a/app/pages/project/vpcs/VpcPage.tsx b/app/pages/project/vpcs/VpcPage.tsx index 627fea6de..100984ac6 100644 --- a/app/pages/project/vpcs/VpcPage.tsx +++ b/app/pages/project/vpcs/VpcPage.tsx @@ -75,7 +75,7 @@ export default function VpcPage() { Firewall Rules - Subnets + VPC Subnets Routers Internet Gateways diff --git a/app/pages/project/vpcs/VpcSubnetsTab.tsx b/app/pages/project/vpcs/VpcSubnetsTab.tsx index 00f9ce52e..198a722ca 100644 --- a/app/pages/project/vpcs/VpcSubnetsTab.tsx +++ b/app/pages/project/vpcs/VpcSubnetsTab.tsx @@ -35,7 +35,7 @@ export async function clientLoader({ params }: LoaderFunctionArgs) { return null } -export const handle = { crumb: 'Subnets' } +export const handle = { crumb: 'VPC Subnets' } export default function VpcSubnetsTab() { const vpcSelector = useVpcSelector() @@ -44,7 +44,7 @@ export default function VpcSubnetsTab() { onSuccess() { queryClient.invalidateEndpoint('vpcSubnetList') // We only have the ID, so will show a generic confirmation message - addToast({ content: 'Subnet deleted' }) + addToast({ content: 'VPC subnet deleted' }) }, }) @@ -90,8 +90,8 @@ export default function VpcSubnetsTab() { const emptyState = ( ) @@ -106,7 +106,7 @@ export default function VpcSubnetsTab() { return ( <>
- New subnet + New VPC subnet
{table} diff --git a/app/util/__snapshots__/path-builder.spec.ts.snap b/app/util/__snapshots__/path-builder.spec.ts.snap index 62c7e050b..ad7d56793 100644 --- a/app/util/__snapshots__/path-builder.spec.ts.snap +++ b/app/util/__snapshots__/path-builder.spec.ts.snap @@ -1195,7 +1195,7 @@ exports[`breadcrumbs 2`] = ` "path": "/projects/p/vpcs/v/firewall-rules", }, { - "label": "Subnets", + "label": "VPC Subnets", "path": "/projects/p/vpcs/v/", }, ], @@ -1217,7 +1217,7 @@ exports[`breadcrumbs 2`] = ` "path": "/projects/p/vpcs/v/firewall-rules", }, { - "label": "Subnets", + "label": "VPC Subnets", "path": "/projects/p/vpcs/v/", }, ], @@ -1239,7 +1239,7 @@ exports[`breadcrumbs 2`] = ` "path": "/projects/p/vpcs/v/firewall-rules", }, { - "label": "Subnets", + "label": "VPC Subnets", "path": "/projects/p/vpcs/v/", }, ], diff --git a/test/e2e/instance-networking.e2e.ts b/test/e2e/instance-networking.e2e.ts index 91d8a09de..cc18309e8 100644 --- a/test/e2e/instance-networking.e2e.ts +++ b/test/e2e/instance-networking.e2e.ts @@ -58,8 +58,8 @@ test('Instance networking tab — NIC table', async ({ page }) => { await expectVisible(page, [ 'role=heading[name="Add network interface"]', 'role=textbox[name="Description"]', - 'role=textbox[name="IPv4 Address"]', - 'role=textbox[name="IPv6 Address"]', + 'role=textbox[name="IPv4 address"]', + 'role=textbox[name="IPv6 address"]', ]) await page.getByRole('textbox', { name: 'Name' }).fill('nic-2') diff --git a/test/e2e/network-interface-create.e2e.ts b/test/e2e/network-interface-create.e2e.ts index 9d54f0994..d8d2c3055 100644 --- a/test/e2e/network-interface-create.e2e.ts +++ b/test/e2e/network-interface-create.e2e.ts @@ -22,12 +22,12 @@ test('can create a NIC with a specified IP address', async ({ page }) => { await page.getByLabel('Name').fill('nic-1') await page.getByLabel('VPC', { exact: true }).click() await page.getByRole('option', { name: 'mock-vpc' }).click() - await page.getByRole('dialog').getByRole('button', { name: 'Subnet' }).click() + await page.getByRole('dialog').getByRole('button', { name: 'VPC subnet' }).click() await page.getByRole('option', { name: 'mock-subnet', exact: true }).click() // Select IPv4 only await page.getByRole('radio', { name: 'IPv4', exact: true }).click() - await page.getByLabel('IPv4 Address').fill('1.2.3.4') + await page.getByLabel('IPv4 address').fill('1.2.3.4') const sidebar = page.getByRole('dialog', { name: 'Add network interface' }) @@ -52,12 +52,12 @@ test('can create a NIC with a blank IP address', async ({ page }) => { await page.getByLabel('Name').fill('nic-2') await page.getByLabel('VPC', { exact: true }).click() await page.getByRole('option', { name: 'mock-vpc' }).click() - await page.getByRole('dialog').getByRole('button', { name: 'Subnet' }).click() + await page.getByRole('dialog').getByRole('button', { name: 'VPC subnet' }).click() await page.getByRole('option', { name: 'mock-subnet', exact: true }).click() // Dual-stack is selected by default, so both fields should be visible // make sure the IPv4 address field has a non-conforming bit of text in it - await page.getByLabel('IPv4 Address').fill('x') + await page.getByLabel('IPv4 address').fill('x') // try to submit it const sidebar = page.getByRole('dialog', { name: 'Add network interface' }) @@ -67,8 +67,8 @@ test('can create a NIC with a blank IP address', async ({ page }) => { await expect(sidebar.getByText('Zod error for body')).toBeVisible() // make sure both IP address fields have spaces in them - await page.getByLabel('IPv4 Address').fill(' ') - await page.getByLabel('IPv6 Address').fill(' ') + await page.getByLabel('IPv4 address').fill(' ') + await page.getByLabel('IPv6 address').fill(' ') // test that the form can be submitted and a new network interface is created await sidebar.getByRole('button', { name: 'Add network interface' }).click() @@ -92,12 +92,12 @@ test('can create a NIC with IPv6 only', async ({ page }) => { await page.getByLabel('Name').fill('nic-3') await page.getByLabel('VPC', { exact: true }).click() await page.getByRole('option', { name: 'mock-vpc' }).click() - await page.getByRole('dialog').getByRole('button', { name: 'Subnet' }).click() + await page.getByRole('dialog').getByRole('button', { name: 'VPC subnet' }).click() await page.getByRole('option', { name: 'mock-subnet', exact: true }).click() // Select IPv6 only await page.getByRole('radio', { name: 'IPv6', exact: true }).click() - await page.getByLabel('IPv6 Address').fill('::1') + await page.getByLabel('IPv6 address').fill('::1') const sidebar = page.getByRole('dialog', { name: 'Add network interface' }) await sidebar.getByRole('button', { name: 'Add network interface' }).click() @@ -117,12 +117,12 @@ test('can create a NIC with dual-stack and explicit IPs', async ({ page }) => { await page.getByLabel('Name').fill('nic-4') await page.getByLabel('VPC', { exact: true }).click() await page.getByRole('option', { name: 'mock-vpc' }).click() - await page.getByRole('dialog').getByRole('button', { name: 'Subnet' }).click() + await page.getByRole('dialog').getByRole('button', { name: 'VPC subnet' }).click() await page.getByRole('option', { name: 'mock-subnet', exact: true }).click() // Dual-stack is selected by default - await page.getByLabel('IPv4 Address').fill('10.0.0.5') - await page.getByLabel('IPv6 Address').fill('fd00::5') + await page.getByLabel('IPv4 address').fill('10.0.0.5') + await page.getByLabel('IPv6 address').fill('fd00::5') const sidebar = page.getByRole('dialog', { name: 'Add network interface' }) await sidebar.getByRole('button', { name: 'Add network interface' }).click() diff --git a/test/e2e/networking.e2e.ts b/test/e2e/networking.e2e.ts index 583b5dc01..bde6b045e 100644 --- a/test/e2e/networking.e2e.ts +++ b/test/e2e/networking.e2e.ts @@ -7,13 +7,7 @@ */ import { expect, test } from '@playwright/test' -import { - clickRowAction, - closeToast, - expectNotVisible, - expectRowVisible, - expectVisible, -} from './utils' +import { clickRowAction, closeToast, expectRowVisible, expectVisible } from './utils' test('Create and edit VPC', async ({ page }) => { await page.goto('/projects/mock-project') @@ -84,42 +78,36 @@ test('Create and edit subnet', async ({ page }) => { 'role=cell[name="allow-icmp"]', ]) - await page.getByRole('tab', { name: 'Subnets' }).click() + await page.getByRole('tab', { name: 'VPC Subnets' }).click() // Create subnet - await page.click('role=link[name="New subnet"]') - await expectVisible(page, [ - 'role=heading[name="Create subnet"]', - 'role=button[name="Create subnet"]', - ]) - await page.fill('role=textbox[name="Name"]', 'new-subnet') - await page.fill('role=textbox[name="IPv4 block"]', '10.1.1.1/24') - await page.click('role=button[name="Create subnet"]') + await page.getByRole('link', { name: 'New VPC subnet' }).click() + const createDialog = page.getByRole('dialog', { name: 'Create VPC subnet' }) + await expect(createDialog).toBeVisible() + await expect( + createDialog.getByRole('button', { name: 'Create VPC subnet' }) + ).toBeVisible() + await createDialog.getByRole('textbox', { name: 'Name' }).fill('new-subnet') + await createDialog.getByRole('textbox', { name: 'IPv4 block' }).fill('10.1.1.1/24') + await createDialog.getByRole('button', { name: 'Create VPC subnet' }).click() // Edit subnet - await expectVisible(page, ['role=cell[name="new-subnet"]']) - await page - .locator('role=row', { hasText: 'new-subnet' }) - .locator('role=button[name="Row actions"]') - .click() - await page.click('role=menuitem[name="Edit"]') + await expect(page.getByRole('cell', { name: 'new-subnet' })).toBeVisible() + await clickRowAction(page, 'new-subnet', 'Edit') - await expectVisible(page, [ - 'role=heading[name="Edit subnet"]', - 'role=button[name="Update subnet"]', - ]) - await page.fill('role=textbox[name="Name"]', 'edited-subnet') - await page.fill('role=textbox[name="Description"]', 'behold') - await page.click('role=button[name="Update subnet"]') + const editDialog = page.getByRole('dialog', { name: 'Edit VPC subnet' }) + await expect(editDialog).toBeVisible() + await expect(editDialog.getByRole('button', { name: 'Update VPC subnet' })).toBeVisible() + await editDialog.getByRole('textbox', { name: 'Name' }).fill('edited-subnet') + await editDialog.getByRole('textbox', { name: 'Description' }).fill('behold') + await editDialog.getByRole('button', { name: 'Update VPC subnet' }).click() - await expectNotVisible(page, ['role=cell[name="new-subnet"]']) - await expectVisible(page, ['role=cell[name="edited-subnet"]']) + await expect(page.getByRole('cell', { name: 'new-subnet' })).toBeHidden() + await expect(page.getByRole('cell', { name: 'edited-subnet' })).toBeVisible() // Firewall rules - await page.click('role=tab[name="Firewall Rules"]') - await expectVisible(page, [ - 'role=cell[name="allow-icmp"]', - 'role=cell[name="allow-internal-inbound"]', - 'role=cell[name="allow-ssh"]', - ]) + await page.getByRole('tab', { name: 'Firewall Rules' }).click() + await expect(page.getByRole('cell', { name: 'allow-icmp' })).toBeVisible() + await expect(page.getByRole('cell', { name: 'allow-internal-inbound' })).toBeVisible() + await expect(page.getByRole('cell', { name: 'allow-ssh' })).toBeVisible() }) diff --git a/test/e2e/vpcs.e2e.ts b/test/e2e/vpcs.e2e.ts index c4b8885bb..9361de732 100644 --- a/test/e2e/vpcs.e2e.ts +++ b/test/e2e/vpcs.e2e.ts @@ -76,7 +76,7 @@ test('can edit VPC', async ({ page }) => { test('can create and delete subnet', async ({ page }) => { await page.goto('/projects/mock-project/vpcs/mock-vpc') - await page.getByRole('tab', { name: 'Subnets' }).click() + await page.getByRole('tab', { name: 'VPC Subnets' }).click() // two rows in table: mock-subnet and mock-subnet-2 const table = page.getByRole('table') const rows = page.getByRole('table').getByRole('row') @@ -89,9 +89,9 @@ test('can create and delete subnet', async ({ page }) => { }) // open modal, fill out form, submit - await page.getByRole('link', { name: 'New subnet' }).click() + await page.getByRole('link', { name: 'New VPC subnet' }).click() - const dialog = page.getByRole('dialog', { name: 'Create subnet' }) + const dialog = page.getByRole('dialog', { name: 'Create VPC subnet' }) await expect(dialog).toBeVisible() await dialog.getByRole('textbox', { name: 'Name' }).fill('mock-subnet-3') @@ -101,7 +101,7 @@ test('can create and delete subnet', async ({ page }) => { await dialog.getByRole('textbox', { name: 'IPv6 block' }).fill('abc') await dialog.getByRole('textbox', { name: 'IPv6 block' }).clear() - await dialog.getByRole('button', { name: 'Create subnet' }).click() + await dialog.getByRole('button', { name: 'Create VPC subnet' }).click() await expect(dialog).toBeHidden() await expect(rows).toHaveCount(4) @@ -126,7 +126,7 @@ test('can create and delete subnet', async ({ page }) => { test('can create and update subnets with a custom router', async ({ page }) => { await page.goto('/projects/mock-project/vpcs/mock-vpc/subnets') - await page.getByRole('link', { name: 'New subnet' }).click() + await page.getByRole('link', { name: 'New VPC subnet' }).click() const table = page.getByRole('table') const rows = table.getByRole('row') @@ -137,7 +137,7 @@ test('can create and update subnets with a custom router', async ({ page }) => { 'IP Block': expect.stringContaining('10.1.1.1/24'), }) - const dialog = page.getByRole('dialog', { name: 'Create subnet' }) + const dialog = page.getByRole('dialog', { name: 'Create VPC subnet' }) await expect(dialog).toBeVisible() await page.getByRole('textbox', { name: 'Name' }).fill('mock-subnet-3') @@ -146,7 +146,7 @@ test('can create and update subnets with a custom router', async ({ page }) => { await page.getByRole('button', { name: 'Custom router' }).click() await page.getByRole('option', { name: 'mock-custom-router' }).click() - await page.getByRole('button', { name: 'Create subnet' }).click() + await page.getByRole('button', { name: 'Create VPC subnet' }).click() await expect(dialog).toBeHidden() await expect(rows).toHaveCount(4) @@ -160,7 +160,7 @@ test('can create and update subnets with a custom router', async ({ page }) => { await page.getByRole('link', { name: 'mock-subnet-3' }).click() await page.getByRole('button', { name: 'Custom router' }).click() await page.getByRole('option', { name: 'None' }).click() - await page.getByRole('button', { name: 'Update subnet' }).click() + await page.getByRole('button', { name: 'Update VPC subnet' }).click() await expect(dialog).toBeHidden() await expectRowVisible(table, {