Fix SSH key manager modal layout and test compatibility (#325)

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Tao Xu 2025-07-15 09:52:49 +09:00 committed by GitHub
parent 68e6456aef
commit e89abc9dc6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 214 additions and 132 deletions

View file

@ -33,12 +33,31 @@ export class SSHKeyManager extends LitElement {
@state() private importKeyContent = ''; @state() private importKeyContent = '';
@state() private showInstructions = false; @state() private showInstructions = false;
@state() private instructionsKeyId = ''; @state() private instructionsKeyId = '';
private documentKeyHandler = (e: KeyboardEvent) => this.handleDocumentKeyDown(e);
connectedCallback() { connectedCallback() {
super.connectedCallback(); super.connectedCallback();
this.refreshKeys(); this.refreshKeys();
} }
updated(changedProperties: Map<string | number | symbol, unknown>) {
super.updated(changedProperties);
// Handle document keydown events when modal visibility changes
if (changedProperties.has('visible')) {
if (this.visible) {
document.addEventListener('keydown', this.documentKeyHandler);
} else {
document.removeEventListener('keydown', this.documentKeyHandler);
}
}
}
disconnectedCallback() {
super.disconnectedCallback();
document.removeEventListener('keydown', this.documentKeyHandler);
}
private refreshKeys() { private refreshKeys() {
this.keys = this.sshAgent.listKeys() as SSHKey[]; this.keys = this.sshAgent.listKeys() as SSHKey[];
} }
@ -139,22 +158,41 @@ export class SSHKeyManager extends LitElement {
} }
} }
private handleBackdropClick(e: Event) {
if (e.target === e.currentTarget) {
this.handleClose();
}
}
private handleDocumentKeyDown(e: KeyboardEvent) {
if (e.key === 'Escape' && this.visible) {
e.preventDefault();
this.handleClose();
}
}
render() { render() {
if (!this.visible) return html``; if (!this.visible) return html``;
return html` return html`
<modal-wrapper <div
.visible=${this.visible} class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center p-4 z-[1000]"
modalClass="" @click=${this.handleBackdropClick}
contentClass="modal-content modal-positioned bg-bg border border-base rounded-lg p-6 w-full max-w-4xl max-h-[80vh] overflow-y-auto"
ariaLabel="SSH Key Manager"
@close=${this.handleClose}
.closeOnBackdrop=${true}
.closeOnEscape=${true}
> >
<div class="flex items-center justify-between mb-6"> <div
<h2 class="text-xl font-mono text-primary">SSH Key Manager</h2> class="bg-bg-secondary border border-border rounded-lg p-6 w-full max-w-[95vw] sm:max-w-3xl max-h-[90vh] overflow-y-auto shadow-2xl z-[1001]"
<button @click=${this.handleClose} class="text-muted hover:text-primary"> role="dialog"
aria-modal="true"
aria-label="SSH Key Manager"
@click=${(e: Event) => e.stopPropagation()}
>
<div class="relative mb-8">
<h2 class="text-2xl font-mono text-primary text-center">🔑 SSH Key Manager</h2>
<button
@click=${this.handleClose}
class="absolute top-0 right-0 w-8 h-8 flex items-center justify-center text-muted hover:text-primary hover:bg-surface rounded transition-colors"
title="Close"
>
</button> </button>
</div> </div>
@ -196,27 +234,27 @@ export class SSHKeyManager extends LitElement {
: '' : ''
} }
<div class="mb-6"> <div class="mb-8">
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-6 pb-3 border-b border-border">
<h3 class="font-mono text-lg text-primary">SSH Keys</h3> <h3 class="font-mono text-xl text-primary">SSH Keys</h3>
<button <button
@click=${() => { @click=${() => {
this.showAddForm = !this.showAddForm; this.showAddForm = !this.showAddForm;
}} }}
class="btn-primary" class="btn-primary px-4 py-2 font-medium"
?disabled=${this.loading} ?disabled=${this.loading}
> >
${this.showAddForm ? 'Cancel' : 'Add Key'} ${this.showAddForm ? 'Cancel' : '+ Add Key'}
</button> </button>
</div> </div>
${ ${
this.showAddForm this.showAddForm
? html` ? html`
<div class="space-y-6 mb-4"> <div class="space-y-6 mb-8">
<!-- Generate New Key Section --> <!-- Generate New Key Section -->
<div class="bg-surface border border-base rounded p-4"> <div class="bg-surface border border-border rounded-lg p-6">
<h4 class="text-primary font-mono text-lg mb-4 flex items-center gap-2"> <h4 class="text-primary font-mono text-lg mb-6 flex items-center gap-2 font-semibold">
🔑 Generate New SSH Key 🔑 Generate New SSH Key
</h4> </h4>
@ -273,8 +311,8 @@ export class SSHKeyManager extends LitElement {
</div> </div>
<!-- Import Existing Key Section --> <!-- Import Existing Key Section -->
<div class="bg-surface border border-base rounded p-4"> <div class="bg-surface border border-border rounded-lg p-6">
<h4 class="text-primary font-mono text-lg mb-4 flex items-center gap-2"> <h4 class="text-primary font-mono text-lg mb-6 flex items-center gap-2 font-semibold">
📁 Import Existing SSH Key 📁 Import Existing SSH Key
</h4> </h4>
@ -336,26 +374,29 @@ export class SSHKeyManager extends LitElement {
${ ${
this.showInstructions && this.instructionsKeyId this.showInstructions && this.instructionsKeyId
? html` ? html`
<div class="bg-surface border border-base rounded p-4 mb-6"> <div class="bg-surface border border-border rounded-lg p-6 mb-8">
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-6">
<h4 class="text-primary font-mono text-lg">Setup Instructions</h4> <h4 class="text-primary font-mono text-lg font-semibold flex items-center gap-2">
📋 Setup Instructions
</h4>
<button <button
@click=${() => { @click=${() => {
this.showInstructions = false; this.showInstructions = false;
}} }}
class="text-muted hover:text-primary" class="w-8 h-8 flex items-center justify-center text-muted hover:text-primary hover:bg-bg rounded transition-colors"
title="Close instructions"
> >
</button> </button>
</div> </div>
<div class="space-y-4"> <div class="space-y-6">
<div class="bg-bg border border-base rounded p-3"> <div class="bg-bg border border-border rounded-lg p-4">
<p class="text-muted text-xs mb-2"> <p class="text-muted text-sm mb-3 font-medium">
1. Add the public key to your authorized_keys file: 1. Add the public key to your authorized_keys file:
</p> </p>
<div class="relative"> <div class="relative">
<pre <pre
class="bg-secondary p-2 rounded text-xs overflow-x-auto text-primary pr-20" class="bg-secondary p-3 rounded-lg text-xs overflow-x-auto text-primary pr-20 font-mono"
> >
echo "${this.sshAgent.getPublicKey(this.instructionsKeyId)}" >> ~/.ssh/authorized_keys</pre echo "${this.sshAgent.getPublicKey(this.instructionsKeyId)}" >> ~/.ssh/authorized_keys</pre
> >
@ -373,11 +414,11 @@ echo "${this.sshAgent.getPublicKey(this.instructionsKeyId)}" >> ~/.ssh/authorize
</button> </button>
</div> </div>
</div> </div>
<div class="bg-bg border border-base rounded p-3"> <div class="bg-bg border border-border rounded-lg p-4">
<p class="text-muted text-xs mb-2">2. Or copy the public key:</p> <p class="text-muted text-sm mb-3 font-medium">2. Or copy the public key:</p>
<div class="relative"> <div class="relative">
<pre <pre
class="bg-secondary p-2 rounded text-xs overflow-x-auto text-primary pr-20" class="bg-secondary p-3 rounded-lg text-xs overflow-x-auto text-primary pr-20 font-mono"
> >
${this.sshAgent.getPublicKey(this.instructionsKeyId)}</pre ${this.sshAgent.getPublicKey(this.instructionsKeyId)}</pre
> >
@ -396,9 +437,11 @@ ${this.sshAgent.getPublicKey(this.instructionsKeyId)}</pre
</button> </button>
</div> </div>
</div> </div>
<p class="text-muted text-xs font-mono"> <div class="bg-blue-50 border border-blue-200 rounded-lg p-3">
💡 Tip: Make sure ~/.ssh/authorized_keys has correct permissions (600) <p class="text-blue-700 text-sm font-mono flex items-center gap-2">
</p> 💡 <strong>Tip:</strong> Make sure ~/.ssh/authorized_keys has correct permissions (600)
</p>
</div>
</div> </div>
</div> </div>
` `
@ -410,14 +453,15 @@ ${this.sshAgent.getPublicKey(this.instructionsKeyId)}</pre
${ ${
this.keys.length === 0 this.keys.length === 0
? html` ? html`
<div class="text-center py-8 text-muted"> <div class="text-center py-12 text-muted border border-border rounded-lg bg-surface">
<p class="font-mono text-lg mb-2">No SSH keys found</p> <div class="text-4xl mb-4">🔑</div>
<p class="font-mono text-lg mb-2 text-primary">No SSH keys found</p>
<p class="text-sm">Generate or import a key to get started</p> <p class="text-sm">Generate or import a key to get started</p>
</div> </div>
` `
: this.keys.map( : this.keys.map(
(key) => html` (key) => html`
<div class="ssh-key-item"> <div class="ssh-key-item border border-border rounded-lg p-4 bg-surface hover:bg-bg transition-colors">
<div class="flex items-start justify-between"> <div class="flex items-start justify-between">
<div class="flex-1"> <div class="flex-1">
<div class="flex items-center gap-2 mb-2"> <div class="flex items-center gap-2 mb-2">
@ -457,7 +501,8 @@ ${this.sshAgent.getPublicKey(this.instructionsKeyId)}</pre
) )
} }
</div> </div>
</modal-wrapper> </div>
</div>
`; `;
} }
} }

View file

@ -19,19 +19,33 @@ test.describe('SSH Key Manager', () => {
}); });
test('should open SSH key manager from login page', async ({ page }) => { test('should open SSH key manager from login page', async ({ page }) => {
// Look for SSH key manager trigger (usually near login form) // Look for SSH key manager trigger using data-testid for reliability
const sshKeyTrigger = page const sshKeyTrigger = page.locator('[data-testid="manage-keys"]');
// Also try alternate selectors as fallback
const fallbackTrigger = page
.locator( .locator(
'button:has-text("SSH Keys"), button:has-text("Manage Keys"), ssh-key-manager button, [title*="SSH"]' 'button:has-text("Manage Keys"), button:has-text("SSH Keys"), ssh-key-manager button, [title*="SSH"]'
) )
.first(); .first();
if (await sshKeyTrigger.isVisible()) { let triggerToUse = sshKeyTrigger;
await sshKeyTrigger.click(); if (!(await sshKeyTrigger.isVisible())) {
triggerToUse = fallbackTrigger;
}
// Verify SSH key manager modal opens if (await triggerToUse.isVisible()) {
await expect(page.locator('ssh-key-manager')).toBeVisible({ timeout: 5000 }); await triggerToUse.click();
await expect(page.locator('[data-testid="modal-backdrop"], .modal-backdrop')).toBeVisible();
// Wait a bit for the click event to propagate
await page.waitForTimeout(100);
// Verify SSH key manager modal opens - check the actual modal content
await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible({ timeout: 5000 });
await expect(page.locator('ssh-key-manager div[role="dialog"]')).toBeVisible();
// Also verify the header text is visible
await expect(page.locator('ssh-key-manager h2:has-text("SSH Key Manager")')).toBeVisible();
} else { } else {
// Skip test if SSH key manager is not accessible from this view // Skip test if SSH key manager is not accessible from this view
test.skip(); test.skip();
@ -48,7 +62,7 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// Check for key list container // Check for key list container
const keyList = page.locator('.space-y-2, .space-y-4, .grid, .flex.flex-col').filter({ const keyList = page.locator('.space-y-2, .space-y-4, .grid, .flex.flex-col').filter({
@ -61,9 +75,7 @@ test.describe('SSH Key Manager', () => {
hasText: /rsa|ed25519|ecdsa|ssh-/i, hasText: /rsa|ed25519|ecdsa|ssh-/i,
}); });
const emptyState = page.locator( const emptyState = page.locator('ssh-key-manager :has-text("No SSH keys found")').first();
':has-text("No SSH keys"), :has-text("Add your first"), :has-text("No keys found")'
);
const hasKeysOrEmpty = (await keyItems.count()) > 0 || (await emptyState.isVisible()); const hasKeysOrEmpty = (await keyItems.count()) > 0 || (await emptyState.isVisible());
expect(hasKeysOrEmpty).toBeTruthy(); expect(hasKeysOrEmpty).toBeTruthy();
@ -82,9 +94,27 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// Look for generate/create key button - first click Add Key to show the form
const addKeyButton = page
.locator(
'button:has-text("+ Add Key"), button:has-text("Add Key"), button:has-text("Generate"), button:has-text("Create")'
)
.first();
if (await addKeyButton.isVisible()) {
await addKeyButton.click();
}
// First fill in the required key name field
const keyNameInput = page
.locator('input[placeholder*="name"], input[placeholder*="Name"]')
.first();
if (await keyNameInput.isVisible()) {
await keyNameInput.fill('test-key-name');
}
// Look for generate/create key button
const generateButton = page const generateButton = page
.locator( .locator(
'button:has-text("Generate"), button:has-text("Create"), button:has-text("New Key"), button[title*="Generate"]' 'button:has-text("Generate"), button:has-text("Create"), button:has-text("New Key"), button[title*="Generate"]'
@ -94,23 +124,19 @@ test.describe('SSH Key Manager', () => {
if (await generateButton.isVisible()) { if (await generateButton.isVisible()) {
await generateButton.click(); await generateButton.click();
// Should open generation dialog // Wait for the generation to complete
const generationDialog = page.locator('.modal, [role="dialog"]').filter({ await page.waitForTimeout(1000);
hasText: /generate|create|new key/i,
});
await expect(generationDialog).toBeVisible({ timeout: 3000 }); // Check if key was generated successfully - look for setup instructions or key in list
const setupInstructions = page
.locator('ssh-key-manager h4:has-text("Setup Instructions")')
.first();
const keyInList = page.locator('ssh-key-manager :has-text("test-key-name")').first();
// Should have key type selection // Should see either setup instructions or the key in the list
const keyTypeOptions = page.locator('select, input[type="radio"], button').filter({ const hasInstructionsOrKey =
hasText: /rsa|ed25519|ecdsa/i, (await setupInstructions.isVisible()) || (await keyInList.isVisible());
}); expect(hasInstructionsOrKey).toBeTruthy();
if (await keyTypeOptions.first().isVisible()) {
// Should have at least one key type option
const optionCount = await keyTypeOptions.count();
expect(optionCount).toBeGreaterThan(0);
}
} }
} else { } else {
test.skip(); test.skip();
@ -126,7 +152,30 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// First click Add Key to show the form
const addKeyButton = page
.locator('button:has-text("+ Add Key"), button:has-text("Add Key")')
.first();
if (await addKeyButton.isVisible()) {
await addKeyButton.click();
}
// Fill in the key name field for import section
const importKeyNameInput = page.locator('input[placeholder*="name"]').nth(1); // Second name input (for import)
if (await importKeyNameInput.isVisible()) {
await importKeyNameInput.fill('imported-test-key');
}
// Fill in the private key content
const keyContentTextarea = page.locator('textarea[placeholder*="PRIVATE KEY"]');
if (await keyContentTextarea.isVisible()) {
await keyContentTextarea.fill(
'-----BEGIN PRIVATE KEY-----\ntest-key-content\n-----END PRIVATE KEY-----'
);
}
// Look for import button // Look for import button
const importButton = page const importButton = page
@ -149,23 +198,20 @@ test.describe('SSH Key Manager', () => {
expect(acceptsSSHKeys).toBeTruthy(); expect(acceptsSSHKeys).toBeTruthy();
} }
} else { } else {
// Regular import button - click to open import dialog // Regular import button - click to import the key
await importButton.click(); await importButton.click();
const importDialog = page.locator('.modal, [role="dialog"]').filter({ // Wait for import to complete
hasText: /import|add key|paste/i, await page.waitForTimeout(1000);
});
await expect(importDialog).toBeVisible({ timeout: 3000 }); // Should see success message or imported key in list
const successMessage = page.locator('ssh-key-manager .bg-status-success').first();
const keyInList = page.locator('ssh-key-manager :has-text("imported-test-key")').first();
// Should have textarea for key content // Either success message appears or key is added to the list
const keyTextarea = page.locator('textarea, input[type="text"]').filter({ const hasSuccessOrKey =
hasText: /key|ssh|paste/i, (await successMessage.isVisible()) || (await keyInList.isVisible());
}); expect(hasSuccessOrKey).toBeTruthy();
if (await keyTextarea.isVisible()) {
await expect(keyTextarea).toBeVisible();
}
} }
} }
} else { } else {
@ -182,7 +228,28 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// First click Add Key to show the form
const addKeyButton = page
.locator('button:has-text("+ Add Key"), button:has-text("Add Key")')
.first();
if (await addKeyButton.isVisible()) {
await addKeyButton.click();
}
// Fill in the key name field for import section
const importKeyNameInput = page.locator('input[placeholder*="name"]').nth(1); // Second name input (for import)
if (await importKeyNameInput.isVisible()) {
await importKeyNameInput.fill('validation-test-key');
}
// Fill in invalid key content
const keyContentTextarea = page.locator('textarea[placeholder*="PRIVATE KEY"]');
if (await keyContentTextarea.isVisible()) {
await keyContentTextarea.fill('invalid-ssh-key-format');
}
// Try to find import functionality // Try to find import functionality
const importButton = page const importButton = page
@ -192,36 +259,13 @@ test.describe('SSH Key Manager', () => {
if (await importButton.isVisible()) { if (await importButton.isVisible()) {
await importButton.click(); await importButton.click();
// Look for key input field // Wait for validation to complete
const keyInput = page await page.waitForTimeout(500);
.locator('textarea, input[type="text"]')
.filter({
hasNotText: /name|label|comment/i,
})
.first();
if (await keyInput.isVisible()) { // Should show validation error
// Try invalid key format const errorMessage = page.locator('ssh-key-manager .bg-status-error').first();
await keyInput.fill('invalid-ssh-key-format');
// Look for submit/save button await expect(errorMessage).toBeVisible({ timeout: 3000 });
const submitButton = page
.locator('button:has-text("Save"), button:has-text("Import"), button:has-text("Add")')
.last();
if (await submitButton.isVisible()) {
await submitButton.click();
// Should show validation error
const errorMessage = page
.locator('.text-red, .text-error, .bg-red, [role="alert"]')
.filter({
hasText: /invalid|format|error/i,
});
await expect(errorMessage).toBeVisible({ timeout: 3000 });
}
}
} }
} else { } else {
test.skip(); test.skip();
@ -237,7 +281,7 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// Look for existing keys with delete buttons // Look for existing keys with delete buttons
const deleteButtons = page const deleteButtons = page
@ -301,7 +345,7 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// Look for key generation with passphrase option // Look for key generation with passphrase option
const generateButton = page const generateButton = page
@ -352,7 +396,7 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// Look for export buttons // Look for export buttons
const exportButtons = page.locator( const exportButtons = page.locator(
@ -408,7 +452,7 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// Look for key metadata display // Look for key metadata display
const keyItems = page.locator('.border.rounded, .bg-gray, .bg-dark').filter({ const keyItems = page.locator('.border.rounded, .bg-gray, .bg-dark').filter({
@ -460,37 +504,30 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
// Test closing with escape key // Test closing with backdrop click - click on the actual backdrop div
await page.keyboard.press('Escape'); const backdrop = page.locator('ssh-key-manager .fixed.inset-0').first();
await waitForModalClosed(page);
await expect(page.locator('ssh-key-manager')).not.toBeVisible();
// Reopen and test closing with backdrop click
await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible();
const backdrop = page.locator('[data-testid="modal-backdrop"], .modal-backdrop').first();
if (await backdrop.isVisible()) { if (await backdrop.isVisible()) {
await backdrop.click(); // Click on the backdrop itself (the outer div that handles backdrop clicks)
await backdrop.click({ position: { x: 10, y: 10 } }); // Click on top-left corner of backdrop
await waitForModalClosed(page); await waitForModalClosed(page);
await expect(page.locator('ssh-key-manager')).not.toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).not.toBeVisible();
} }
// Reopen and test closing with close button // Reopen and test closing with close button
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
const closeButton = page const closeButton = page
.locator( .locator(
'button:has-text("Close"), button:has-text("Cancel"), button[aria-label*="close"], button[title*="close"]' 'button:has-text("Close"), button:has-text("Cancel"), button[aria-label*="close"], button[title*="close"], button:has-text("✕")'
) )
.first(); .first();
if (await closeButton.isVisible()) { if (await closeButton.isVisible()) {
await closeButton.click(); await closeButton.click();
await waitForModalClosed(page); await waitForModalClosed(page);
await expect(page.locator('ssh-key-manager')).not.toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).not.toBeVisible();
} }
} else { } else {
test.skip(); test.skip();
@ -506,7 +543,7 @@ test.describe('SSH Key Manager', () => {
if (await sshKeyTrigger.isVisible()) { if (await sshKeyTrigger.isVisible()) {
await sshKeyTrigger.click(); await sshKeyTrigger.click();
await expect(page.locator('ssh-key-manager')).toBeVisible(); await expect(page.locator('ssh-key-manager .fixed.inset-0')).toBeVisible();
const generateButton = page const generateButton = page
.locator( .locator(