Skip to content

Commit 0f9184b

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

File tree

5 files changed

+113
-21
lines changed

5 files changed

+113
-21
lines changed

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

Lines changed: 98 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
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'
911

@@ -22,7 +24,7 @@ describe('VpcPage', () => {
2224
expect(screen.queryByTestId('create-vpc-subnet-modal')).toBeNull()
2325

2426
// click button to open modal
25-
clickByRole('button', 'New subnet')
27+
await clickByRole('button', 'New subnet')
2628

2729
// modal is open
2830
screen.getByRole('dialog', { name: 'Create subnet' })
@@ -32,7 +34,7 @@ describe('VpcPage', () => {
3234
typeByRole('textbox', 'Name', 'mock-subnet-2')
3335

3436
// submit the form
35-
clickByRole('button', 'Create subnet')
37+
await clickByRole('button', 'Create subnet')
3638

3739
// wait for modal to close
3840
await waitForElementToBeRemoved(() =>
@@ -48,7 +50,7 @@ describe('VpcPage', () => {
4850
describe('firewall rule', () => {
4951
it('create works', async () => {
5052
renderAppAt('/orgs/maze-war/projects/mock-project/vpcs/mock-vpc')
51-
clickByRole('tab', 'Firewall Rules')
53+
await clickByRole('tab', 'Firewall Rules')
5254

5355
// default rules show up in the table
5456
for (const { name } of defaultFirewallRules) {
@@ -63,45 +65,45 @@ describe('VpcPage', () => {
6365
).toBeNull()
6466

6567
// click button to open modal
66-
clickByRole('button', 'New rule')
68+
await clickByRole('button', 'New rule')
6769

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

7173
typeByRole('textbox', 'Name', 'my-new-rule')
7274

73-
clickByRole('radio', 'Outgoing')
75+
await clickByRole('radio', 'Outgoing')
7476

7577
// input type="number" becomes spinbutton for some reason
7678
typeByRole('spinbutton', 'Priority', '5')
7779

78-
clickByRole('button', 'Target type')
79-
clickByRole('option', 'VPC')
80+
await clickByRole('button', 'Target type')
81+
await clickByRole('option', 'VPC')
8082
typeByRole('textbox', 'Target name', 'my-target-vpc')
81-
clickByRole('button', 'Add target')
83+
await clickByRole('button', 'Add target')
8284

8385
// target is added to targets table
8486
screen.getByRole('cell', { name: 'my-target-vpc' })
8587

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

9193
// host is added to hosts table
9294
screen.getByRole('cell', { name: 'my-target-instance' })
9395

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

98100
// port range is added to port ranges table
99101
screen.getByRole('cell', { name: '123-456' })
100102

101-
clickByRole('checkbox', 'UDP')
103+
await clickByRole('checkbox', 'UDP')
102104

103105
// submit the form
104-
clickByRole('button', 'Create rule')
106+
await clickByRole('button', 'Create rule')
105107

106108
// wait for modal to close
107109
await waitForElementToBeRemoved(
@@ -112,9 +114,88 @@ describe('VpcPage', () => {
112114

113115
// table refetches and now includes the new rule as well as the originals
114116
await screen.findByText('my-new-rule')
117+
118+
// TODO: assert the target and host show up in the row
119+
115120
for (const { name } of defaultFirewallRules) {
116121
screen.getByText(name)
117122
}
118123
}, 10000)
124+
125+
it('edit works', async () => {
126+
renderAppAt('/orgs/maze-war/projects/mock-project/vpcs/mock-vpc')
127+
await clickByRole('tab', 'Firewall Rules')
128+
129+
// default rules show up in the table
130+
for (const { name } of defaultFirewallRules) {
131+
await screen.findByText(name)
132+
}
133+
// the one we'll be adding is not there
134+
expect(screen.queryByRole('cell', { name: 'new-rule-name' })).toBeNull()
135+
136+
// modal is not already open
137+
expect(
138+
screen.queryByRole('dialog', { name: 'Edit firewall rule' })
139+
).toBeNull()
140+
141+
// click more button on allow-icmp row to get menu, then click Edit
142+
const allowIcmpRow = screen.getByRole('row', { name: /allow-icmp/ })
143+
const more = getByRole(allowIcmpRow, 'button', { name: 'More' })
144+
await userEvent.click(more)
145+
await clickByRole('menuitem', 'Edit')
146+
147+
// now the modal is open
148+
screen.getByRole('dialog', { name: 'Edit firewall rule' })
149+
150+
// name is populated
151+
const name = screen.getByRole('textbox', {
152+
name: 'Name',
153+
}) as HTMLInputElement
154+
expect(name.value).toEqual('allow-icmp')
155+
156+
// priority is populated
157+
const priority = screen.getByRole('spinbutton', {
158+
name: 'Priority',
159+
}) as HTMLInputElement
160+
expect(priority.value).toEqual('65534')
161+
162+
// protocol is populated
163+
expect(screen.getByRole('checkbox', { name: /ICMP/ })).toBeChecked()
164+
expect(screen.getByRole('checkbox', { name: /TCP/ })).not.toBeChecked()
165+
expect(screen.getByRole('checkbox', { name: /UDP/ })).not.toBeChecked()
166+
167+
// targets default vpc
168+
screen.getByRole('cell', { name: 'vpc' })
169+
screen.getByRole('cell', { name: 'default' })
170+
171+
// update name
172+
await userEvent.clear(name)
173+
await userEvent.type(name, 'new-rule-name')
174+
175+
// TODO: update more things in the form
176+
177+
// submit the form
178+
await clickByRole('button', 'Update rule')
179+
180+
// wait for modal to close
181+
await waitForElementToBeRemoved(
182+
() => screen.queryByText('Edit firewall rule'),
183+
// fails in CI without a longer timeout (default 1000). boo
184+
{ timeout: 2000 }
185+
)
186+
187+
// table refetches and now includes the updated rule name, not the old name
188+
await screen.findByText('new-rule-name')
189+
expect(screen.queryByRole('cell', { name: 'allow-icmp' })).toBeNull()
190+
191+
// TODO: assert other stuff is in the row
192+
// const updatedRow = screen.getByRole('row', { name: /new-rule-name/ })
193+
194+
// other 3 rules are still there
195+
const rest = defaultFirewallRules.filter((r) => r.name !== 'allow-icmp')
196+
for (const { name } of rest) {
197+
screen.getByRole('cell', { name })
198+
}
199+
}, 10000)
119200
})
120201
})

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)