Files
threshold-ui/e2e-tests/desktop/tests/targets.spec.js
T
Priya Patel d2cf82b85c e2e Rdp client tests (#3055)
* test: 💍 e2e test for rdp client launch

* test: 💍 added rdp test helper

* refactor: 💡 misc

* refactor: 💡 addressed comments

* refactor: 💡 removed similar test
2025-11-19 14:22:07 -08:00

327 lines
10 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { expect, test } from '../fixtures/baseTest.js';
import * as boundaryHttp from '../../helpers/boundary-http.js';
import { textToMatch } from '../fixtures/tesseractTest.js';
import {
isRdpClientInstalled,
isRdpRunning,
killRdpProcesses,
isOSForRdpSupported,
} from '../../helpers/rdp.js';
const hostName = 'Host name for test';
let org;
let targetWithHost;
let targetWithTwoHosts;
let sshTarget;
let credential;
let updCredential;
let rdpTarget;
test.beforeEach(
async ({ request, targetAddress, targetPort, sshUser, sshKeyPath }) => {
org = await boundaryHttp.createOrg(request);
const project = await boundaryHttp.createProject(request, org.id);
// Create host set
const hostCatalog = await boundaryHttp.createStaticHostCatalog(
request,
project.id,
);
const host = await boundaryHttp.createHost(request, {
hostCatalogId: hostCatalog.id,
address: targetAddress,
});
const host2 = await boundaryHttp.createHost(request, {
hostCatalogId: hostCatalog.id,
address: targetAddress,
name: hostName,
});
const hostSet = await boundaryHttp.createHostSet(request, hostCatalog.id);
await boundaryHttp.addHostToHostSet(request, {
hostSet,
hostIds: [host.id],
});
// Create a host set with 2 hosts
let hostSetWithTwoHosts = await boundaryHttp.createHostSet(
request,
hostCatalog.id,
);
hostSetWithTwoHosts = await boundaryHttp.addHostToHostSet(request, {
hostSet: hostSetWithTwoHosts,
hostIds: [host.id],
});
hostSetWithTwoHosts = await boundaryHttp.addHostToHostSet(request, {
hostSet: hostSetWithTwoHosts,
hostIds: [host2.id],
});
// Create a static credential store and key pair credential
const credentialStore = await boundaryHttp.createStaticCredentialStore(
request,
project.id,
);
credential = await boundaryHttp.createStaticCredentialKeyPair(request, {
credentialStoreId: credentialStore.id,
username: sshUser,
sshKeyPath,
});
updCredential =
await boundaryHttp.createStaticCredentialUsernamePasswordDomain(request, {
credentialStoreId: credentialStore.id,
username: sshUser,
password: 'password',
domain: 'domain',
});
// Create tcp target with host set and 1 host
targetWithHost = await boundaryHttp.createTarget(request, {
scopeId: project.id,
type: 'tcp',
port: targetPort,
});
targetWithHost = await boundaryHttp.addHostSource(request, {
target: targetWithHost,
hostSourceIds: [hostSet.id],
});
targetWithHost = await boundaryHttp.addBrokeredCredentials(request, {
target: targetWithHost,
credentialIds: [credential.id],
});
// Create tcp target with host set and 2 hosts
targetWithTwoHosts = await boundaryHttp.createTarget(request, {
scopeId: project.id,
type: 'tcp',
port: targetPort,
});
targetWithTwoHosts = await boundaryHttp.addHostSource(request, {
target: targetWithTwoHosts,
hostSourceIds: [hostSetWithTwoHosts.id],
});
targetWithTwoHosts = await boundaryHttp.addBrokeredCredentials(request, {
target: targetWithTwoHosts,
credentialIds: [credential.id],
});
// Create an SSH target with address
sshTarget = await boundaryHttp.createTarget(request, {
scopeId: project.id,
type: 'ssh',
port: targetPort,
address: targetAddress,
});
sshTarget = await boundaryHttp.addInjectedCredentials(request, {
target: sshTarget,
credentialIds: [credential.id],
});
// Create an RDP target and add host source and credential sources
rdpTarget = await boundaryHttp.createTarget(request, {
scopeId: project.id,
type: 'rdp',
port: 3389,
});
rdpTarget = await boundaryHttp.addHostSource(request, {
target: rdpTarget,
hostSourceIds: [hostSet.id],
});
rdpTarget = await boundaryHttp.addBrokeredCredentials(request, {
target: rdpTarget,
credentialIds: [updCredential.id],
});
rdpTarget = await boundaryHttp.addInjectedCredentials(request, {
target: rdpTarget,
credentialIds: [updCredential.id],
});
},
);
test.afterEach(async ({ request }) => {
if (org) {
await boundaryHttp.deleteOrg(request, org.id);
}
});
test.describe('Targets tests', () => {
test('Connects to a tcp target with one host', async ({ authedPage }) => {
await authedPage.getByRole('link', { name: targetWithHost.name }).click();
await authedPage.getByRole('button', { name: 'Connect' }).click();
await expect(
authedPage.getByRole('heading', { name: 'Sessions' }),
).toBeVisible();
await expect(authedPage.getByText(credential.name)).toBeVisible();
await expect(authedPage.getByText('username')).toBeVisible();
await expect(authedPage.getByText('private_key')).toBeVisible();
await authedPage
.getByRole('listitem')
.filter({ hasText: 'username' })
.getByLabel('Toggle secret visibility')
.click();
await expect(
authedPage
.getByRole('listitem')
.filter({ hasText: 'username' })
.locator('pre'),
).toHaveText(credential.attributes.username);
await authedPage
.getByRole('listitem')
.filter({ hasText: 'private_key' })
.getByLabel('Toggle secret visibility')
.click();
await expect(
authedPage
.getByRole('listitem')
.filter({ hasText: 'private_key' })
.locator('pre'),
).toContainText(/BEGIN (OPENSSH|RSA) PRIVATE KEY/);
await authedPage.getByRole('button', { name: 'End Session' }).click();
await expect(authedPage.getByText('Canceled successfully.')).toBeVisible();
await expect(
authedPage.getByRole('heading', { name: 'Targets' }),
).toBeVisible();
});
[{ host: 'Quick Connect' }, { host: hostName }].forEach(({ host }) => {
test(`Connects to a tcp target with two hosts using ${host}`, async ({
authedPage,
}) => {
await authedPage
.getByRole('link', { name: targetWithTwoHosts.name })
.click();
// eslint-disable-next-line playwright/no-conditional-in-test
if (host === 'Quick Connect') {
await authedPage.getByRole('button', { name: host }).click();
} else {
await authedPage
.getByRole('row')
.filter({ hasText: host })
.getByRole('button', { name: 'Connect' })
.click();
}
await expect(
authedPage.getByRole('heading', { name: 'Sessions' }),
).toBeVisible();
await expect(authedPage.getByText(credential.name)).toBeVisible();
await expect(authedPage.getByText('username')).toBeVisible();
await expect(authedPage.getByText('private_key')).toBeVisible();
await authedPage
.getByRole('listitem')
.filter({ hasText: 'username' })
.getByLabel('Toggle secret visibility')
.click();
await expect(
authedPage
.getByRole('listitem')
.filter({ hasText: 'username' })
.locator('pre'),
).toHaveText(credential.attributes.username);
await authedPage
.getByRole('listitem')
.filter({ hasText: 'private_key' })
.getByLabel('Toggle secret visibility')
.click();
await expect(
authedPage
.getByRole('listitem')
.filter({ hasText: 'private_key' })
.locator('pre'),
).toContainText(/BEGIN (OPENSSH|RSA) PRIVATE KEY/);
await authedPage.getByRole('button', { name: 'End Session' }).click();
await expect(
authedPage.getByText('Canceled successfully.'),
).toBeVisible();
await expect(authedPage).toHaveURL(
/.*\/scopes\/global\/projects\/targets$/,
);
});
});
test('Connects to an SSH target', async ({ authedPage, tesseract }) => {
await authedPage.getByRole('link', { name: sshTarget.name }).click();
await authedPage.getByRole('button', { name: 'Connect' }).click();
await expect(
authedPage.getByRole('heading', { name: 'Sessions' }),
).toBeVisible();
await authedPage.getByRole('tab', { name: 'Shell' }).click();
await expect(async () => {
const screenshot = await authedPage.locator('.xterm-screen').screenshot();
const result = await tesseract.recognize(screenshot);
expect(result.data.text).toMatch(textToMatch);
}).toPass();
await authedPage.getByRole('button', { name: 'End Session' }).click();
await expect(authedPage.getByText('Canceled successfully.')).toBeVisible();
await expect(
authedPage.getByRole('heading', { name: 'Targets' }),
).toBeVisible();
});
test('Searches targets correctly', async ({ authedPage }) => {
await authedPage.getByLabel('Search').fill(targetWithHost.name);
await expect(
authedPage
.getByRole('row')
.filter({ hasNot: authedPage.getByRole('columnheader') }),
).toHaveCount(1);
await expect(
authedPage.getByRole('link', { name: targetWithHost.name }),
).toBeVisible();
});
test('Launches RDP client when connecting to an RDP target', async ({
authedPage,
}) => {
const isRdpClientInstalledCheck = await isRdpClientInstalled();
const isOSForRdpSupportedCheck = await isOSForRdpSupported();
test.skip(
!isRdpClientInstalledCheck || !isOSForRdpSupportedCheck,
'RDP client is not installed/supported on this system',
);
const beforeLaunchRunning = await isRdpRunning();
expect(beforeLaunchRunning).toBe(false);
await authedPage.getByRole('link', { name: rdpTarget.name }).click();
await authedPage.getByRole('button', { name: 'Open' }).click();
await expect(
authedPage.getByRole('heading', { name: 'Sessions' }),
).toBeVisible();
const afterLaunchRunning = await isRdpRunning();
expect(afterLaunchRunning).toBe(true);
await authedPage.getByRole('button', { name: 'End Session' }).click();
await expect(authedPage.getByText('Canceled successfully.')).toBeVisible();
killRdpProcesses();
const afterKillRunning = await isRdpRunning();
expect(afterKillRunning).toBe(false);
});
});