test: 💍 refactor session-recording test selectors (#2811)

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-16423
This commit is contained in:
Lisbet Alvarez authored and GitHub committed 2025-05-05 10:41:42 -07:00
1 parent b7559c1f4e
commit 8dafc2b9a0
5 files changed
+154 -116

No files matched your search

@@ -21,12 +21,8 @@
{{#if
(can 'reapplyStoragePolicy session-recording' @model.sessionRecording)
}}
<Hds::Dropdown as |dd|>
<dd.ToggleButton
data-test-manage-dropdown
@text={{t 'actions.manage'}}
@color='secondary'
/>
<Hds::Dropdown data-test-manage-channels-dropdown as |dd|>
<dd.ToggleButton @text={{t 'actions.manage'}} @color='secondary' />
<dd.Interactive
{{on 'click' (fn this.reapplyStoragePolicy @model.sessionRecording)}}
@@ -34,7 +30,6 @@
{{#if (can 'delete session-recording' @model.sessionRecording)}}
<dd.Separator />
<dd.Interactive
data-test-manage-dropdown-delete
@color='critical'
{{on 'click' (fn this.delete @model.sessionRecording)}}
>
@@ -4,20 +4,14 @@
*/
import { module, test } from 'qunit';
import {
visit,
currentURL,
click,
fillIn,
waitUntil,
findAll,
} from '@ember/test-helpers';
import { visit, currentURL, click, fillIn, waitFor } 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';
import * as commonSelectors from 'admin/tests/helpers/selectors';
import { faker } from '@faker-js/faker';
import * as commonSelectors from 'admin/tests/helpers/selectors';
import * as selectors from './selectors';
module('Acceptance | session recordings | list', function (hooks) {
setupApplicationTest(hooks);
@@ -26,17 +20,6 @@ module('Acceptance | session recordings | list', function (hooks) {
let featuresService;
// Selectors
const SESSION_RECORDING_TITLE = 'Session Recordings';
const SEARCH_INPUT_SELECTOR = '.search-filtering [type="search"]';
const NO_RESULTS_MSG_SELECTOR = '[data-test-no-session-recording-results]';
const FILTER_TOGGLE_SELECTOR = (name) =>
`[data-test-session-recordings-bar] div[name="${name}"] button`;
const FILTER_APPLY_BUTTON = (name) =>
`[data-test-session-recordings-bar] div[name="${name}"] div div:last-child button[type="button"]`;
const LAST_3_DAYS_OPTION =
'[data-test-session-recordings-bar] div[name="time"] li:nth-child(2) button';
// Instances
const instances = {
scopes: {
@@ -127,19 +110,20 @@ module('Acceptance | session recordings | list', function (hooks) {
test('users can navigate to session-recordings with proper authorization', async function (assert) {
await visit(urls.globalScope);
assert.true(
instances.scopes.global.authorized_collection_actions[
'session-recordings'
].includes('list'),
);
assert.dom(`[href="${urls.sessionRecordings}"]`).exists();
assert.dom(commonSelectors.HREF(urls.sessionRecordings)).isVisible();
assert
.dom(commonSelectors.SIDEBAR_NAV_CONTENT)
.includesText(SESSION_RECORDING_TITLE);
.includesText(selectors.SESSION_RECORDING_TITLE);
// Visit session recordings
await click(`[href="${urls.sessionRecordings}"]`);
await click(commonSelectors.HREF(urls.sessionRecordings));
assert.strictEqual(currentURL(), urls.sessionRecordings);
});
@@ -147,7 +131,6 @@ module('Acceptance | session recordings | list', function (hooks) {
instances.scopes.global.authorized_collection_actions[
'session-recordings'
] = [];
await visit(urls.globalScope);
assert.false(
@@ -157,83 +140,95 @@ module('Acceptance | session recordings | list', function (hooks) {
);
assert
.dom(commonSelectors.SIDEBAR_NAV_CONTENT)
.doesNotIncludeText(SESSION_RECORDING_TITLE);
assert.dom(`[href="${urls.sessionRecordings}"]`).doesNotExist();
.doesNotIncludeText(selectors.SESSION_RECORDING_TITLE);
assert.dom(commonSelectors.HREF(urls.sessionRecordings)).doesNotExist();
});
test('user can search for a session recording by id', async function (assert) {
await visit(urls.sessionRecordings);
await visit(urls.globalScope);
assert.dom(commonSelectors.HREF(urls.sessionRecording)).exists();
assert.dom(commonSelectors.HREF(urls.sessionRecording2)).exists();
await click(commonSelectors.HREF(urls.sessionRecordings));
await fillIn(SEARCH_INPUT_SELECTOR, instances.sessionRecording.id);
await waitUntil(
() => findAll(commonSelectors.HREF(urls.sessionRecording2)).length === 0,
);
assert.dom(commonSelectors.HREF(urls.sessionRecording)).isVisible();
assert.dom(commonSelectors.HREF(urls.sessionRecording2)).isVisible();
assert.dom(commonSelectors.HREF(urls.sessionRecording)).exists();
await fillIn(commonSelectors.SEARCH_INPUT, instances.sessionRecording.id);
await waitFor(commonSelectors.HREF(urls.sessionRecording2), { count: 0 });
assert.dom(commonSelectors.HREF(urls.sessionRecording)).isVisible();
assert.dom(commonSelectors.HREF(urls.sessionRecording2)).doesNotExist();
});
test('user can search for a session recording by id and get no results', async function (assert) {
await visit(urls.sessionRecordings);
await visit(urls.globalScope);
assert.dom(commonSelectors.HREF(urls.sessionRecording)).exists();
assert.dom(commonSelectors.HREF(urls.sessionRecording2)).exists();
await click(commonSelectors.HREF(urls.sessionRecordings));
await fillIn(SEARCH_INPUT_SELECTOR, 'sr_404');
await waitUntil(() => findAll(NO_RESULTS_MSG_SELECTOR).length === 1);
assert.dom(commonSelectors.HREF(urls.sessionRecording)).isVisible();
assert.dom(commonSelectors.HREF(urls.sessionRecording2)).isVisible();
await fillIn(commonSelectors.SEARCH_INPUT, 'sr_404');
await waitFor(selectors.NO_RESULTS_MSG, { count: 1 });
assert.dom(commonSelectors.HREF(urls.sessionRecording)).doesNotExist();
assert.dom(commonSelectors.HREF(urls.sessionRecording2)).doesNotExist();
assert.dom(NO_RESULTS_MSG_SELECTOR).includesText('No results found');
assert.dom(selectors.NO_RESULTS_MSG).includesText('No results found');
});
test('user can filter session recordings by user', async function (assert) {
await visit(urls.sessionRecordings);
await visit(urls.globalScope);
assert.dom('tbody tr').exists({ count: 2 });
await click(commonSelectors.HREF(urls.sessionRecordings));
await click(FILTER_TOGGLE_SELECTOR('user'));
await click(`input[value="${instances.user.id}"]`);
await click(FILTER_APPLY_BUTTON('user'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 2 });
assert.dom('tbody tr').exists({ count: 1 });
await click(commonSelectors.FILTER_DROPDOWN('user'));
await click(commonSelectors.FILTER_DROPDOWN_ITEM(instances.user.id));
await click(commonSelectors.FILTER_DROPDOWN_ITEM_APPLY_BTN('user'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 1 });
});
test('user can filter session recordings by scope', async function (assert) {
await visit(urls.sessionRecordings);
await visit(urls.globalScope);
assert.dom('tbody tr').exists({ count: 2 });
await click(commonSelectors.HREF(urls.sessionRecordings));
await click(FILTER_TOGGLE_SELECTOR('target'));
await click(`input[value="${instances.target.id}"]`);
await click(FILTER_APPLY_BUTTON('target'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 2 });
assert.dom('tbody tr').exists({ count: 1 });
await click(commonSelectors.FILTER_DROPDOWN('target'));
await click(commonSelectors.FILTER_DROPDOWN_ITEM(instances.target.id));
await click(commonSelectors.FILTER_DROPDOWN_ITEM_APPLY_BTN('target'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 1 });
});
test('user can filter session recordings by target', async function (assert) {
await visit(urls.sessionRecordings);
await visit(urls.globalScope);
assert.dom('tbody tr').exists({ count: 2 });
await click(commonSelectors.HREF(urls.sessionRecordings));
await click(FILTER_TOGGLE_SELECTOR('scope'));
await click(`input[value="${instances.target.scope.id}"]`);
await click(FILTER_APPLY_BUTTON('scope'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 2 });
assert.dom('tbody tr').exists({ count: 1 });
await click(commonSelectors.FILTER_DROPDOWN('scope'));
await click(
commonSelectors.FILTER_DROPDOWN_ITEM(instances.target.scope.id),
);
await click(commonSelectors.FILTER_DROPDOWN_ITEM_APPLY_BTN('scope'));
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 1 });
});
test('user can filter session recordings by time', async function (assert) {
await visit(urls.sessionRecordings);
await visit(urls.globalScope);
assert.dom('tbody tr').exists({ count: 2 });
await click(commonSelectors.HREF(urls.sessionRecordings));
await click(FILTER_TOGGLE_SELECTOR('time'));
await click(LAST_3_DAYS_OPTION);
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 2 });
assert.dom('tbody tr').exists({ count: 1 });
await click(commonSelectors.FILTER_DROPDOWN('time'));
await click(selectors.LAST_3_DAYS_OPTION);
assert.dom(commonSelectors.TABLE_ROW).isVisible({ count: 1 });
});
});
@@ -10,6 +10,8 @@ import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import a11yAudit from 'ember-a11y-testing/test-support/audit';
import { authenticateSession } from 'ember-simple-auth/test-support';
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import * as commonSelectors from 'admin/tests/helpers/selectors';
import * as selectors from './selectors';
module('Acceptance | session-recordings | read', function (hooks) {
setupApplicationTest(hooks);
@@ -18,12 +20,6 @@ module('Acceptance | session-recordings | read', function (hooks) {
let featuresService;
// Selectors
const LIST_SESSION_RECORDING_BUTTON =
'table > tbody > tr > td:last-child > a';
const LIST_CHANNEL_RECORDING_BUTTON =
'table > tbody > tr > td:last-child > a';
// Instances
const instances = {
scopes: {
@@ -81,23 +77,31 @@ module('Acceptance | session-recordings | read', function (hooks) {
const session = this.owner.lookup('service:session');
session.set('data.theme', 'light');
featuresService.enable('ssh-session-recording');
await visit(urls.globalScope);
// Visit session recordings
await visit(urls.sessionRecordings);
await click(commonSelectors.HREF(urls.sessionRecordings));
await a11yAudit();
// Click a session recording and check it navigates properly
await click(LIST_SESSION_RECORDING_BUTTON);
await click(selectors.TABLE_FIRST_ROW_ACTION_LINK);
await a11yAudit();
assert.strictEqual(currentURL(), urls.sessionRecording);
});
test('user can navigate to a session recording with proper authorization', async function (assert) {
featuresService.enable('ssh-session-recording');
await visit(urls.globalScope);
// Visit session recordings
await visit(urls.sessionRecordings);
await click(commonSelectors.HREF(urls.sessionRecordings));
assert.true(instances.sessionRecording.authorized_actions.includes('read'));
assert.dom(`[href="${urls.sessionRecording}"]`).exists();
assert.dom(commonSelectors.HREF(urls.sessionRecording)).isVisible();
// Click a session recording and check it navigates properly
await click(LIST_SESSION_RECORDING_BUTTON);
await click(selectors.TABLE_FIRST_ROW_ACTION_LINK);
assert.strictEqual(currentURL(), urls.sessionRecording);
});
@@ -107,22 +111,27 @@ module('Acceptance | session-recordings | read', function (hooks) {
instances.sessionRecording.authorized_actions.filter(
(item) => item !== 'read',
);
await visit(urls.globalScope);
// Visit session recordings
await visit(urls.sessionRecordings);
assert.dom(LIST_SESSION_RECORDING_BUTTON).doesNotExist();
await click(commonSelectors.HREF(urls.sessionRecordings));
assert.dom(selectors.TABLE_FIRST_ROW_ACTION_LINK).doesNotExist();
});
test('user can navigate to a channel recording', async function (assert) {
featuresService.enable('ssh-session-recording');
// Visit session recording
await visit(urls.sessionRecording);
assert.dom('table').hasClass('hds-table');
await visit(urls.sessionRecordings);
// Visit session recordings
await click(commonSelectors.HREF(urls.sessionRecording));
// Click a channel recording and check it navigates properly
await click(LIST_CHANNEL_RECORDING_BUTTON);
await click(selectors.TABLE_FIRST_ROW_ACTION_LINK);
assert.strictEqual(currentURL(), urls.channelRecording);
});
test('users can navigate to session recording and incorrect url autocorrects', async function (assert) {
test('users can navigate to session recording and incorrect url auto-corrects', async function (assert) {
featuresService.enable('ssh-session-recording');
const incorrectUrl = `/scopes/${instances.scopes.org.id}/session-recordings/${instances.sessionRecording.id}/channels-by-connection`;
@@ -0,0 +1,24 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const SESSION_RECORDING_TITLE = 'Session Recordings';
export const TABLE_FIRST_ROW_ACTION_LINK =
'tbody tr:first-child td:last-child a';
export const SESSION_RECORDING_PLAYER = '.session-recording-player';
export const SESSION_RECORDING_PLAYER_LINK =
'.session-recording-player-header > a';
export const RETAIN_UNTIL_OPTION = '[data-test-retain-until]';
export const DELETE_AFTER_OPTION = '[data-test-delete-after]';
// Search and filtering selectors
export const NO_RESULTS_MSG = '[data-test-no-session-recording-results]';
export const LAST_3_DAYS_OPTION =
'[data-test-session-recordings-bar] div[name="time"] li:nth-child(2) button';
// Manage actions dropdown selectors
export const MANAGE_DROPDOWN =
'[data-test-manage-channels-dropdown] button:first-child';
export const DELETE_ACTION =
'[data-test-manage-channels-dropdown] ul li:last-child button';
@@ -7,10 +7,12 @@ import { module, test } from 'qunit';
import { visit, currentURL, click } 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';
import { authenticateSession } from 'ember-simple-auth/test-support';
import { Response } from 'miragejs';
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
import * as commonSelectors from 'admin/tests/helpers/selectors';
import * as selectors from '../../selectors';
module(
'Acceptance | session-recordings | session-recording | channels-by-connection | channel',
@@ -22,9 +24,6 @@ module(
let featuresService;
let getRecordingCount;
const DELETE_DROPDOWN_SELECTOR = '[data-test-manage-dropdown-delete]';
const DROPDOWN_SELECTOR = '[data-test-manage-dropdown]';
// Instances
const instances = {
scopes: {
@@ -84,27 +83,34 @@ module(
});
test('user can navigate to a channel', async function (assert) {
await visit(urls.sessionRecording);
// Visit channel
await visit(urls.channelRecording);
await click(commonSelectors.HREF(urls.channelRecording));
await a11yAudit();
assert.strictEqual(currentURL(), urls.channelRecording);
});
test('user can view recording with proper authorization', async function (assert) {
await visit(urls.sessionRecording);
// Visit channel
await visit(urls.channelRecording);
await click(commonSelectors.HREF(urls.channelRecording));
// if authorized player will render
assert.dom('.session-recording-player').exists();
assert.dom(selectors.SESSION_RECORDING_PLAYER).isVisible();
});
test('user cannot view recording without proper authorization: channel mime_types', async function (assert) {
instances.channelRecording.mime_types = [];
await visit(urls.sessionRecording);
// Visit channel
await visit(urls.channelRecording);
await click(commonSelectors.HREF(urls.channelRecording));
// if unauthorized player will not render
assert.dom('.session-recording-player').doesNotExist();
assert.dom(selectors.SESSION_RECORDING_PLAYER).doesNotExist();
});
test('user cannot view recording without proper authorization: session recording download action', async function (assert) {
@@ -117,7 +123,7 @@ module(
await visit(urls.channelRecording);
// if unauthorized player will not render
assert.dom('.session-recording-player').doesNotExist();
assert.dom(selectors.SESSION_RECORDING_PLAYER).doesNotExist();
});
test('user cannot view recording if asciicast download errors out', async function (assert) {
@@ -134,23 +140,26 @@ module(
},
),
);
await visit(urls.sessionRecording);
// Visit channel
await visit(urls.channelRecording);
await click(commonSelectors.HREF(urls.channelRecording));
// if there was an error player will not render
assert.dom('.session-recording-player').doesNotExist();
assert.dom('.hds-application-state__title').hasText('Playback error');
assert.dom(selectors.SESSION_RECORDING_PLAYER).doesNotExist();
assert.dom(commonSelectors.PAGE_MESSAGE_HEADER).hasText('Playback error');
assert
.dom(commonSelectors.ALERT_TOAST_BODY)
.includesText('rpc error: code = Unknown');
});
test('user can navigate back to session recording screen', async function (assert) {
await visit(urls.sessionRecording);
// Visit channel
await visit(urls.channelRecording);
await click(commonSelectors.HREF(urls.channelRecording));
// click "Back to channels" link in player header
await click('.session-recording-player-header > a');
await click(selectors.SESSION_RECORDING_PLAYER_LINK);
assert.strictEqual(currentURL(), urls.sessionRecording);
});
@@ -198,16 +207,17 @@ module(
);
await visit(urls.sessionRecording);
assert.dom(DROPDOWN_SELECTOR).doesNotExist();
assert.dom(selectors.MANAGE_DROPDOWN).doesNotExist();
});
test('user can view manage dropdown with proper authorization', async function (assert) {
// Visit channel
featuresService.enable('ssh-session-recording');
await visit(urls.sessionRecordings);
await visit(urls.sessionRecording);
await click(commonSelectors.HREF(urls.sessionRecording));
assert.dom(DROPDOWN_SELECTOR).isVisible();
assert.dom(selectors.MANAGE_DROPDOWN).isVisible();
});
test('user can delete a recording with proper authorization', async function (assert) {
@@ -217,10 +227,12 @@ module(
assert.true(
instances.sessionRecording.authorized_actions.includes('delete'),
);
await visit(urls.sessionRecording);
await click(DROPDOWN_SELECTOR);
await visit(urls.sessionRecordings);
await click(DELETE_DROPDOWN_SELECTOR);
await click(commonSelectors.HREF(urls.sessionRecording));
await click(selectors.MANAGE_DROPDOWN);
await click(selectors.DELETE_ACTION);
assert.strictEqual(currentURL(), urls.sessionRecordings);
assert.strictEqual(getRecordingCount(), count - 1);
@@ -233,20 +245,23 @@ module(
instances.sessionRecording.authorized_actions.filter(
(item) => item !== 'delete',
);
await visit(urls.sessionRecording);
assert.dom(DELETE_DROPDOWN_SELECTOR).doesNotExist();
await visit(urls.sessionRecordings);
await click(commonSelectors.HREF(urls.sessionRecording));
assert.dom(selectors.DELETE_ACTION).doesNotExist();
});
test('both retain until and delete after can be seen with proper authorization', async function (assert) {
// Visit channel
featuresService.enable('ssh-session-recording');
await visit(urls.sessionRecordings);
await visit(urls.sessionRecording);
await click(commonSelectors.HREF(urls.sessionRecording));
assert.dom('.hds-dropdown-toggle-button__text').isVisible();
assert.dom('[data-test-retain-until]').isVisible();
assert.dom('[data-test-delete-after]').isVisible();
assert.dom(selectors.MANAGE_DROPDOWN).isVisible();
assert.dom(selectors.RETAIN_UNTIL_OPTION).isVisible();
assert.dom(selectors.DELETE_AFTER_OPTION).isVisible();
});
},
);