feat: 🎸 preferred clients section on settings page (#3034)

* feat: 🎸 preferred clients section on settings page

* chore: 🤖 update mock ipc with new handlers

* refactor: 💡 moved windows rdp protocol to const

* refactor: 💡 moved rdp calls to app route

* test: 💍 fixed failings tests

* refactor: 💡 addressed comments

* fix: 🐛 fixed failing tests

* refactor: 💡 add mock rdp service calls to tests

* refactor: 💡 addressed comments

* test: 💍 add additional tests

* refactor: 💡 fixed test failure
This commit is contained in:
Priya Patel authored and Dharini committed 2025-11-19 14:22:06 -08:00
1 parent 9234dbae70
commit e55ea0b629
19 files changed
+487 -31

No files matched your search

@@ -0,0 +1,78 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
}}
<SettingsCard
@header={{t 'settings.preferred-clients.title'}}
@icon='external-link'
@description={{t 'settings.preferred-clients.description'}}
>
<:body>
<Hds::Table
class='full-width'
@model={{this.protocolClients}}
@columns={{array
(hash
label=(t 'settings.preferred-clients.table.header.protocol')
width='50%'
)
(hash
label=(t 'settings.preferred-clients.table.header.client') width='50%'
)
}}
>
<:body as |B|>
<B.Tr>
<B.Td>{{t
(concat
'settings.preferred-clients.table.data.protocols.'
B.data.protocolType
)
}}
</B.Td>
<B.Td>
{{#if this.showRecommendedRdpClient}}
<Hds::Text::Body data-test-recommended-rdp-client>
{{t
'settings.preferred-clients.table.data.clients.none-detected'
rdpClientLink=this.rdp.recommendedRdpClient.link
rdpClientName=(t
(concat
'settings.preferred-clients.table.data.clients.'
this.rdp.recommendedRdpClient.name
)
)
htmlSafe=true
}}
</Hds::Text::Body>
{{else}}
<Hds::Form::Select::Field
@width='100%'
{{on 'change' B.data.updateClient}}
data-test-select-preferred-rdp-client
as |F|
>
<F.Options>
{{#each B.data.clients as |client|}}
<option
value={{client}}
selected={{eq B.data.preferredClient client}}
>
{{t
(concat
'settings.preferred-clients.table.data.clients.'
client
)
}}
</option>
{{/each}}
</F.Options>
</Hds::Form::Select::Field>
{{/if}}
</B.Td>
</B.Tr>
</:body>
</Hds::Table>
</:body>
</SettingsCard>
@@ -0,0 +1,50 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { service } from '@ember/service';
const PROTOCOL_WINDOWS_RDP = 'windows-rdp';
export default class SettingsCardPreferredClientsComponent extends Component {
// =services
@service rdp;
// =getters
/**
* Returns the list of protocols and their available clients
* @returns {Array<Object>}
*/
get protocolClients() {
return [
{
protocolType: PROTOCOL_WINDOWS_RDP,
clients: this.rdp.rdpClients,
preferredClient: this.rdp.preferredRdpClient,
updateClient: this.updatePreferredRDPClient,
},
];
}
get showRecommendedRdpClient() {
return (
this.rdp.rdpClients.length === 1 && this.rdp.rdpClients[0] === 'none'
);
}
// =methods
/**
* Updates the preferred RDP client
* @param value
* @return {Promise<void>}
*/
@action
async updatePreferredRDPClient({ target: { value } }) {
await this.rdp.setPreferredRdpClient(value);
}
}
+4
View File
@@ -16,6 +16,7 @@ export default class ApplicationRoute extends Route {
@service clusterUrl;
@service ipc;
@service intl;
@service rdp;
// =attributes
@@ -52,6 +53,9 @@ export default class ApplicationRoute extends Route {
await this.session.loadAuthenticatedAccount();
}
// initialize RDP service with rdp client data
await this.rdp.initialize();
}
/**
+59 -6
View File
@@ -7,7 +7,23 @@ import Service from '@ember/service';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export const RDP_CLIENT_NONE = 'none';
export const RDP_CLIENT_WINDOWS_APP = 'windows-app';
export const RDP_CLIENT_MSTSC = 'mstsc';
export const RDP_CLIENT_WINDOWS_APP_LINK =
'https://apps.apple.com/us/app/windows-app/id1295203466';
export const RDP_CLIENT_MSTSC_LINK =
'https://learn.microsoft.com/windows-server/remote/remote-desktop-services/remotepc/uninstall-remote-desktop-connection';
const { __electronLog } = globalThis;
const macRecommendedRdpClient = {
name: RDP_CLIENT_WINDOWS_APP,
link: RDP_CLIENT_WINDOWS_APP_LINK,
};
const windowsRecommendedRdpClient = {
name: RDP_CLIENT_MSTSC,
link: RDP_CLIENT_MSTSC_LINK,
};
export default class RdpService extends Service {
// =services
@@ -19,17 +35,21 @@ export default class RdpService extends Service {
/**
* The preferred RDP client set by the user.
* @type {string|null}
* @private
*/
@tracked preferredRdpClient = null;
/**
* The list of available RDP clients fetched from the main process.
* @type {Array<String>}
* @private
*/
@tracked rdpClients = [];
/**
* The recommended RDP client based on platform when only 'none' is available.
* @type {Object|null}
*/
@tracked recommendedRdpClient = null;
// =attributes
/**
@@ -40,12 +60,21 @@ export default class RdpService extends Service {
*/
get isPreferredRdpClientSet() {
return (
this.preferredRdpClient !== null && this.preferredRdpClient !== 'none'
this.preferredRdpClient !== null &&
this.preferredRdpClient !== RDP_CLIENT_NONE
);
}
// =methods
async initialize() {
await Promise.all([
this.getRdpClients(),
this.getPreferredRdpClient(),
this.getRecommendedRdpClient(),
]);
}
/**
* Fetches the list of available RDP clients from the main process.
*/
@@ -60,11 +89,35 @@ export default class RdpService extends Service {
} catch (error) {
__electronLog?.error('Failed to fetch RDP clients', error.message);
// default to 'none' option if it fails
this.rdpClients = ['none'];
this.rdpClients = [RDP_CLIENT_NONE];
return this.rdpClients;
}
}
/**
* Gets the recommended RDP client based on OS platform.
*/
async getRecommendedRdpClient() {
try {
// return cached recommended client if already set
if (this.recommendedRdpClient !== null) {
return this.recommendedRdpClient;
}
const { isWindows, isMac } = await this.ipc.invoke('checkOS');
if (isWindows) {
this.recommendedRdpClient = windowsRecommendedRdpClient;
} else if (isMac) {
this.recommendedRdpClient = macRecommendedRdpClient;
}
} catch (error) {
__electronLog?.error(
'Failed to set recommended RDP client',
error.message,
);
this.recommendedRdpClient = null;
}
}
/**
* Fetches the preferred RDP client from the main process.
* @returns {string} The preferred RDP client
@@ -83,7 +136,7 @@ export default class RdpService extends Service {
error.message,
);
// default to 'none' if it fails
this.preferredRdpClient = 'none';
this.preferredRdpClient = RDP_CLIENT_NONE;
return this.preferredRdpClient;
}
}
@@ -101,7 +154,7 @@ export default class RdpService extends Service {
} catch (error) {
__electronLog?.error('Failed to set preferred RDP client', error.message);
// set to 'none' if it fails
this.preferredRdpClient = 'none';
this.preferredRdpClient = RDP_CLIENT_NONE;
}
}
@@ -7,4 +7,5 @@
<SettingsCard::Server @model={{@model}} />
<SettingsCard::Application @model={{@model}} @toggle={{this.toggleTheme}} />
<SettingsCard::ClientAgent @model={{@model}} />
<SettingsCard::Logs @model={{@model}} />
<SettingsCard::Logs @model={{@model}} />
<SettingsCard::PreferredClients />
+6 -2
View File
@@ -164,13 +164,17 @@ const createWindow = async (partition, closeWindowCB) => {
// Opens external links in the host default browser.
// We allow developer.hashicorp.com domain to open on an external window
// and releases.hashicorp.com domain to download the desktop app or
// link to the release page for the desktop app.
// link to the release page for the desktop app or
// apps.apple.com domain to open the app store page to download the Windows App or
// learn.microsoft.com domain to open the documentation for installing Remote Desktop Connection.
browserWindow.webContents.setWindowOpenHandler(({ url }) => {
if (
isLocalhost(url) ||
url.startsWith('https://developer.hashicorp.com/') ||
url.startsWith('https://releases.hashicorp.com/boundary-desktop/') ||
url.startsWith('https://support.hashicorp.com/hc/en-us')
url.startsWith('https://support.hashicorp.com/hc/en-us') ||
url.startsWith('https://learn.microsoft.com/') ||
url.startsWith('https://apps.apple.com/')
) {
shell.openExternal(url);
}
@@ -9,10 +9,15 @@ const which = require('which');
const { isMac, isWindows } = require('../helpers/platform.js');
const store = require('./electron-store-manager');
// RDP Clients
const RDP_CLIENT_NONE = 'none';
const RDP_CLIENT_WINDOWS_APP = 'windows-app';
const RDP_CLIENT_MSTSC = 'mstsc';
// RDP Client Configuration
const RDP_CLIENTS = [
{
value: 'mstsc',
value: RDP_CLIENT_MSTSC,
isAvailable: async () => {
if (!isWindows()) return false;
try {
@@ -24,7 +29,7 @@ const RDP_CLIENTS = [
},
},
{
value: 'windows-app',
value: RDP_CLIENT_WINDOWS_APP,
isAvailable: () => {
if (!isMac()) return false;
try {
@@ -50,7 +55,7 @@ const RDP_CLIENTS = [
},
},
{
value: 'none',
value: RDP_CLIENT_NONE,
isAvailable: () => true,
},
];
@@ -78,8 +83,10 @@ class RdpClientManager {
*/
async getBestDefaultRdpClient() {
const availableClients = await this.getAvailableRdpClients();
const bestClient = availableClients.find((client) => client !== 'none');
return bestClient ?? 'none';
const bestClient = availableClients.find(
(client) => client !== RDP_CLIENT_NONE,
);
return bestClient ?? RDP_CLIENT_NONE;
}
/**
@@ -103,7 +110,7 @@ class RdpClientManager {
*/
setPreferredRdpClient(preferredClient) {
if (!preferredClient) {
store.set('preferredRdpClient', 'none');
store.set('preferredRdpClient', RDP_CLIENT_NONE);
} else {
store.set('preferredRdpClient', preferredClient);
}
@@ -34,6 +34,10 @@ module('Acceptance | Application', function (hooks) {
const ipcService = this.owner.lookup('service:ipc');
stubs.ipcService = sinon.stub(ipcService, 'invoke');
// mock RDP service calls
let rdpService = this.owner.lookup('service:rdp');
sinon.stub(rdpService, 'initialize').resolves();
});
hooks.afterEach(function () {
@@ -94,6 +94,10 @@ module('Acceptance | clusterUrl', function (hooks) {
urls.authenticate.methods.global = `${urls.authenticate.global}/${instances.authMethods.global.id}`;
urls.projects = `${urls.scopes.global}/projects`;
urls.targets = `${urls.projects}/targets`;
// mock RDP service calls
let rdpService = this.owner.lookup('service:rdp');
sinon.stub(rdpService, 'initialize').resolves();
});
hooks.afterEach(function () {
@@ -20,6 +20,7 @@ import {
} from 'api/models/session';
import setupStubs from 'api/test-support/handlers/cache-daemon-search';
import { setRunOptions } from 'ember-a11y-testing/test-support';
import sinon from 'sinon';
module('Acceptance | projects | sessions | index', function (hooks) {
setupApplicationTest(hooks);
@@ -147,6 +148,10 @@ module('Acceptance | projects | sessions | index', function (hooks) {
this.ipcStub.withArgs('isCacheDaemonRunning').returns(true);
this.stubCacheDaemonSearch('sessions', 'sessions', 'targets');
// mock RDP service calls
let rdpService = this.owner.lookup('service:rdp');
sinon.stub(rdpService, 'initialize').resolves();
});
test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) {
@@ -13,6 +13,7 @@ import WindowMockIPC from '../../../helpers/window-mock-ipc';
import { STATUS_SESSION_ACTIVE } from 'api/models/session';
import setupStubs from 'api/test-support/handlers/cache-daemon-search';
import { setRunOptions } from 'ember-a11y-testing/test-support';
import sinon from 'sinon';
module('Acceptance | projects | sessions | session', function (hooks) {
setupApplicationTest(hooks);
@@ -136,6 +137,10 @@ module('Acceptance | projects | sessions | session', function (hooks) {
setDefaultClusterUrl(this);
this.ipcStub.withArgs('isCacheDaemonRunning').returns(false);
// mock RDP service calls
let rdpService = this.owner.lookup('service:rdp');
sinon.stub(rdpService, 'initialize').resolves();
});
hooks.afterEach(function () {
@@ -19,6 +19,12 @@ import {
import WindowMockIPC from '../../../helpers/window-mock-ipc';
import setupStubs from 'api/test-support/handlers/cache-daemon-search';
import { setRunOptions } from 'ember-a11y-testing/test-support';
import {
RDP_CLIENT_MSTSC_LINK,
RDP_CLIENT_MSTSC,
RDP_CLIENT_NONE,
RDP_CLIENT_WINDOWS_APP,
} from 'desktop/services/rdp';
module('Acceptance | projects | settings | index', function (hooks) {
setupApplicationTest(hooks);
@@ -58,6 +64,9 @@ module('Acceptance | projects | settings | index', function (hooks) {
const SIGNOUT_BTN = '[data-test-settings-signout-btn]';
const MODAL_CLOSE_SESSIONS = '[data-test-close-sessions-modal]';
const MODAL_CONFIRM_BTN = '.hds-modal__footer .hds-button--color-primary';
const RDP_PREFERRED_CLIENT = '[data-test-select-preferred-rdp-client]';
const RDP_RECOMMENDED_CLIENT = '[data-test-recommended-rdp-client]';
const RDP_RECOMMENDED_CLIENT_LINK = '[data-test-recommended-rdp-client] a';
const setDefaultClusterUrl = (test) => {
const windowOrigin = window.location.origin;
@@ -98,6 +107,13 @@ module('Acceptance | projects | settings | index', function (hooks) {
this.ipcStub
.withArgs('cacheDaemonStatus')
.returns({ version: 'Boundary CLI v0.1.0' });
// mock RDP client data
this.ipcStub
.withArgs('getRdpClients')
.returns([RDP_CLIENT_MSTSC, RDP_CLIENT_NONE]);
this.ipcStub.withArgs('getPreferredRdpClient').returns(RDP_CLIENT_MSTSC);
this.ipcStub.withArgs('checkOS').returns({ isWindows: true, isMac: false });
});
test('can navigate to the settings page', async function (assert) {
@@ -226,4 +242,53 @@ module('Acceptance | projects | settings | index', function (hooks) {
assert.ok(stopAllSessions.calledOnce);
assert.notOk(currentSession().isAuthenticated);
});
test('preferred RDP client is selected correctly for Windows', async function (assert) {
await visit(urls.settings);
assert.dom(RDP_PREFERRED_CLIENT).isVisible().hasValue(RDP_CLIENT_MSTSC);
});
test('preferred RDP client is selected correctly for Mac', async function (assert) {
// update IPC stub fo mac
this.ipcStub.withArgs('checkOS').returns({ isWindows: false, isMac: true });
this.ipcStub
.withArgs('getRdpClients')
.returns([RDP_CLIENT_WINDOWS_APP, RDP_CLIENT_NONE]);
this.ipcStub
.withArgs('getPreferredRdpClient')
.returns(RDP_CLIENT_WINDOWS_APP);
await visit(urls.settings);
assert
.dom(RDP_PREFERRED_CLIENT)
.isVisible()
.hasValue(RDP_CLIENT_WINDOWS_APP);
});
test('recommended RDP client is shown when no RDP clients are detected', async function (assert) {
// update IPC stub for no RDP clients
this.ipcStub.withArgs('getRdpClients').returns([RDP_CLIENT_NONE]);
this.ipcStub.withArgs('getPreferredRdpClient').returns(RDP_CLIENT_NONE);
await visit(urls.settings);
assert.dom(RDP_RECOMMENDED_CLIENT).isVisible();
assert
.dom(RDP_RECOMMENDED_CLIENT_LINK)
.hasAttribute('href', RDP_CLIENT_MSTSC_LINK)
.hasText('Remote Desktop Connection (mstsc)');
});
test('preferred RDP client is updated correctly', async function (assert) {
const rdpService = this.owner.lookup('service:rdp');
this.ipcStub.withArgs('setPreferredRdpClient').resolves();
await visit(urls.settings);
await select(RDP_PREFERRED_CLIENT, RDP_CLIENT_NONE);
assert.ok(
this.ipcStub.calledWith('setPreferredRdpClient', RDP_CLIENT_NONE),
);
assert.strictEqual(rdpService.preferredRdpClient, RDP_CLIENT_NONE);
});
});
@@ -23,6 +23,7 @@ import {
STATUS_SESSION_TERMINATED,
} from 'api/models/session';
import { TYPE_TARGET_RDP } from 'api/models/target';
import sinon from 'sinon';
module('Acceptance | projects | targets | index', function (hooks) {
setupApplicationTest(hooks);
@@ -162,6 +163,10 @@ module('Acceptance | projects | targets | index', function (hooks) {
this.ipcStub.withArgs('isCacheDaemonRunning').returns(true);
this.stubCacheDaemonSearch('sessions', 'targets', 'aliases', 'sessions');
// mock RDP service calls
let rdpService = this.owner.lookup('service:rdp');
sinon.stub(rdpService, 'initialize').resolves();
});
test('visiting index while unauthenticated redirects to global authenticate method', async function (assert) {
@@ -18,6 +18,7 @@ import WindowMockIPC from '../../../helpers/window-mock-ipc';
import setupStubs from 'api/test-support/handlers/cache-daemon-search';
import { setRunOptions } from 'ember-a11y-testing/test-support';
import { TYPE_TARGET_RDP } from 'api/models/target';
import sinon from 'sinon';
module('Acceptance | projects | targets | target', function (hooks) {
setupApplicationTest(hooks);
@@ -153,6 +154,10 @@ module('Acceptance | projects | targets | target', function (hooks) {
this.ipcStub.withArgs('isCacheDaemonRunning').returns(true);
this.stubCacheDaemonSearch('sessions', 'targets', 'aliases', 'sessions');
// mock RDP service calls
this.rdpService = this.owner.lookup('service:rdp');
sinon.stub(this.rdpService, 'initialize').resolves();
});
test('user can connect to a target with an address', async function (assert) {
@@ -630,8 +635,7 @@ module('Acceptance | projects | targets | target', function (hooks) {
});
test('shows `Open` and `Connect` button for RDP target with preferred client', async function (assert) {
let rdpService = this.owner.lookup('service:rdp');
rdpService.preferredRdpClient = 'windows-app';
this.rdpService.preferredRdpClient = 'windows-app';
instances.target.update({ type: TYPE_TARGET_RDP });
this.stubCacheDaemonSearch();
@@ -645,8 +649,7 @@ module('Acceptance | projects | targets | target', function (hooks) {
});
test('shows "Connect" button for RDP target without preferred client', async function (assert) {
let rdpService = this.owner.lookup('service:rdp');
rdpService.preferredRdpClient = null;
this.rdpService.preferredRdpClient = null;
instances.target.update({ type: TYPE_TARGET_RDP });
this.stubCacheDaemonSearch();
@@ -658,8 +661,7 @@ module('Acceptance | projects | targets | target', function (hooks) {
});
test('clicking `open` button for RDP target triggers launchRdpClient', async function (assert) {
let rdpService = this.owner.lookup('service:rdp');
rdpService.preferredRdpClient = 'windows-app';
this.rdpService.preferredRdpClient = 'windows-app';
instances.target.update({ type: TYPE_TARGET_RDP });
this.ipcStub.withArgs('cliExists').returns(true);
@@ -683,8 +685,7 @@ module('Acceptance | projects | targets | target', function (hooks) {
});
test('shows `Connect` button for rdp target without preferred client', async function (assert) {
let rdpService = this.owner.lookup('service:rdp');
rdpService.preferredRdpClient = null;
this.rdpService.preferredRdpClient = null;
instances.target.update({ type: TYPE_TARGET_RDP });
this.stubCacheDaemonSearch();
@@ -708,8 +709,7 @@ module('Acceptance | projects | targets | target', function (hooks) {
});
test('shows confirm modal when quickConnectAndLaunchRdp fails', async function (assert) {
let rdpService = this.owner.lookup('service:rdp');
rdpService.preferredRdpClient = 'windows-app';
this.rdpService.preferredRdpClient = 'windows-app';
instances.target.update({ type: TYPE_TARGET_RDP });
this.stubCacheDaemonSearch();
@@ -21,6 +21,7 @@ import {
import WindowMockIPC from '../helpers/window-mock-ipc';
import setupStubs from 'api/test-support/handlers/cache-daemon-search';
import { setRunOptions } from 'ember-a11y-testing/test-support';
import sinon from 'sinon';
module('Acceptance | scopes', function (hooks) {
setupApplicationTest(hooks);
@@ -138,6 +139,10 @@ module('Acceptance | scopes', function (hooks) {
this.ipcStub.withArgs('isCacheDaemonRunning').returns(true);
this.stubCacheDaemonSearch('sessions', 'targets', 'aliases', 'sessions');
// mock RDP service calls
let rdpService = this.owner.lookup('service:rdp');
sinon.stub(rdpService, 'initialize').resolves();
});
test('visiting index', async function (assert) {
@@ -0,0 +1,91 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, select } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { setupIntl } from 'ember-intl/test-support';
import Service from '@ember/service';
import {
RDP_CLIENT_WINDOWS_APP,
RDP_CLIENT_NONE,
RDP_CLIENT_WINDOWS_APP_LINK,
} from 'desktop/services/rdp';
module(
'Integration | Component | settings-card/preferred-clients',
function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks, 'en-us');
test('it renders protocol and preferred client correctly', async function (assert) {
let updatedPreferredRDPClient;
this.owner.register(
'service:rdp',
class extends Service {
rdpClients = [RDP_CLIENT_WINDOWS_APP, RDP_CLIENT_NONE];
preferredRdpClient = RDP_CLIENT_WINDOWS_APP;
setPreferredRdpClient = (value) => {
updatedPreferredRDPClient = value;
};
},
);
await render(hbs`<SettingsCard::PreferredClients />`);
assert
.dom('.hds-table tbody tr td:first-child')
.hasText('Windows RDP', 'Protocol is rendered');
assert
.dom('select option:checked')
.hasText('Windows App', 'Preferred client is selected');
await select('select', RDP_CLIENT_NONE);
assert
.dom('select option:checked')
.hasText('None', 'Preferred client is updated');
assert.strictEqual(
updatedPreferredRDPClient,
RDP_CLIENT_NONE,
'setPreferredRdpClient is called with correct value',
);
});
test('it renders recommended client link only when none is detected', async function (assert) {
this.owner.register(
'service:rdp',
class extends Service {
rdpClients = [RDP_CLIENT_NONE];
recommendedRdpClient = {
name: RDP_CLIENT_WINDOWS_APP,
link: RDP_CLIENT_WINDOWS_APP_LINK,
};
},
);
await render(hbs`<SettingsCard::PreferredClients />`);
assert
.dom('.hds-table tbody tr td:first-child')
.hasText('Windows RDP', 'Protocol is rendered');
assert
.dom('.hds-table tbody tr td:last-child')
.includesText(
'None detected. We recommend Windows App',
'None detected message is rendered',
);
assert
.dom('.hds-table tbody tr td:last-child a')
.hasAttribute(
'href',
RDP_CLIENT_WINDOWS_APP_LINK,
'windows app download link is rendered',
);
});
},
);
+52 -6
View File
@@ -6,6 +6,13 @@
import { module, test } from 'qunit';
import { setupTest } from 'desktop/tests/helpers';
import sinon from 'sinon';
import {
RDP_CLIENT_NONE,
RDP_CLIENT_WINDOWS_APP,
RDP_CLIENT_MSTSC,
RDP_CLIENT_WINDOWS_APP_LINK,
RDP_CLIENT_MSTSC_LINK,
} from 'desktop/services/rdp';
module('Unit | Service | rdp', function (hooks) {
setupTest(hooks);
@@ -17,12 +24,19 @@ module('Unit | Service | rdp', function (hooks) {
ipcService = this.owner.lookup('service:ipc');
});
hooks.afterEach(function () {
sinon.restore();
});
test('getRdpClients sets to fallback value on error', async function (assert) {
sinon.stub(ipcService, 'invoke').withArgs('getRdpClients').rejects();
const ipcStub = sinon.stub(ipcService, 'invoke');
ipcStub.withArgs('getRdpClients').rejects();
ipcStub.withArgs('checkOS').resolves({ isMac: true });
await service.getRdpClients();
assert.deepEqual(
service.rdpClients,
['none'],
[RDP_CLIENT_NONE],
'rdpClients fallback is set correctly',
);
});
@@ -33,9 +47,10 @@ module('Unit | Service | rdp', function (hooks) {
.withArgs('getPreferredRdpClient')
.rejects();
await service.getPreferredRdpClient();
assert.strictEqual(
service.preferredRdpClient,
'none',
RDP_CLIENT_NONE,
'preferredRdpClient fallback is set correctly',
);
});
@@ -43,13 +58,44 @@ module('Unit | Service | rdp', function (hooks) {
test('setPreferredRdpClient sets to fallback value on error', async function (assert) {
sinon
.stub(ipcService, 'invoke')
.withArgs('setPreferredRdpClient', 'mstsc')
.withArgs('setPreferredRdpClient', RDP_CLIENT_MSTSC)
.rejects();
await service.setPreferredRdpClient('mstsc');
await service.setPreferredRdpClient(RDP_CLIENT_MSTSC);
assert.strictEqual(
service.preferredRdpClient,
'none',
RDP_CLIENT_NONE,
'preferredRdpClient fallback is set correctly',
);
});
test('sets recommendedRdpClient correctly based on OS', async function (assert) {
sinon
.stub(ipcService, 'invoke')
.withArgs('checkOS')
.resolves({ isWindows: true });
await service.getRecommendedRdpClient();
assert.deepEqual(
service.recommendedRdpClient,
{
name: RDP_CLIENT_MSTSC,
link: RDP_CLIENT_MSTSC_LINK,
},
'recommendedRdpClient is set correctly for windows',
);
ipcService.invoke.withArgs('checkOS').resolves({ isMac: true });
service.recommendedRdpClient = null;
await service.getRecommendedRdpClient();
assert.deepEqual(
service.recommendedRdpClient,
{
name: RDP_CLIENT_WINDOWS_APP,
link: RDP_CLIENT_WINDOWS_APP_LINK,
},
'recommendedRdpClient is set correctly for mac',
);
});
});