Skip to content

Commit 762347b

Browse files
committed
fix: add tests
1 parent 279a26b commit 762347b

File tree

3 files changed

+304
-7
lines changed

3 files changed

+304
-7
lines changed

src/containers/Tenant/GrantAccess/GrantAccess.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,15 @@ export function GrantAccess({handleCloseDrawer}: GrantAccessProps) {
144144
)}
145145
</Flex>
146146
{subjectSelected && (
147-
<Rights
148-
inheritedRights={inheritedRightsSet}
149-
rights={currentRightsMap}
150-
availablePermissions={availablePermissions}
151-
handleChangeRightGetter={handleChangeRightGetter}
152-
view={rightView}
153-
/>
147+
<div className={block('rights-wrapper')}>
148+
<Rights
149+
inheritedRights={inheritedRightsSet}
150+
rights={currentRightsMap}
151+
availablePermissions={availablePermissions}
152+
handleChangeRightGetter={handleChangeRightGetter}
153+
view={rightView}
154+
/>
155+
</div>
154156
)}
155157
</Flex>
156158

tests/suites/tenant/diagnostics/Diagnostics.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export enum DiagnosticsTab {
1717
HotKeys = 'Hot keys',
1818
Describe = 'Describe',
1919
Storage = 'Storage',
20+
Access = 'Access',
2021
}
2122

2223
export class Table {
@@ -230,6 +231,7 @@ export class Diagnostics {
230231
storage: StoragePage;
231232
nodes: NodesPage;
232233
memoryViewer: MemoryViewer;
234+
private page: Page;
233235

234236
private tabs: Locator;
235237
private schemaViewer: Locator;
@@ -245,8 +247,12 @@ export class Diagnostics {
245247
private tableRadioButton: Locator;
246248
private fixedHeightQueryElements: Locator;
247249
private copyLinkButton: Locator;
250+
private ownerCard: Locator;
251+
private changeOwnerButton: Locator;
252+
private grantAccessButton: Locator;
248253

249254
constructor(page: Page) {
255+
this.page = page;
250256
this.storage = new StoragePage(page);
251257
this.nodes = new NodesPage(page);
252258
this.memoryViewer = new MemoryViewer(page);
@@ -269,6 +275,9 @@ export class Diagnostics {
269275
this.storageCard = page.locator('.metrics-cards__tab:has-text("Storage")');
270276
this.memoryCard = page.locator('.metrics-cards__tab:has-text("Memory")');
271277
this.healthcheckCard = page.locator('.ydb-healthcheck-preview');
278+
this.ownerCard = page.locator('.ydb-access-rights__owner-card');
279+
this.changeOwnerButton = page.locator('.ydb-access-rights__owner-card button');
280+
this.grantAccessButton = page.locator('button:has-text("Grant Access")');
272281
}
273282

274283
async isSchemaViewerVisible() {
@@ -423,4 +432,160 @@ export class Diagnostics {
423432
const rowElementClass = await rowElement.getAttribute('class');
424433
return rowElementClass?.includes('kv-top-queries__row_active') || false;
425434
}
435+
436+
async isOwnerCardVisible(): Promise<boolean> {
437+
await this.ownerCard.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
438+
return true;
439+
}
440+
441+
async getOwnerName(): Promise<string> {
442+
const ownerNameElement = this.ownerCard.locator('.ydb-subject-with-avatar__subject');
443+
444+
return await ownerNameElement.innerText();
445+
}
446+
447+
async clickChangeOwnerButton(): Promise<void> {
448+
await this.changeOwnerButton.click();
449+
}
450+
451+
async changeOwner(newOwnerName: string): Promise<void> {
452+
await this.clickChangeOwnerButton();
453+
454+
// Wait for the dialog to appear
455+
const dialog = this.page.locator('.g-dialog');
456+
await dialog.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
457+
458+
// Wait for the owner input field to appear
459+
const ownerInput = dialog.locator('input[placeholder="Enter subject"]');
460+
await ownerInput.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
461+
462+
// Clear the input and type the new owner name
463+
await ownerInput.clear();
464+
await ownerInput.fill(newOwnerName);
465+
466+
// Click the Apply button
467+
const applyButton = dialog.locator('button:has-text("Apply")');
468+
469+
// Wait for the button to be enabled
470+
await this.page.waitForTimeout(500);
471+
// Wait for the button to become enabled
472+
await this.page.waitForSelector('.g-dialog button:has-text("Apply"):not([disabled])', {
473+
timeout: VISIBILITY_TIMEOUT,
474+
});
475+
await applyButton.click();
476+
477+
// Wait for the dialog to close and changes to be applied
478+
await dialog.waitFor({state: 'hidden', timeout: VISIBILITY_TIMEOUT});
479+
await this.page.waitForTimeout(500);
480+
}
481+
482+
async clickGrantAccessButton(): Promise<void> {
483+
await this.grantAccessButton.click();
484+
}
485+
486+
async isGrantAccessDrawerVisible(): Promise<boolean> {
487+
const grantAccessDialog = this.page.locator('.ydb-grant-access');
488+
await grantAccessDialog.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
489+
return true;
490+
}
491+
492+
async enterSubjectInGrantAccessDialog(subject: string): Promise<void> {
493+
const subjectInput = this.page.locator('.ydb-grant-access input[name="subjectInput"]');
494+
await subjectInput.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
495+
await subjectInput.fill(subject);
496+
await subjectInput.press('Enter');
497+
}
498+
499+
async isRightsWrapperVisible(): Promise<boolean> {
500+
const rightsWrapper = this.page.locator('.ydb-grant-access__rights-wrapper');
501+
return rightsWrapper.isVisible();
502+
}
503+
504+
async isApplyButtonDisabled(): Promise<boolean> {
505+
const applyButton = this.page.locator('.ydb-grant-access__footer-button:has-text("Apply")');
506+
await applyButton.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
507+
return await applyButton.isDisabled();
508+
}
509+
510+
async clickFullAccessSwitch(): Promise<void> {
511+
const fullAccessCard = this.page.locator('.ydb-grant-access__single-right').first();
512+
await fullAccessCard.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
513+
const switchElement = fullAccessCard.locator('.g-switch__indicator');
514+
await switchElement.click();
515+
}
516+
517+
async clickApplyButton(): Promise<void> {
518+
const applyButton = this.page.locator('button:has-text("Apply")');
519+
await applyButton.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
520+
await applyButton.click();
521+
}
522+
523+
async isSubjectInRightsTable(subject: string): Promise<boolean> {
524+
const rightsTable = this.page.locator('.ydb-access-rights__rights-table');
525+
await rightsTable.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
526+
527+
const rows = rightsTable.locator('.data-table__row');
528+
529+
await rows
530+
.filter({hasText: subject})
531+
.waitFor({state: 'visible', timeout: VISIBILITY_TIMEOUT});
532+
533+
// for (const row of Array.from(rows)) {
534+
// // Get the first cell (Subject column)
535+
// const firstCell = row.querySelector('.data-table__td');
536+
// if (!firstCell) {
537+
// continue;
538+
// }
539+
540+
// // Find the subject text element
541+
// const subjectElement = firstCell.querySelector('.ydb-subject-with-avatar__subject');
542+
// if (!subjectElement) {
543+
// continue;
544+
// }
545+
546+
// // Check if the subject text contains the search text
547+
// const subjectText = subjectElement.textContent || '';
548+
// if (subjectText.includes(searchText)) {
549+
// return true;
550+
// }
551+
// }
552+
553+
return true;
554+
}
555+
556+
// export function isSubjectInRightsTable(searchText: string): boolean {
557+
// // Find the rights table
558+
// const rightsTable = document.querySelector(
559+
// '.ydb-resizeable-data-table.ydb-access-rights__rights-table',
560+
// );
561+
// if (!rightsTable) {
562+
// return false;
563+
// }
564+
565+
// // Find all rows in the table
566+
// const rows = rightsTable.querySelectorAll('.data-table__row');
567+
568+
// // Check each row
569+
// for (const row of Array.from(rows)) {
570+
// // Get the first cell (Subject column)
571+
// const firstCell = row.querySelector('.data-table__td');
572+
// if (!firstCell) {
573+
// continue;
574+
// }
575+
576+
// // Find the subject text element
577+
// const subjectElement = firstCell.querySelector('.ydb-subject-with-avatar__subject');
578+
// if (!subjectElement) {
579+
// continue;
580+
// }
581+
582+
// // Check if the subject text contains the search text
583+
// const subjectText = subjectElement.textContent || '';
584+
// if (subjectText.includes(searchText)) {
585+
// return true;
586+
// }
587+
// }
588+
589+
// return false;
590+
// }
426591
}
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import {expect, test} from '@playwright/test';
2+
3+
import {TenantPage} from '../../TenantPage';
4+
import {Diagnostics, DiagnosticsTab} from '../Diagnostics';
5+
6+
const newSubject = 'foo';
7+
8+
test.describe('Diagnostics Access tab', async () => {
9+
test('Access tab shows owner card', async ({page}) => {
10+
const pageQueryParams = {
11+
schema: '/local/.sys_health',
12+
database: '/local',
13+
tenantPage: 'diagnostics',
14+
diagnosticsTab: 'access',
15+
};
16+
const tenantPage = new TenantPage(page);
17+
await tenantPage.goto(pageQueryParams);
18+
19+
const diagnostics = new Diagnostics(page);
20+
21+
// Verify owner card is visible
22+
await expect(diagnostics.isOwnerCardVisible()).resolves.toBe(true);
23+
});
24+
25+
test('Can change owner on access tab', async ({page}) => {
26+
const pageQueryParams = {
27+
schema: '/local/.sys_health',
28+
database: '/local',
29+
tenantPage: 'diagnostics',
30+
diagnosticsTab: 'access',
31+
};
32+
const tenantPage = new TenantPage(page);
33+
await tenantPage.goto(pageQueryParams);
34+
35+
const diagnostics = new Diagnostics(page);
36+
37+
// Get the current owner name
38+
const initialOwnerName = await diagnostics.getOwnerName();
39+
40+
// Change the owner to "John Dow"
41+
const newOwnerName = 'John Dow';
42+
await diagnostics.changeOwner(newOwnerName);
43+
44+
// Verify the owner has been changed
45+
const updatedOwnerName = await diagnostics.getOwnerName();
46+
expect(updatedOwnerName).toBe(newOwnerName);
47+
expect(updatedOwnerName).not.toBe(initialOwnerName);
48+
});
49+
50+
test('Owner card is visible after navigating to access tab', async ({page}) => {
51+
const pageQueryParams = {
52+
schema: '/dev02/home/xenoxeno/db1/my_row_table',
53+
database: '/dev02/home/xenoxeno/db1',
54+
tenantPage: 'diagnostics',
55+
};
56+
const tenantPage = new TenantPage(page);
57+
await tenantPage.goto(pageQueryParams);
58+
59+
const diagnostics = new Diagnostics(page);
60+
61+
// Navigate to the Access tab
62+
await diagnostics.clickTab(DiagnosticsTab.Access);
63+
64+
// Verify owner card is visible
65+
await expect(diagnostics.isOwnerCardVisible()).resolves.toBe(true);
66+
});
67+
68+
test('Grant Access button opens grant access drawer', async ({page}) => {
69+
const pageQueryParams = {
70+
schema: '/local/.sys_health',
71+
database: '/local',
72+
tenantPage: 'diagnostics',
73+
diagnosticsTab: 'access',
74+
summaryTab: 'acl',
75+
};
76+
const tenantPage = new TenantPage(page);
77+
await tenantPage.goto(pageQueryParams);
78+
79+
const diagnostics = new Diagnostics(page);
80+
81+
// Click on the Grant Access button
82+
await diagnostics.clickGrantAccessButton();
83+
84+
await expect(diagnostics.isGrantAccessDrawerVisible()).resolves.toBe(true);
85+
});
86+
87+
test.only('Can grant full access to a new subject', async ({page}) => {
88+
const pageQueryParams = {
89+
schema: '/local/.sys_health',
90+
database: '/local',
91+
tenantPage: 'diagnostics',
92+
diagnosticsTab: 'access',
93+
summaryTab: 'acl',
94+
};
95+
const tenantPage = new TenantPage(page);
96+
await tenantPage.goto(pageQueryParams);
97+
98+
const diagnostics = new Diagnostics(page);
99+
100+
// Verify that the rights wrapper is not visible initially
101+
await expect(diagnostics.isRightsWrapperVisible()).resolves.toBe(false);
102+
103+
// Click on the Grant Access button
104+
await diagnostics.clickGrantAccessButton();
105+
106+
// Verify that the grant access dialog appears
107+
await expect(diagnostics.isGrantAccessDrawerVisible()).resolves.toBe(true);
108+
109+
// Enter "foo" in the subject input and press Enter
110+
await diagnostics.enterSubjectInGrantAccessDialog(newSubject);
111+
112+
// Verify that the rights wrapper appears
113+
await expect(diagnostics.isRightsWrapperVisible()).resolves.toBe(true);
114+
115+
// Verify that the Apply button is disabled initially
116+
await expect(diagnostics.isApplyButtonDisabled()).resolves.toBe(true);
117+
118+
// Click on the switch for the "full" access right
119+
await diagnostics.clickFullAccessSwitch();
120+
121+
// Verify that the Apply button is now enabled
122+
await expect(diagnostics.isApplyButtonDisabled()).resolves.toBe(false);
123+
124+
// Click the Apply button
125+
await diagnostics.clickApplyButton();
126+
127+
// Verify that "foo" appears in the rights table
128+
await expect(diagnostics.isSubjectInRightsTable(newSubject)).resolves.toBe(true);
129+
});
130+
});

0 commit comments

Comments
 (0)