Skip to content

Commit 699fc12

Browse files
committed
refactor(e2e): Use Kubernetes API for deployment test setup instead of UI creation
Signed-off-by: SunsetB612 <[email protected]>
1 parent 785ed30 commit 699fc12

File tree

8 files changed

+576
-349
lines changed

8 files changed

+576
-349
lines changed

ui/apps/dashboard/e2e/workload/deployment/deployment-create.spec.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ limitations under the License.
1212
*/
1313

1414
import { test, expect } from '@playwright/test';
15-
import { setupDashboardAuthentication, generateTestDeploymentYaml } from './test-utils';
15+
import { setupDashboardAuthentication, generateTestDeploymentYaml, deleteK8sDeployment } from './test-utils';
16+
import { parse } from 'yaml';
17+
import _ from 'lodash';
1618

1719
test.beforeEach(async ({ page }) => {
1820
await setupDashboardAuthentication(page);
@@ -96,24 +98,40 @@ test('should create a new deployment', async ({ page }) => {
9698
await page.click('[role="dialog"] button:has-text("Submit")');
9799

98100
// Wait for API call to succeed
99-
const response = await apiRequestPromise;
100-
expect(response.status()).toBe(200);
101+
await apiRequestPromise;
101102

102103
// Wait for dialog to close
103104
await page.waitForSelector('[role="dialog"]', { state: 'detached', timeout: 5000 }).catch(() => {
104105
// Dialog may already be closed
105106
});
106107

107108
// Verify new deployment appears in list
108-
const deploymentName = testDeploymentYaml.match(/name: (.+)/)?.[1];
109-
if (deploymentName) {
110-
try {
111-
await expect(page.locator('table').locator(`text=${deploymentName}`)).toBeVisible({
112-
timeout: 15000
113-
});
114-
} catch {
115-
// If not shown immediately in list, may be due to cache or refresh delay
116-
// But API success indicates deployment was created
117-
}
109+
const yamlObject = parse(testDeploymentYaml);
110+
const deploymentName = _.get(yamlObject,'metadata.name');
111+
112+
// Assert deployment name exists
113+
expect(deploymentName).toBeTruthy();
114+
expect(deploymentName).toBeDefined();
115+
116+
try {
117+
await expect(page.locator('table').locator(`text=${deploymentName}`)).toBeVisible({
118+
timeout: 15000
119+
});
120+
} catch {
121+
// If not shown immediately in list, may be due to cache or refresh delay
122+
// But API success indicates deployment was created
123+
}
124+
125+
// Cleanup: Delete the created deployment
126+
try {
127+
await deleteK8sDeployment(deploymentName, 'default');
128+
} catch (error) {
129+
console.warn(`Failed to cleanup deployment ${deploymentName}:`, error);
130+
}
131+
132+
// Debug
133+
if(process.env.DEBUG === 'true'){
134+
await page.screenshot({ path: 'debug-deployment-create.png', fullPage: true });
118135
}
136+
119137
});

ui/apps/dashboard/e2e/workload/deployment/deployment-delete.spec.ts

Lines changed: 31 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -12,169 +12,71 @@ limitations under the License.
1212
*/
1313

1414
import { test, expect } from '@playwright/test';
15-
import { setupDashboardAuthentication, generateTestDeploymentYaml } from './test-utils';
15+
import { setupDashboardAuthentication, generateTestDeploymentYaml, createK8sDeployment, getDeploymentNameFromYaml} from './test-utils';
1616

1717
test.beforeEach(async ({ page }) => {
1818
await setupDashboardAuthentication(page);
1919
});
2020

2121
test('should delete deployment successfully', async ({ page }) => {
22+
// Create a test deployment directly via kubectl to set up test data
23+
const testDeploymentYaml = generateTestDeploymentYaml();
24+
const deploymentName = getDeploymentNameFromYaml(testDeploymentYaml);
25+
26+
// Setup: Create deployment using kubectl
27+
await createK8sDeployment(testDeploymentYaml);
28+
2229
// Navigate to workload page
2330
await page.click('text=Workloads');
2431
await expect(page.getByRole('radio', { name: 'Deployment' })).toBeChecked();
2532
await expect(page.locator('table')).toBeVisible({ timeout: 30000 });
26-
27-
// Create a test deployment
28-
await page.click('button:has-text("Add")');
29-
await page.waitForSelector('[role="dialog"]', { timeout: 10000 });
30-
31-
// Listen for API calls
32-
const apiRequestPromise = page.waitForResponse(response => {
33-
return response.url().includes('/api/v1/_raw/Deployment') && response.status() === 200;
34-
}, { timeout: 15000 });
35-
36-
const testDeploymentYaml = generateTestDeploymentYaml();
37-
38-
// Set Monaco editor DOM content
39-
await page.evaluate((yaml) => {
40-
const textarea = document.querySelector('.monaco-editor textarea') as HTMLTextAreaElement;
41-
if (textarea) {
42-
textarea.value = yaml;
43-
textarea.focus();
44-
}
45-
}, testDeploymentYaml);
46-
47-
// Call React onChange callback to update component state
48-
await page.evaluate((yaml) => {
49-
const findReactFiber = (element: any) => {
50-
const keys = Object.keys(element);
51-
return keys.find(key => key.startsWith('__reactFiber') || key.startsWith('__reactInternalInstance'));
52-
};
53-
54-
const monacoContainer = document.querySelector('.monaco-editor');
55-
if (monacoContainer) {
56-
const fiberKey = findReactFiber(monacoContainer);
57-
if (fiberKey) {
58-
let fiber = (monacoContainer as any)[fiberKey];
59-
60-
while (fiber) {
61-
if (fiber.memoizedProps && fiber.memoizedProps.onChange) {
62-
fiber.memoizedProps.onChange(yaml);
63-
return;
64-
}
65-
fiber = fiber.return;
66-
}
67-
}
68-
}
6933

70-
const dialog = document.querySelector('[role="dialog"]');
71-
if (dialog) {
72-
const fiberKey = findReactFiber(dialog);
73-
if (fiberKey) {
74-
let fiber = (dialog as any)[fiberKey];
75-
76-
const traverse = (node: any, depth = 0) => {
77-
if (!node || depth > 20) return false;
78-
79-
if (node.memoizedProps && node.memoizedProps.onChange) {
80-
node.memoizedProps.onChange(yaml);
81-
return true;
82-
}
83-
84-
if (node.child && traverse(node.child, depth + 1)) return true;
85-
if (node.sibling && traverse(node.sibling, depth + 1)) return true;
86-
87-
return false;
88-
};
89-
90-
traverse(fiber);
91-
}
92-
}
93-
}, testDeploymentYaml);
94-
95-
// Wait for submit button to become enabled
96-
await expect(page.locator('[role="dialog"] button:has-text("Submit")')).toBeEnabled();
97-
await page.click('[role="dialog"] button:has-text("Submit")');
98-
99-
// Wait for API call to succeed
100-
const response = await apiRequestPromise;
101-
expect(response.status()).toBe(200);
102-
103-
// Get the created deployment name
104-
const deploymentName = testDeploymentYaml.match(/name: (.+)/)?.[1];
105-
if (!deploymentName) {
106-
throw new Error('Could not extract deployment name from YAML');
107-
}
108-
109-
// Wait for success message to appear
110-
try {
111-
await expect(page.locator('text=Workloads Newly Added Success')).toBeVisible({ timeout: 5000 });
112-
} catch (e) {
113-
// Success message may not appear, continue execution
114-
}
115-
116-
// Wait for dialog to close
117-
await page.waitForSelector('[role="dialog"]', { state: 'detached', timeout: 10000 }).catch(() => {});
118-
11934
// Wait for deployment to appear in list
12035
const table = page.locator('table');
121-
await expect(table).toBeVisible({ timeout: 30000 });
122-
123-
// Try multiple times to find deployment with more flexible selector
124-
let deploymentFound = false;
125-
for (let i = 0; i < 10; i++) {
126-
try {
127-
const deploymentElement = page.locator(`table tbody tr:has-text("${deploymentName}")`);
128-
await expect(deploymentElement).toBeVisible({ timeout: 3000 });
129-
deploymentFound = true;
130-
break;
131-
} catch (e) {
132-
await page.waitForTimeout(2000); // Wait 2 seconds then retry
133-
}
134-
}
135-
136-
if (!deploymentFound) {
137-
throw new Error(`Deployment ${deploymentName} not found in the table after multiple attempts`);
138-
}
139-
36+
await expect(table.locator(`text=${deploymentName}`)).toBeVisible({ timeout: 30000 });
37+
14038
// Find row containing test deployment name
14139
const targetRow = page.locator(`table tbody tr:has-text("${deploymentName}")`);
14240
await expect(targetRow).toBeVisible({ timeout: 15000 });
143-
41+
14442
// Find Delete button in that row and click
145-
const deleteButton = targetRow.locator('button[type="button"]').filter({ hasText: /^(|Delete)$/ });
43+
const deleteButton = targetRow.locator('button[type="button"]').filter({ hasText: /^(Delete)$/ });
14644
await expect(deleteButton).toBeVisible({ timeout: 10000 });
147-
45+
14846
// Listen for delete API call
14947
const deleteApiPromise = page.waitForResponse(response => {
150-
return response.url().includes('/_raw/deployment') &&
151-
response.url().includes(`name/${deploymentName}`) &&
152-
response.request().method() === 'DELETE' &&
153-
response.status() === 200;
48+
return response.url().includes('/_raw/deployment') &&
49+
response.url().includes(`name/${deploymentName}`) &&
50+
response.request().method() === 'DELETE' &&
51+
response.status() === 200;
15452
}, { timeout: 15000 });
155-
53+
15654
await deleteButton.click();
157-
55+
15856
// Wait for delete confirmation tooltip to appear
15957
await page.waitForSelector('[role="tooltip"]', { timeout: 10000 });
160-
58+
16159
// Click Confirm button to confirm deletion
16260
const confirmButton = page.locator('[role="tooltip"] button').filter({ hasText: /^(Confirm)$/ });
16361
await expect(confirmButton).toBeVisible({ timeout: 5000 });
16462
await confirmButton.click();
165-
63+
16664
// Wait for delete API call to succeed
167-
const deleteResponse = await deleteApiPromise;
168-
expect(deleteResponse.status()).toBe(200);
169-
65+
await deleteApiPromise;
66+
17067
// Wait for tooltip to close
17168
await page.waitForSelector('[role="tooltip"]', { state: 'detached', timeout: 10000 }).catch(() => {});
17269

70+
// Refresh page to ensure UI is updated after deletion
71+
await page.reload();
72+
await page.click('text=Workloads');
73+
await expect(table).toBeVisible({ timeout: 30000 });
74+
17375
// Verify deployment no longer exists in table
174-
await expect(table.locator(`text=${deploymentName}`)).toHaveCount(0, { timeout: 10000 });
76+
await expect(table.locator(`text=${deploymentName}`)).toHaveCount(0, { timeout: 30000 });
17577

17678
// Debug
17779
if(process.env.DEBUG === 'true'){
178-
await page.screenshot({ path: 'debug-deployment-delete.png', fullPage: true });
80+
await page.screenshot({ path: 'debug-deployment-delete-kubectl.png', fullPage: true });
17981
}
180-
});
82+
});

0 commit comments

Comments
 (0)