fix: 🐛 aliasing bugs (#2257)

* fix: 🐛 aliasing bugs
This commit is contained in:
Dharini Jeeva authored and GitHub committed 2024-04-22 12:16:00 -07:00
1 parent 5ce83d9239
commit 4c342061d3
16 files changed
+224 -168

No files matched your search

+1
View File
@@ -60,6 +60,7 @@ questions:
remove-confirm: Are you sure you want to remove this association?
abandon-confirm: Are you sure you want to navigate away? Your unsaved changes will be lost.
retry-confirm: Would you like to retry?
clear-confirm: Are you sure you want to clear the resource id?
themes:
system: System Default
light: Light
@@ -1024,8 +1024,7 @@ alias:
title: Welcome to Aliases
description: No Aliases yet
link: Create a new alias
clear-or-delete: Deleting this alias may break any workflows using it. You can also clear the alias of the resource it points to without deleting it and then edit it to point it to a new resource.
delete: Deleting this alias may break any workflows using it.
delete: Deleting this alias may break any workflows using it. You can also clear the alias of the resource it points to without deleting it and then edit it to point it to a new resource.
form:
options:
label: Alias options
@@ -92,6 +92,7 @@
@isOptional={{true}}
@value={{@model.destination_id}}
@isInvalid={{@model.errors.destination_id}}
readonly={{@hideTargetId}}
disabled={{form.disabled}}
{{on 'input' (set-from-event @model 'destination_id')}}
as |F|
@@ -8,17 +8,13 @@ import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import { tracked } from '@glimmer/tracking';
import { confirm } from 'core/decorators/confirm';
export default class ScopesScopeAliasesIndexController extends Controller {
// =services
@service can;
@service router;
// =attributes
@tracked showModal = false;
@tracked selectedAlias;
@tracked hasDestinationId;
// =actions
/**
@@ -52,32 +48,19 @@ export default class ScopesScopeAliasesIndexController extends Controller {
await this.router.refresh();
}
/**
* Handles modal visibility and sets the destination_id to a tracked variable so we can handle the clear button visibility on the modal
*/
@action
toggleModal(alias) {
if (alias?.destination_id) {
this.hasDestinationId = true;
}
this.showModal = !this.showModal;
this.selectedAlias = alias;
}
/**
* Remove destaination_id from alias
* @param {AliasModel} alias
*/
@action
@loading
@confirm('questions.clear-confirm')
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.clear-success')
async clearAlias(alias) {
alias.destination_id = '';
this.hasDestinationId = false;
await alias.save();
await this.router.refresh();
this.showModal = false;
}
/**
@@ -86,11 +69,12 @@ export default class ScopesScopeAliasesIndexController extends Controller {
*/
@action
@loading
@confirm('resources.alias.messages.delete')
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.delete-success')
async deleteAlias(alias) {
await alias.destroyRecord();
this.showModal = false;
await this.router.replaceWith('scopes.scope.aliases');
await this.router.refresh();
}
}
@@ -147,6 +147,7 @@ export default class ScopesScopeTargetsRoute extends Route {
*/
@action
@loading
@confirm('resources.alias.messages.delete')
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.delete-success')
async deleteAlias(alias) {
@@ -161,6 +162,7 @@ export default class ScopesScopeTargetsRoute extends Route {
*/
@action
@loading
@confirm('questions.clear-confirm')
@notifyError(({ message }) => message, { catch: true })
@notifySuccess('notifications.clear-success')
async clearAlias(alias) {
@@ -23,8 +23,10 @@ export default class ScopesScopeTargetsTargetCreateAliasRoute extends Route {
*/
model() {
const scopeModel = this.store.peekRecord('scope', 'global');
const { id } = this.modelFor('scopes.scope.targets.target');
const record = this.store.createRecord('alias', {
type: TYPE_ALIAS_TARGET,
destination_id: id,
});
record.scopeModel = scopeModel;
return record;
@@ -10,7 +10,7 @@
<page.header>
<h2>
{{t 'resources.alias.title'}}
{{! TODO: DOC LINK }}
<DocLink @doc='aliases' @iconSize='large' />
</h2>
<p>{{t 'resources.alias.description'}}</p>
<Hds::Copy::Snippet @color='secondary' @textToCopy={{@model.id}} />
@@ -23,7 +23,37 @@
</nav.link>
</Rose::Nav::Tabs>
</page.navigation>
{{#let
(hash
canUpdate=(can 'update model' @model)
canDelete=(can 'delete model' @model)
)
as |perms|
}}
<page.actions>
{{#if (or perms.canUpdate perms.canDelete)}}
<Hds::Dropdown as |dd|>
<dd.ToggleButton @text={{t 'actions.manage'}} @color='secondary' />
{{#if (and perms.canUpdate @model.destination_id)}}
<dd.Interactive
@text={{t 'actions.clear'}}
@color='action'
{{on 'click' (fn this.aliases.clearAlias @model)}}
/>
{{/if}}
{{#if perms.canDelete}}
<dd.Interactive
@color='critical'
@text={{t 'actions.delete'}}
{{on 'click' (fn this.aliases.deleteAlias @model)}}
/>
{{/if}}
</Hds::Dropdown>
{{/if}}
</page.actions>
{{/let}}
<page.body>
<Form::Alias
@model={{@model}}
@@ -48,11 +48,11 @@
@route='scopes.scope.aliases.alias'
@model={{B.data.alias.id}}
>
{{B.data.alias.displayName}}
{{B.data.alias.value}}
</LinkTo>
{{else}}
<Hds::Text::Body @tag='p'>
{{B.data.alias.displayName}}
{{B.data.alias.value}}
</Hds::Text::Body>
{{/if}}
{{#if B.data.alias.description}}
@@ -92,12 +92,12 @@
<B.Td>
{{#let
(hash
canRead=(can 'read model' B.data.alias)
canUpdate=(can 'update model' B.data.alias)
canDelete=(can 'delete model' B.data.alias)
)
as |perms|
}}
{{#if (or perms.canRead perms.canDelete)}}
{{#if (or perms.canUpdate perms.canDelete)}}
<Hds::Dropdown as |dd|>
<dd.ToggleIcon
@@ -106,21 +106,26 @@
@hasChevron={{false}}
@size='small'
/>
{{#if perms.canRead}}
{{#if perms.canUpdate}}
<dd.Interactive
@route='scopes.scope.aliases.alias'
@model={{B.data.alias.id}}
@text={{t 'actions.edit'}}
/>
{{#if B.data.alias.destination_id}}
<dd.Interactive
@text={{t 'actions.clear'}}
@color='action'
{{on 'click' (fn this.clearAlias B.data.alias)}}
/>
{{/if}}
{{/if}}
{{#if (and perms.canRead perms.canDelete)}}
<dd.Separator />
{{/if}}
{{#if perms.canDelete}}
<dd.Interactive
@text={{t 'actions.delete'}}
@color='critical'
{{on 'click' (fn this.toggleModal B.data.alias)}}
@text={{t 'actions.delete'}}
{{on 'click' (fn this.deleteAlias B.data.alias)}}
/>
{{/if}}
</Hds::Dropdown>
@@ -163,54 +168,6 @@
</Rose::Message>
</Rose::Layout::Centered>
{{/if}}
{{#if this.showModal}}
<Hds::Modal
class='alias-deletion-modal'
@color='warning'
@onClose={{this.toggleModal}}
as |M|
>
<M.Header @icon='alert-triangle'>
{{t 'questions.delete-confirm'}}
</M.Header>
<M.Body>
<p class='hds-typography-body-300 hds-foreground-primary'>
{{#if this.hasDestinationId}}
{{t 'resources.alias.messages.clear-or-delete'}}
{{else}}
{{t 'resources.alias.messages.delete'}}
{{/if}}
</p>
</M.Body>
<M.Footer>
<Hds::ButtonSet>
<Hds::Button
type='button'
@text={{t 'actions.delete'}}
{{on 'click' (fn this.deleteAlias this.selectedAlias)}}
/>
{{#if this.hasDestinationId}}
<Hds::Button
type='button'
@text={{t 'actions.clear'}}
@color='secondary'
{{on 'click' (fn this.clearAlias this.selectedAlias)}}
/>
{{/if}}
<Hds::Button
type='button'
@text={{t 'actions.cancel'}}
@color='secondary'
{{on 'click' this.toggleModal}}
/>
</Hds::ButtonSet>
</M.Footer>
</Hds::Modal>
{{/if}}
</page.body>
</Rose::Layout::Page>
@@ -25,6 +25,7 @@
<page.body>
<Form::Alias
@model={{@model}}
@hideTargetId='true'
@submit={{route-action 'save' @model}}
@cancel={{route-action 'cancel' @model}}
/>
@@ -14,36 +14,45 @@
<page.header>
<h2>
{{t 'resources.alias.title'}}
{{! TODO: DOC LINK }}
<DocLink @doc='aliases' @iconSize='large' />
</h2>
<p>{{t 'resources.alias.description'}}</p>
<Hds::Copy::Snippet @color='secondary' @textToCopy={{@model.id}} />
</page.header>
<page.actions>
{{#let
(hash
canUpdate=(can 'update model' @model)
canDelete=(can 'delete model' @model)
)
as |perms|
}}
<page.actions>
{{#if (or perms.canUpdate perms.canDelete)}}
<Hds::Dropdown as |dd|>
<dd.ToggleButton
data-test-manage-dropdown
@text={{t 'actions.manage'}}
@color='secondary'
/>
<dd.Interactive
@text={{t 'actions.clear'}}
{{on 'click' (route-action 'clearAlias' @model)}}
/>
{{#if (can 'delete model' @model)}}
<dd.Separator />
<dd.Interactive
data-test-manage-alias-dropdown-delete
@color='critical'
@text={{t 'actions.delete'}}
{{on 'click' (route-action 'deleteAlias' @model)}}
/>
<Hds::Dropdown as |dd|>
<dd.ToggleButton
data-test-manage-dropdown
@text={{t 'actions.manage'}}
@color='secondary'
/>
{{#if (and perms.canUpdate @model.destination_id)}}
<dd.Interactive
@text={{t 'actions.clear'}}
{{on 'click' (route-action 'clearAlias' @model)}}
/>
{{/if}}
{{#if perms.canDelete}}
<dd.Separator />
<dd.Interactive
@color='critical'
@text={{t 'actions.delete'}}
{{on 'click' (route-action 'deleteAlias' @model)}}
/>
{{/if}}
</Hds::Dropdown>
{{/if}}
</Hds::Dropdown>
</page.actions>
</page.actions>
{{/let}}
<page.body>
<Form::Alias
@@ -18,10 +18,8 @@ module('Acceptance | aliases | delete', function (hooks) {
let aliasCount;
const DROPDOWN_BUTTON_SELECTOR = '.hds-dropdown-toggle-icon';
const DROPDOWN_ITEM_SELECTOR = '.hds-dropdown-list-item button';
const MODAL_SELECTOR = '.alias-deletion-modal';
const DELETE_BUTTON_SELECTOR = '.hds-modal__footer .hds-button:nth-child(1)';
const CLEAR_BUTTON_SELECTOR = '.hds-modal__footer .hds-button:nth-child(2)';
const DELETE_DROPDOWN_SELECTOR =
'.hds-dropdown-list-item--color-critical button';
const instances = {
scopes: {
@@ -64,21 +62,14 @@ module('Acceptance | aliases | delete', function (hooks) {
aliasCount = () => this.server.schema.aliases.all().models.length;
});
test('users can delete an alias', async function (assert) {
test('users can delete an alias with proper authorization', async function (assert) {
const count = aliasCount();
assert.true(instances.alias.authorized_actions.includes('delete'));
await visit(urls.globalScope);
urls.alias = `${urls.aliases}/${instances.alias.id}`;
await click(`[href="${urls.aliases}"]`);
await visit(urls.aliases);
await click(DROPDOWN_BUTTON_SELECTOR);
await click(DELETE_DROPDOWN_SELECTOR);
assert.dom(DROPDOWN_ITEM_SELECTOR).exists();
assert.dom(DROPDOWN_ITEM_SELECTOR).hasText('Delete');
await click(DROPDOWN_ITEM_SELECTOR);
assert.dom(MODAL_SELECTOR);
await click(DELETE_BUTTON_SELECTOR);
assert.strictEqual(aliasCount(), count - 1);
});
@@ -93,26 +84,6 @@ module('Acceptance | aliases | delete', function (hooks) {
await click(`[href="${urls.aliases}"]`);
await click(DROPDOWN_BUTTON_SELECTOR);
assert.dom(DROPDOWN_ITEM_SELECTOR).isNotVisible();
});
test('users have the option to clear an alias instead of deleting it', async function (assert) {
const count = aliasCount();
assert.true(instances.alias.authorized_actions.includes('delete'));
await visit(urls.globalScope);
urls.alias = `${urls.aliases}/${instances.alias.id}`;
await click(`[href="${urls.aliases}"]`);
await click(DROPDOWN_BUTTON_SELECTOR);
assert.dom(DROPDOWN_ITEM_SELECTOR).exists();
assert.dom(DROPDOWN_ITEM_SELECTOR).hasText('Delete');
await click(DROPDOWN_ITEM_SELECTOR);
assert.dom(MODAL_SELECTOR);
await click(CLEAR_BUTTON_SELECTOR);
// await click(`[href="${urls.aliases}"]`);
assert.strictEqual(aliasCount(), count);
assert.dom(DELETE_DROPDOWN_SELECTOR).doesNotExist();
});
});
@@ -7,12 +7,16 @@ import { module, test } from 'qunit';
import { visit, click, fillIn } from '@ember/test-helpers';
import { setupApplicationTest } from 'admin/tests/helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import { authenticateSession } from 'ember-simple-auth/test-support';
module('Acceptance | aliases | update', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
setupIndexedDb(hooks);
let aliasCount;
const SAVE_BTN_SELECTOR = '.rose-form-actions [type="submit"]';
@@ -21,6 +25,11 @@ module('Acceptance | aliases | update', function (hooks) {
const NAME_FIELD_TEXT = 'random string';
const BUTTON_SELECTOR = '.rose-form-actions [type="button"]';
const CLEAR_DROPDOWN_SELECTOR =
'.hds-dropdown-list-item--color-action:nth-child(2)';
const DROPDOWN_BUTTON_SELECTOR = '.hds-dropdown-toggle-icon';
const DROPDOWN_ITEM_SELECTOR = '.hds-dropdown-list-item';
const instances = {
scopes: {
@@ -29,12 +38,14 @@ module('Acceptance | aliases | update', function (hooks) {
project: null,
},
alias: null,
target: null,
};
const urls = {
globalScope: null,
aliases: null,
alias: null,
target: null,
};
hooks.beforeEach(function () {
@@ -43,13 +54,17 @@ module('Acceptance | aliases | update', function (hooks) {
type: 'org',
scope: { id: 'global', type: 'global' },
});
instances.target = this.server.create('target', {
scope: instances.scopes.project,
});
instances.alias = this.server.create('alias', {
scope: instances.scopes.global,
destination_id: instances.target.id,
});
urls.globalScope = `/scopes/global`;
urls.aliases = `${urls.globalScope}/aliases`;
urls.alias = `${urls.aliases}/${instances.alias.id}`;
aliasCount = () => this.server.schema.aliases.all().models.length;
authenticateSession({});
});
@@ -78,4 +93,34 @@ module('Acceptance | aliases | update', function (hooks) {
assert.dom(NAME_FIELD_SELECTOR).hasValue(`${name}`);
assert.strictEqual(instances.alias.name, name);
});
test('users have the option to clear an alias', async function (assert) {
const count = aliasCount();
assert.true(instances.alias.authorized_actions.includes('update'));
await visit(urls.globalScope);
urls.alias = `${urls.aliases}/${instances.alias.id}`;
await click(`[href="${urls.aliases}"]`);
await click(DROPDOWN_BUTTON_SELECTOR);
assert.dom(DROPDOWN_ITEM_SELECTOR).exists();
assert.dom(CLEAR_DROPDOWN_SELECTOR).exists();
await click(CLEAR_DROPDOWN_SELECTOR);
assert.strictEqual(aliasCount(), count);
});
test('users can not see the option to clear an alias without proper authorization', async function (assert) {
instances.alias.authorized_actions =
instances.alias.authorized_actions.filter((item) => item !== 'update');
await visit(urls.globalScope);
assert.false(instances.alias.authorized_actions.includes('update'));
urls.alias = `${urls.aliases}/${instances.alias.id}`;
await click(`[href="${urls.aliases}"]`);
await click(DROPDOWN_BUTTON_SELECTOR);
assert.dom(DROPDOWN_ITEM_SELECTOR).exists();
assert.dom(CLEAR_DROPDOWN_SELECTOR).doesNotExist();
});
});
@@ -4,7 +4,7 @@
*/
import { module, test } from 'qunit';
import { visit, click, fillIn } from '@ember/test-helpers';
import { visit, click, fillIn, getContext } from '@ember/test-helpers';
import { setupApplicationTest } from 'admin/tests/helpers';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import a11yAudit from 'ember-a11y-testing/test-support/audit';
@@ -20,6 +20,7 @@ module('Acceptance | targets | create-alias', function (hooks) {
setupIndexedDb(hooks);
let getAliasCount;
let featuresService;
const SAVE_BTN_SELECTOR = '[type="submit"]';
const CANCEL_BTN_SELECTOR = '.rose-form-actions [type="button"]';
@@ -37,6 +38,8 @@ module('Acceptance | targets | create-alias', function (hooks) {
global: null,
org: null,
},
target: null,
alias: null,
};
const urls = {
@@ -47,6 +50,8 @@ module('Acceptance | targets | create-alias', function (hooks) {
};
hooks.beforeEach(function () {
const { owner } = getContext();
featuresService = owner.lookup('service:features');
instances.scopes.global = this.server.create('scope', { id: 'global' });
instances.scopes.org = this.server.create('scope', {
type: 'org',
@@ -61,7 +66,9 @@ module('Acceptance | targets | create-alias', function (hooks) {
scope: instances.scopes.project,
type: TYPE_TARGET_TCP,
});
instances.alias = this.server.create('alias', {
scope: instances.scopes.global,
});
urls.globalScope = `/scopes/global`;
urls.projectScope = `/scopes/${instances.scopes.project.id}`;
@@ -83,18 +90,47 @@ module('Acceptance | targets | create-alias', function (hooks) {
await fillIn(NAME_FIELD_SELECTOR, NAME_FIELD_TEXT);
await fillIn(ALIAS_FIELD_SELECTOR, ALIAS_VALUE_TEXT);
await fillIn(DEST_FIELD_SELECTOR, instances.target.id);
await click(SAVE_BTN_SELECTOR);
const alias = this.server.schema.aliases.findBy({
name: NAME_FIELD_TEXT,
});
assert.strictEqual(alias.name, NAME_FIELD_TEXT);
assert.strictEqual(alias.destinationId, instances.target.id);
assert.strictEqual(alias.scopeId, 'global');
assert.strictEqual(getAliasCount(), aliasCount + 1);
});
test('users can create a new alias for a target of SSH type', async function (assert) {
featuresService.enable('ssh-target');
instances.target.update({
type: TYPE_TARGET_SSH,
});
const aliasCount = getAliasCount();
await visit(urls.targets);
await click(`[href="${urls.target}"]`);
await click(ADD_AN_ALIAS_SELECTOR);
await fillIn(NAME_FIELD_SELECTOR, NAME_FIELD_TEXT);
await fillIn(ALIAS_FIELD_SELECTOR, ALIAS_VALUE_TEXT);
await click(SAVE_BTN_SELECTOR);
const alias = this.server.schema.aliases.findBy({
name: NAME_FIELD_TEXT,
});
assert.strictEqual(alias.name, NAME_FIELD_TEXT);
assert.strictEqual(alias.destinationId, instances.target.id);
assert.strictEqual(alias.scopeId, 'global');
assert.strictEqual(getAliasCount(), aliasCount + 1);
});
test('destination id should be readonly', async function (assert) {
instances.target = this.server.create('target', {
scope: instances.scopes.project,
type: TYPE_TARGET_SSH,
@@ -109,8 +145,7 @@ module('Acceptance | targets | create-alias', function (hooks) {
await fillIn(NAME_FIELD_SELECTOR, NAME_FIELD_TEXT);
await fillIn(ALIAS_FIELD_SELECTOR, ALIAS_VALUE_TEXT);
await fillIn(DEST_FIELD_SELECTOR, instances.target.id);
assert.dom(DEST_FIELD_SELECTOR).hasAttribute('readOnly');
await click(SAVE_BTN_SELECTOR);
const alias = this.server.schema.aliases.findBy({
name: NAME_FIELD_TEXT,
@@ -23,6 +23,7 @@ module('Acceptance | targets | manage-alias', function (hooks) {
const CLEAR_BTN_SELECTOR = '.hds-dropdown-list-item--color-action button';
const DELETE_BTN_SELECTOR = '.hds-dropdown-list-item--color-critical button';
const LINK_TO_NEW_ALIAS = '.target-sidebar-aliases .hds-button';
const DEST_FIELD_SELECTOR = '[name="destination_id"]';
const instances = {
scopes: {
@@ -149,6 +150,8 @@ module('Acceptance | targets | manage-alias', function (hooks) {
assert.dom(DROPDOWN_ITEM_SELECTOR).hasText('Manage');
await click(DROPDOWN_ITEM_SELECTOR);
assert.dom(DEST_FIELD_SELECTOR).doesNotHaveAttribute('readOnly');
assert.strictEqual(currentURL(), urls.tcpAlias);
await click(DROPDOWN_ACTION);
@@ -48,25 +48,27 @@
</Hds::ApplicationState>
</bc.Body>
<bc.Sidebar>
<div class='details-sidebar aliases'>
<div
class='title hds-typography-display-200 hds-font-weight-semibold'
>
{{t 'resources.alias.details'}}
{{#if @model.target.aliases}}
<div class='details-sidebar aliases'>
<div
class='title hds-typography-display-200 hds-font-weight-semibold'
>
{{t 'resources.alias.details'}}
</div>
<Rose::MetadataList @orientation='vertical' as |list|>
{{#each @model.target.aliases as |alias|}}
<list.Item @color='faint'>
<Hds::Copy::Snippet
@textToCopy={{alias.value}}
@color='secondary'
/>
</list.Item>
{{/each}}
</Rose::MetadataList>
</div>
<Rose::MetadataList @orientation='vertical' as |list|>
{{#each @model.target.aliases as |alias|}}
<list.Item @color='faint'>
<Hds::Copy::Snippet
@textToCopy={{alias.value}}
@color='secondary'
/>
</list.Item>
{{/each}}
</Rose::MetadataList>
</div>
{{/if}}
<div class='details-sidebar'>
<div>
<div
@@ -39,6 +39,7 @@ module('Acceptance | projects | targets | target', function (hooks) {
target: null,
targetWithOneHost: null,
targetWithTwoHosts: null,
alias: null,
};
const urls = {
@@ -91,6 +92,7 @@ module('Acceptance | projects | targets | target', function (hooks) {
scope: instances.scopes.project,
address: 'localhost',
});
instances.targetWithOneHost = this.server.create(
'target',
{ scope: instances.scopes.project },
@@ -101,6 +103,10 @@ module('Acceptance | projects | targets | target', function (hooks) {
{ scope: instances.scopes.project },
'withTwoHosts',
);
instances.alias = this.server.create('alias', {
scope: instances.scopes.global,
destination_id: instances.targetWithOneHost.id,
});
instances.session = this.server.create(
'session',
{
@@ -264,14 +270,22 @@ module('Acceptance | projects | targets | target', function (hooks) {
assert.strictEqual(currentURL(), urls.targetWithOneHost);
});
test('user can visit target details and see the associated aliases', async function (assert) {
instances.targetWithOneHost.update({
aliases: [{ id: 123, val: 'value' }],
});
test('user can visit target details and should not see the associated aliases if there are none', async function (assert) {
await visit(urls.targets);
await click(`[href="${urls.targetWithOneHost}"]`);
assert.strictEqual(currentURL(), urls.targetWithOneHost);
assert.dom('.aliases').doesNotExist();
});
test('user can visit target details and see the associated aliases', async function (assert) {
await visit(urls.targets);
instances.targetWithOneHost.update({
aliases: [{ id: instances.alias.id, value: instances.alias.value }],
});
await click(`[href="${urls.targetWithOneHost}"]`);
assert.strictEqual(currentURL(), urls.targetWithOneHost);
assert.dom('.aliases').exists();
});