Skip to content

Commit 1eedbc1

Browse files
committed
test for edit modal
1 parent 89e1792 commit 1eedbc1

File tree

5 files changed

+127
-23
lines changed

5 files changed

+127
-23
lines changed

app/pages/project/networking/VpcPage/VpcPage.spec.ts

Lines changed: 112 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import {
2+
clickByRole,
23
renderAppAt,
34
screen,
4-
waitForElementToBeRemoved,
5-
clickByRole,
65
typeByRole,
6+
waitForElementToBeRemoved,
7+
userEvent,
8+
getByRole,
79
} from 'app/test-utils'
810
import { defaultFirewallRules } from '@oxide/api-mocks'
11+
import { logRoles } from '@testing-library/react'
912

1013
describe('VpcPage', () => {
1114
describe('subnet', () => {
@@ -22,7 +25,7 @@ describe('VpcPage', () => {
2225
expect(screen.queryByTestId('create-vpc-subnet-modal')).toBeNull()
2326

2427
// click button to open modal
25-
clickByRole('button', 'New subnet')
28+
await clickByRole('button', 'New subnet')
2629

2730
// modal is open
2831
screen.getByRole('dialog', { name: 'Create subnet' })
@@ -32,7 +35,7 @@ describe('VpcPage', () => {
3235
typeByRole('textbox', 'Name', 'mock-subnet-2')
3336

3437
// submit the form
35-
clickByRole('button', 'Create subnet')
38+
await clickByRole('button', 'Create subnet')
3639

3740
// wait for modal to close
3841
await waitForElementToBeRemoved(() =>
@@ -48,7 +51,7 @@ describe('VpcPage', () => {
4851
describe('firewall rule', () => {
4952
it('create works', async () => {
5053
renderAppAt('/orgs/maze-war/projects/mock-project/vpcs/mock-vpc')
51-
clickByRole('tab', 'Firewall Rules')
54+
await clickByRole('tab', 'Firewall Rules')
5255

5356
// default rules show up in the table
5457
for (const { name } of defaultFirewallRules) {
@@ -63,45 +66,45 @@ describe('VpcPage', () => {
6366
).toBeNull()
6467

6568
// click button to open modal
66-
clickByRole('button', 'New rule')
69+
await clickByRole('button', 'New rule')
6770

6871
// modal is open
69-
await screen.findByText('Create firewall rule')
72+
screen.getByRole('dialog', { name: 'Create firewall rule' })
7073

7174
typeByRole('textbox', 'Name', 'my-new-rule')
7275

73-
clickByRole('radio', 'Outgoing')
76+
await clickByRole('radio', 'Outgoing')
7477

7578
// input type="number" becomes spinbutton for some reason
7679
typeByRole('spinbutton', 'Priority', '5')
7780

78-
clickByRole('button', 'Target type')
79-
clickByRole('option', 'VPC')
81+
await clickByRole('button', 'Target type')
82+
await clickByRole('option', 'VPC')
8083
typeByRole('textbox', 'Target name', 'my-target-vpc')
81-
clickByRole('button', 'Add target')
84+
await clickByRole('button', 'Add target')
8285

8386
// target is added to targets table
8487
screen.getByRole('cell', { name: 'my-target-vpc' })
8588

86-
clickByRole('button', 'Host type')
87-
clickByRole('option', 'Instance')
88-
typeByRole('textbox', 'Value', 'my-target-instance')
89-
clickByRole('button', 'Add host filter')
89+
await clickByRole('button', 'Host type')
90+
await clickByRole('option', 'Instance')
91+
typeByRole('textbox', 'Value', 'host-filter-instance')
92+
await clickByRole('button', 'Add host filter')
9093

9194
// host is added to hosts table
92-
screen.getByRole('cell', { name: 'my-target-instance' })
95+
screen.getByRole('cell', { name: 'host-filter-instance' })
9396

9497
// TODO: test invalid port range once I put an error message in there
9598
typeByRole('textbox', 'Port filter', '123-456')
96-
clickByRole('button', 'Add port filter')
99+
await clickByRole('button', 'Add port filter')
97100

98101
// port range is added to port ranges table
99102
screen.getByRole('cell', { name: '123-456' })
100103

101-
clickByRole('checkbox', 'UDP')
104+
await clickByRole('checkbox', 'UDP')
102105

103106
// submit the form
104-
clickByRole('button', 'Create rule')
107+
await clickByRole('button', 'Create rule')
105108

106109
// wait for modal to close
107110
await waitForElementToBeRemoved(
@@ -112,9 +115,99 @@ describe('VpcPage', () => {
112115

113116
// table refetches and now includes the new rule as well as the originals
114117
await screen.findByText('my-new-rule')
118+
screen.getByRole('cell', {
119+
name: 'instance host-filter-instance UDP 123-456',
120+
})
121+
115122
for (const { name } of defaultFirewallRules) {
116123
screen.getByText(name)
117124
}
118125
}, 10000)
126+
127+
it('edit works', async () => {
128+
renderAppAt('/orgs/maze-war/projects/mock-project/vpcs/mock-vpc')
129+
await clickByRole('tab', 'Firewall Rules')
130+
131+
// default rules show up in the table
132+
for (const { name } of defaultFirewallRules) {
133+
await screen.findByText(name)
134+
}
135+
expect(screen.getAllByRole('row').length).toEqual(5) // 4 + header
136+
137+
// the one we'll be adding is not there
138+
expect(screen.queryByRole('cell', { name: 'new-rule-name' })).toBeNull()
139+
140+
// modal is not already open
141+
expect(
142+
screen.queryByRole('dialog', { name: 'Edit firewall rule' })
143+
).toBeNull()
144+
145+
// click more button on allow-icmp row to get menu, then click Edit
146+
const allowIcmpRow = screen.getByRole('row', { name: /allow-icmp/ })
147+
const more = getByRole(allowIcmpRow, 'button', { name: 'More' })
148+
await userEvent.click(more)
149+
await clickByRole('menuitem', 'Edit')
150+
151+
// now the modal is open
152+
screen.getByRole('dialog', { name: 'Edit firewall rule' })
153+
154+
// name is populated
155+
const name = screen.getByRole('textbox', {
156+
name: 'Name',
157+
}) as HTMLInputElement
158+
expect(name.value).toEqual('allow-icmp')
159+
160+
// priority is populated
161+
const priority = screen.getByRole('spinbutton', {
162+
name: 'Priority',
163+
}) as HTMLInputElement
164+
expect(priority.value).toEqual('65534')
165+
166+
// protocol is populated
167+
expect(screen.getByRole('checkbox', { name: /ICMP/ })).toBeChecked()
168+
expect(screen.getByRole('checkbox', { name: /TCP/ })).not.toBeChecked()
169+
expect(screen.getByRole('checkbox', { name: /UDP/ })).not.toBeChecked()
170+
171+
// targets default vpc
172+
screen.getByRole('cell', { name: 'vpc' })
173+
screen.getByRole('cell', { name: 'default' })
174+
175+
// update name
176+
await userEvent.clear(name)
177+
await userEvent.type(name, 'new-rule-name')
178+
179+
await clickByRole('button', 'Host type')
180+
await clickByRole('option', 'Instance')
181+
typeByRole('textbox', 'Value', 'edit-filter-instance')
182+
await clickByRole('button', 'Add host filter')
183+
184+
// host is added to hosts table
185+
screen.getByRole('cell', { name: 'edit-filter-instance' })
186+
187+
// submit the form
188+
await clickByRole('button', 'Update rule')
189+
190+
// wait for modal to close
191+
await waitForElementToBeRemoved(
192+
() => screen.queryByText('Edit firewall rule'),
193+
// fails in CI without a longer timeout (default 1000). boo
194+
{ timeout: 2000 }
195+
)
196+
197+
// table refetches and now includes the updated rule name, not the old name
198+
await screen.findByText('new-rule-name')
199+
expect(screen.queryByRole('cell', { name: 'allow-icmp' })).toBeNull()
200+
expect(screen.getAllByRole('row').length).toEqual(5) // 4 + header
201+
202+
screen.getByRole('cell', {
203+
name: 'instance edit-filter-instance ICMP',
204+
})
205+
206+
// other 3 rules are still there
207+
const rest = defaultFirewallRules.filter((r) => r.name !== 'allow-icmp')
208+
for (const { name } of rest) {
209+
screen.getByRole('cell', { name })
210+
}
211+
}, 15000)
119212
})
120213
})

app/pages/project/networking/VpcPage/modals/firewall-rules.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,8 @@ type EditProps = {
498498
existingRules: VpcFirewallRule[]
499499
}
500500

501+
// TODO: this whole thing. shouldn't take much to fill in the initialValues
502+
// based on the rule being edited
501503
export function EditFirewallRuleModal({
502504
onDismiss,
503505
orgName,
@@ -527,7 +529,7 @@ export function EditFirewallRuleModal({
527529
return (
528530
<SideModal
529531
id="edit-firewall-rule-modal"
530-
title="Edit rule"
532+
title="Edit firewall rule"
531533
onDismiss={dismiss}
532534
>
533535
<Formik

app/test-utils.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,16 @@ export function renderAppAt(url: string) {
9191
****************************************/
9292

9393
export * from '@testing-library/react'
94-
export { customRender as render }
94+
import userEvent from '@testing-library/user-event'
95+
export { customRender as render, userEvent }
9596

9697
// convenience functions so we can click and type in a one-liner. these were
9798
// initially created to use the user-event library, but it was remarkably slow.
9899
// see if those issues are improved before trying that again
99100

100-
export function clickByRole(role: string, name: string) {
101+
export async function clickByRole(role: string, name: string) {
101102
const element = screen.getByRole(role, { name })
102-
fireEvent.click(element)
103+
await userEvent.click(element)
103104
}
104105

105106
export function typeByRole(role: string, name: string, text: string) {

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"@testing-library/jest-dom": "^5.14.1",
7979
"@testing-library/react": "^12.0.0",
8080
"@testing-library/react-hooks": "^7.0.1",
81+
"@testing-library/user-event": "14.0.0-beta.10",
8182
"@types/jscodeshift": "^0.11.2",
8283
"@types/mousetrap": "^1.6.8",
8384
"@types/node": "^16.11.9",

yarn.lock

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3103,6 +3103,13 @@
31033103
"@babel/runtime" "^7.12.5"
31043104
"@testing-library/dom" "^8.0.0"
31053105

3106+
"@testing-library/[email protected]":
3107+
version "14.0.0-beta.10"
3108+
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.0.0-beta.10.tgz#7ac68e9542e30aa1744f354a7f026d7a70647de2"
3109+
integrity sha512-a3iA66OE1PfcDc1BlfGm4yqgRid78en4GtAEsn6PwMIteVJzZe1aWztvZsWbEPX85y4JXaPwRiLD9aSloi0cwA==
3110+
dependencies:
3111+
"@babel/runtime" "^7.12.5"
3112+
31063113
"@tootallnate/once@2":
31073114
version "2.0.0"
31083115
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"

0 commit comments

Comments
 (0)