-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathdisks.e2e.ts
More file actions
281 lines (222 loc) · 11.1 KB
/
disks.e2e.ts
File metadata and controls
281 lines (222 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import {
clickRowAction,
expect,
expectNoToast,
expectRowVisible,
expectToast,
fillNumberInput,
propertiesTableValue,
test,
} from './utils'
test('Disk detail side modal', async ({ page }) => {
await page.goto('/projects/mock-project/disks')
await page.getByRole('link', { name: 'disk-1', exact: true }).click()
const modal = page.getByRole('dialog', { name: 'Disk details' })
await expect(modal).toBeVisible()
await expect(modal.getByText('disk-1')).toBeVisible()
await expect(modal.getByText('2 GiB')).toBeVisible()
await expect(modal.getByText('2,048 bytes')).toBeVisible() // block size
await expect(propertiesTableValue(modal, 'Read only')).toHaveText('False')
})
test('Read-only disk shows badge in table and detail', async ({ page }) => {
await page.goto('/projects/mock-project/disks')
const table = page.getByRole('table')
// The read-only disk has a "Read only" badge in the name cell
const readOnlyRow = table.getByRole('row', { name: /read-only-disk/ })
await expect(readOnlyRow.getByText('Read only', { exact: true })).toBeVisible()
// A regular disk does not
const regularRow = table.getByRole('row', { name: /disk-1 db1/ })
await expect(regularRow.getByText('Read only', { exact: true })).toBeHidden()
// Detail modal shows read-only as True
await page.getByRole('link', { name: 'read-only-disk' }).click()
const modal = page.getByRole('dialog', { name: 'Disk details' })
await expect(propertiesTableValue(modal, 'Read only')).toHaveText('True')
})
test('List disks and snapshot', async ({ page }) => {
await page.goto('/projects/mock-project/disks')
const table = page.getByRole('table')
await expect(table.getByRole('row')).toHaveCount(16) // 15 + header
// check one attached and one not attached
await expectRowVisible(table, {
Instance: 'db1',
name: 'disk-1',
size: '2 GiB',
state: 'attached',
})
await expectRowVisible(table, {
Instance: '—',
name: 'disk-3',
size: '6 GiB',
state: 'detached',
})
await clickRowAction(page, 'disk-1 db1', 'Snapshot')
await expectToast(page, 'Creating snapshot of disk disk-1')
// expectToast should have closed the toast already, but verify
await expectNoToast(page, 'Creating snapshot of disk disk-1')
// Next line is a little awkward, but we don't actually know what the snapshot name will be
await expectToast(page, /Snapshot disk-1-[a-z0-9]{6} created/)
})
test('Disk snapshot error', async ({ page }) => {
await page.goto('/projects/mock-project/disks')
// special disk that triggers snapshot error
await clickRowAction(page, 'disk-snapshot-error', 'Snapshot')
await expectToast(page, 'Creating snapshot of disk disk-snapshot-error')
// just including an actual expect to satisfy the linter
await expect(page.getByRole('cell', { name: 'disk-snapshot-error' })).toBeVisible()
// expectToast should have closed the toast already, but let's just verify …
await expectNoToast(page, 'Creating snapshot of disk disk-snapshot-error')
// … before we can check for the error toast
await expectToast(page, 'Failed to create snapshotCannot snapshot disk')
})
test('Local disk snapshot disabled', async ({ page }) => {
await page.goto('/projects/mock-project/disks')
const row = page.getByRole('row', { name: 'local-disk', exact: false })
await row.getByRole('button', { name: 'Row actions' }).click()
const snapshotItem = page.getByRole('menuitem', { name: 'Snapshot' })
await expect(snapshotItem).toBeDisabled()
// hover to see tooltip with disabled reason
await snapshotItem.hover()
await expect(page.getByRole('tooltip')).toHaveText("Local disks don't support snapshots")
})
test('Read-only disk snapshot disabled', async ({ page }) => {
await page.goto('/projects/mock-project/disks')
const row = page.getByRole('row', { name: 'read-only-disk', exact: false })
await row.getByRole('button', { name: 'Row actions' }).click()
const snapshotItem = page.getByRole('menuitem', { name: 'Snapshot' })
await expect(snapshotItem).toBeDisabled()
await snapshotItem.hover()
await expect(page.getByRole('tooltip')).toHaveText(
"Read-only disks don't support snapshots"
)
})
test.describe('Disk create', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/projects/mock-project/disks-new')
await expect(page.getByRole('dialog', { name: 'Create disk' })).toBeVisible()
await page.getByRole('textbox', { name: 'Name' }).fill('a-new-disk')
})
test.afterEach(async ({ page }) => {
await page.getByRole('button', { name: 'Create disk' }).click()
await expect(page.getByRole('dialog', { name: 'Create disk' })).toBeHidden()
await expectToast(page, 'Disk a-new-disk created')
await expect(page.getByRole('cell', { name: 'a-new-disk' })).toBeVisible()
})
// expects are in the afterEach
/* eslint-disable playwright/expect-expect */
test('from blank', async ({ page }) => {
await page.getByRole('radio', { name: '512' }).click()
})
test('from snapshot', async ({ page }) => {
await page.getByRole('radio', { name: 'Snapshot' }).click()
await page.getByRole('button', { name: 'Source snapshot' }).click()
await page.getByRole('option', { name: 'delete-500' }).click()
})
// max-size snapshot required a fix
test('from max-size snapshot', async ({ page }) => {
await page.getByRole('radio', { name: 'Snapshot' }).click()
await page.getByRole('button', { name: 'Source snapshot' }).click()
await page.getByRole('option', { name: 'snapshot-max' }).click()
})
test('from image', async ({ page }) => {
await page.getByRole('radio', { name: 'Image' }).click()
await page.getByRole('button', { name: 'Source image' }).click()
await page.getByRole('option', { name: 'image-3' }).click()
})
test('switching to snapshot and back to blank', async ({ page }) => {
await page.getByRole('radio', { name: 'Snapshot' }).click()
await page.getByRole('radio', { name: 'Blank' }).click()
})
test('local disk', async ({ page }) => {
const source = page.getByRole('radiogroup', { name: 'Source' })
const blockSize = page.getByRole('radiogroup', { name: 'Block size' })
// verify source and block size are visible for distributed (default)
await expect(source).toBeVisible()
await expect(blockSize).toBeVisible()
await page.getByRole('radio', { name: 'Local' }).click()
// source and block size options should disappear when local is selected
await expect(source).toBeHidden()
await expect(blockSize).toBeHidden()
})
/* eslint-enable playwright/expect-expect */
})
test('Distributed disk clamps size to max of 1023 GiB', async ({ page }) => {
await page.goto('/projects/mock-project/disks-new')
// Wait for form to be hydrated by checking a field that renders after mount
await expect(page.getByRole('radiogroup', { name: 'Block size' })).toBeVisible()
const sizeInput = page.getByRole('textbox', { name: 'Size (GiB)' })
await fillNumberInput(sizeInput, '2000', '1023')
})
test('Local disk has no max size limit', async ({ page }) => {
await page.goto('/projects/mock-project/disks-new')
// Wait for form to be hydrated by checking a field that renders after mount
await expect(page.getByRole('radiogroup', { name: 'Block size' })).toBeVisible()
await page.getByRole('radio', { name: 'Local' }).click()
// Wait for form to update (Block size disappears in local mode)
await expect(page.getByRole('radiogroup', { name: 'Block size' })).toBeHidden()
const sizeInput = page.getByRole('textbox', { name: 'Size (GiB)' })
await fillNumberInput(sizeInput, '2000')
// Should not show the max size error
await expect(page.getByText('Can be at most 1023 GiB')).toBeHidden()
// Value should remain 2000, not clamped to 1023
await expect(sizeInput).toHaveValue('2000')
})
test('Create local disk with size > 1023 GiB', async ({ page }) => {
await page.goto('/projects/mock-project/disks-new')
// Wait for form to be hydrated by checking a field that renders after mount
await expect(page.getByRole('radiogroup', { name: 'Block size' })).toBeVisible()
await page.getByRole('textbox', { name: 'Name' }).fill('big-local-disk')
await page.getByRole('radio', { name: 'Local' }).click()
// Wait for form to update (Block size disappears in local mode)
await expect(page.getByRole('radiogroup', { name: 'Block size' })).toBeHidden()
const sizeInput = page.getByRole('textbox', { name: 'Size (GiB)' })
await fillNumberInput(sizeInput, '2000')
await page.getByRole('button', { name: 'Create disk' }).click()
await expect(page.getByRole('dialog', { name: 'Create disk' })).toBeHidden()
await expectToast(page, 'Disk big-local-disk created')
// 2000 GiB is displayed as 1.95 TiB (filesize formatting)
await expectRowVisible(page.getByRole('table'), {
name: 'big-local-disk',
size: '1.95 TiB',
})
})
test('Create disk from snapshot with read-only', async ({ page }) => {
await page.goto('/projects/mock-project/disks-new')
await page.getByRole('textbox', { name: 'Name' }).fill('a-new-disk')
await page.getByRole('radio', { name: 'Snapshot' }).click()
await page.getByRole('button', { name: 'Source snapshot' }).click()
await page.getByRole('option', { name: 'delete-500' }).click()
await page.getByRole('checkbox', { name: 'Make disk read-only' }).check()
await page.getByRole('button', { name: 'Create disk' }).click()
await expect(page.getByRole('dialog', { name: 'Create disk' })).toBeHidden()
const row = page.getByRole('row', { name: /a-new-disk/ })
await expect(row.getByText('Read only', { exact: true })).toBeVisible()
// Verify snapshot ID in detail modal (now truncated)
await page.getByRole('link', { name: 'a-new-disk' }).click()
const modal = page.getByRole('dialog', { name: 'Disk details' })
// The ID is truncated to 32 chars, but full ID is in aria-label
await expect(modal.getByLabel('e6c58826-62fb-4205-820e-620407cd04e7')).toBeVisible()
})
test('Create disk from image with read-only', async ({ page }) => {
await page.goto('/projects/mock-project/disks-new')
await page.getByRole('textbox', { name: 'Name' }).fill('a-new-disk')
await page.getByRole('radio', { name: 'Image' }).click()
await page.getByRole('button', { name: 'Source image' }).click()
await page.getByRole('option', { name: 'image-3' }).click()
await page.getByRole('checkbox', { name: 'Make disk read-only' }).check()
await page.getByRole('button', { name: 'Create disk' }).click()
await expect(page.getByRole('dialog', { name: 'Create disk' })).toBeHidden()
const row = page.getByRole('row', { name: /a-new-disk/ })
await expect(row.getByText('Read only', { exact: true })).toBeVisible()
// Verify image ID in detail modal (now truncated)
await page.getByRole('link', { name: 'a-new-disk' }).click()
const modal = page.getByRole('dialog', { name: 'Disk details' })
// The ID is truncated to 32 chars, but full ID is in aria-label
await expect(modal.getByLabel('4700ecf1-8f48-4ecf-b78e-816ddb76aaca')).toBeVisible()
})