Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test reorg: Clients, Mirage, General selectors #26260

Merged
merged 33 commits into from
Apr 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
131e1b0
Add readme
hashishaw Apr 2, 2024
fdba7e6
Rename general selectors export
hashishaw Apr 2, 2024
2e68dd4
reorg clients helper -- all clients tests pass
hashishaw Apr 2, 2024
dcf40c3
Update custom messages & dashboard selectors
hashishaw Apr 2, 2024
d8ce0f9
Rename client count selector export
hashishaw Apr 2, 2024
c92e61f
clean up .CodeMirror selectors to use helper instead
hashishaw Apr 2, 2024
2cc755d
move secret-edit-toolbar helper
hashishaw Apr 2, 2024
0e0e40c
remove helper used only once
hashishaw Apr 2, 2024
8dfbe45
replace noop-all-api-requests with mirage
hashishaw Apr 2, 2024
4607bd1
move policy generators into their respective folders
hashishaw Apr 2, 2024
4148300
Move LDAP helpers
hashishaw Apr 2, 2024
5568ce0
Move overrideResponse to stubs helper, rename clients helper
hashishaw Apr 2, 2024
0242c4b
replace oidc-specific mirage & capabilities overrides
hashishaw Apr 3, 2024
fc06682
add secretTab and checkboxByAttr to general selectors
hashishaw Apr 3, 2024
fe7317d
general-selectors are TS
hashishaw Apr 4, 2024
cd3c028
fix merge conflict import
hashishaw Apr 4, 2024
b5392d4
Bump message wait time for oidc auth method test
hashishaw Apr 4, 2024
cf1b31b
Refactor auth methods mgmt test so we don't run into a timeout
hashishaw Apr 4, 2024
3c4e0e4
Update comment
hashishaw Apr 4, 2024
6a162ec
revert acceptance tests only
hashishaw Apr 4, 2024
e831a39
don't allow mutability of array returned by supportedAuthBackends
hashishaw Apr 4, 2024
60fad68
unrevert -- remove noop-all-api-requests
hashishaw Apr 4, 2024
fea667e
remove hardcoded ?with param
hashishaw Apr 4, 2024
9483c46
Merge branch 'ui/test-reorg-base' into ui/hackweek-test-reorg
hashishaw Apr 5, 2024
007d766
Update ui/tests/_README.md
hashishaw Apr 10, 2024
867946e
Update ui/tests/acceptance/auth-list-test.js
hashishaw Apr 10, 2024
9c061fa
Update ui/tests/acceptance/auth-test.js
hashishaw Apr 10, 2024
cf6349a
Update ui/tests/acceptance/settings/auth/configure/section-test.js
hashishaw Apr 10, 2024
4839315
Update ui/tests/unit/adapters/identity/entity-test.js
hashishaw Apr 10, 2024
a8a538b
Update ui/tests/unit/adapters/identity/entity-alias-test.js
hashishaw Apr 10, 2024
1bc3047
replace CLIENT_COUNT as ts in tests
hashishaw Apr 10, 2024
b10ed46
update assertions
hashishaw Apr 10, 2024
48aec94
move readme to docs
hashishaw Apr 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ui/app/helpers/supported-auth-backends.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ const ENTERPRISE_AUTH_METHODS = [
];

export function supportedAuthBackends() {
return SUPPORTED_AUTH_BACKENDS;
return [...SUPPORTED_AUTH_BACKENDS];
}

export function allSupportedAuthBackends() {
Expand Down
2 changes: 1 addition & 1 deletion ui/app/serializers/clients/activity.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { formatISO } from 'date-fns';
import { formatByMonths, formatByNamespace, destructureClientCounts } from 'core/utils/client-count-utils';
import timestamp from 'core/utils/timestamp';

// see tests/helpers/clients for sample API response (ACTIVITY_RESPONSE_STUB)
// see tests/helpers/clients/client-count-helpers for sample API response (ACTIVITY_RESPONSE_STUB)
// and transformed by_namespace and by_month examples (SERIALIZED_ACTIVITY_RESPONSE)
export default class ActivitySerializer extends ApplicationSerializer {
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
Expand Down
35 changes: 35 additions & 0 deletions ui/docs/tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Test Helpers Organization

Our test are constantly evolving, but here's a general overview of how we set up and organize tests.

## Folder organization

### /acceptance

Acceptance tests should test the overall workflows and navigation within Vault. When possible, they should use the real API instead of mocked so that breaking changes from the backend can be caught. Reasons you may opt to use a mocked backend instead of the real one:

- Using the real backend would cause instability in concurrently-running tests (eg. seal/unseal flow)
- There isn't a way to set up a 3rd party dependency that the backend needs to run correctly (Database Secrets Engine, Sync Secrets)

### /helpers

Shared helpers such as selectors, common interactions, WebREPL commands, and API response stubs live in this folder. When selectors are only used for a single test, they should be defined on the same file where they are used for the test. Once the selectors are being used for multiple tests, they should be moved to this folder so they can be defined in a single place and shared to wherever they are needed.

Often we will need a set of selectors for "workflow" tests, or acceptance tests that navigate through an area of the app. For these, the helpers should be organized as such:

- `/helpers/<area>/<area>-selectors.ts` - exports selector consts (never default) for each page -- eg. for PKI we would have PKI_OVERVIEW, PKI_ROLE, etc.
- `/helpers/<area>/<area>-interactions.js` - exports methods and consts which are otherwise helpful in the tests -- eg. example API responses, common interactions (eg. writeVersionedSecret for KV v2)

Whenever possible we should try to use the general selectors exported from `/helpers/general-selectors.ts`.

### integration

Integration tests are most often used to test specific components out of context from the rest of the app. Be sure to mock anything that the component needs to work correctly -- for example, if the component has a certain behavior in enterprise than community edition, in your tests for each scenario it should not assume that the underlying Vault binary is in one state or the other, and mock the enterprise/community state in all the scenarios. The exports in `helpers/stubs.js` might be helpful for these tests, particularly when the component uses a model which fetches capabilities.

### pages

[DEPRECATED] This file should be removed in favor of selectors within the "helpers" folder. We are moving away from ember-page-object selectors toward simple strings

### unit

Unit tests are most often used to test utils, adapters, serializers, routes, and services functionality.
2 changes: 1 addition & 1 deletion ui/tests/acceptance/access/identity/entities/index-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { setupApplicationTest } from 'ember-qunit';
import page from 'vault/tests/pages/access/identity/index';
import authPage from 'vault/tests/pages/auth';
import { runCmd } from 'vault/tests/helpers/commands';
import { SELECTORS as GENERAL } from 'vault/tests/helpers/general-selectors';
import { GENERAL } from 'vault/tests/helpers/general-selectors';
import { v4 as uuidv4 } from 'uuid';

const SELECTORS = {
Expand Down
180 changes: 83 additions & 97 deletions ui/tests/acceptance/auth-list-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,109 +73,95 @@ module('Acceptance | auth backend list', function (hooks) {
assert.dom(SELECTORS.listItem).hasText(this.user1, 'user1 exists in the list');
});

test('auth methods are linkable and link to correct view', async function (assert) {
assert.expect(45);
const uid = uuidv4();
await visit('/vault/access');
module('auth methods are linkable and link to correct view', function (hooks) {
hooks.beforeEach(async function () {
this.uid = uuidv4();
await visit('/vault/access');
});

const supportManaged = supportedManagedAuthBackends();
// Test all auth methods, not just those you can log in with
const backends = methods().map((backend) => backend.type);
assert.deepEqual(
backends,
[
'alicloud',
'approle',
'aws',
'azure',
'gcp',
'github',
'jwt',
'oidc',
'kubernetes',
'ldap',
'okta',
'radius',
'cert',
'userpass',
],
'non-enterprise auth methods are available'
);
for (const type of backends) {
const path = type === 'token' ? 'token' : `auth-list-${type}-${uid}`;
if (type !== 'token') {
await enablePage.enable(type, path);
}
await settled();
methods()
.map((backend) => backend.type)
.forEach((type) => {
test(`${type} auth method`, async function (assert) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice improvement adding the loop here!

const supportManaged = supportedManagedAuthBackends();
const path = type === 'token' ? 'token' : `auth-list-${type}-${this.uid}`;
if (type !== 'token') {
await enablePage.enable(type, path);
}
await settled();
await visit('/vault/access');

// check popup menu
const itemCount = type === 'token' ? 2 : 3;
await click(`[data-test-auth-backend-link="${path}"] [data-test-popup-menu-trigger]`);
assert
.dom('.hds-dropdown-list-item')
.exists({ count: itemCount }, `shows ${itemCount} dropdown items for ${type}`);

// all auth methods should be linkable
await click(`[data-test-auth-backend-link="${path}"]`);
if (!supportManaged.includes(type)) {
assert.dom('[data-test-auth-section-tab]').exists({ count: 1 });
assert
.dom('[data-test-auth-section-tab]')
.hasText('Configuration', `only shows configuration tab for ${type} auth method`);
assert.dom('[data-test-doc-link] .doc-link').exists(`includes doc link for ${type} auth method`);
} else {
let expectedTabs = 2;
if (type === 'ldap' || type === 'okta') {
expectedTabs = 3;
}
assert
.dom('[data-test-auth-section-tab]')
.exists({ count: expectedTabs }, `has management tabs for ${type} auth method`);
}
if (type !== 'token') {
// cleanup method
await runCmd(deleteAuthCmd(path));
}
});
});
});

module('enterprise', function () {
test('ent-only auth methods are linkable and link to correct view', async function (assert) {
assert.expect(3);
const uid = uuidv4();
await visit('/vault/access');

// check popup menu
const itemCount = type === 'token' ? 2 : 3;
await click(`[data-test-auth-backend-link="${path}"] [data-test-popup-menu-trigger]`);
assert
.dom('.hds-dropdown-list-item')
.exists({ count: itemCount }, `shows ${itemCount} dropdown items for ${type}`);
// Only SAML is enterprise-only for now
const type = 'saml';
const path = `auth-list-${type}-${uid}`;
await enablePage.enable(type, path);
await settled();
await visit('/vault/access');

// all auth methods should be linkable
await click(`[data-test-auth-backend-link="${path}"]`);
if (!supportManaged.includes(type)) {
assert.dom('[data-test-auth-section-tab]').exists({ count: 1 });
assert
.dom('[data-test-auth-section-tab]')
.hasText('Configuration', `only shows configuration tab for ${type} auth method`);
assert.dom('[data-test-doc-link] .doc-link').exists(`includes doc link for ${type} auth method`);
} else {
let expectedTabs = 2;
if (type == 'ldap' || type === 'okta') {
expectedTabs = 3;
}
assert
.dom('[data-test-auth-section-tab]')
.exists({ count: expectedTabs }, `has management tabs for ${type} auth method`);
}
if (type !== 'token') {
// cleanup method
await runCmd(deleteAuthCmd(path));
}
}
});

test('enterprise: auth methods are linkable and link to correct view', async function (assert) {
assert.expect(3);
const uid = uuidv4();
await visit('/vault/access');

// Only SAML is enterprise-only for now
const type = 'saml';
const path = `auth-list-${type}-${uid}`;
await enablePage.enable(type, path);
await settled();
await visit('/vault/access');

// all auth methods should be linkable
await click(`[data-test-auth-backend-link="${path}"]`);
assert.dom('[data-test-auth-section-tab]').exists({ count: 1 });
assert
.dom('[data-test-auth-section-tab]')
.hasText('Configuration', `only shows configuration tab for ${type} auth method`);
assert.dom('[data-test-doc-link] .doc-link').exists(`includes doc link for ${type} auth method`);
await runCmd(deleteAuthCmd(path));
});

test('enterprise: token config within namespace', async function (assert) {
const ns = 'ns-wxyz';
await runCmd(createNS(ns), false);
await settled();
await authPage.loginNs(ns);
// go directly to token configure route
await visit('/vault/settings/auth/configure/token/options');
await fillIn('[data-test-input="description"]', 'My custom description');
await click('[data-test-save-config="true"]');
assert.strictEqual(currentURL(), '/vault/access', 'successfully saves and navigates away');
await click('[data-test-auth-backend-link="token"]');
assert
.dom('[data-test-row-value="Description"]')
.hasText('My custom description', 'description was saved');
await runCmd(`delete sys/namespaces/${ns}`);
assert.dom('[data-test-auth-section-tab]').exists({ count: 1 });
assert
.dom('[data-test-auth-section-tab]')
.hasText('Configuration', `only shows configuration tab for ${type} auth method`);
assert.dom('[data-test-doc-link] .doc-link').exists(`includes doc link for ${type} auth method`);
await runCmd(deleteAuthCmd(path));
});

test('token config within namespace', async function (assert) {
const ns = 'ns-wxyz';
await runCmd(createNS(ns), false);
await settled();
await authPage.loginNs(ns);
// go directly to token configure route
await visit('/vault/settings/auth/configure/token/options');
await fillIn('[data-test-input="description"]', 'My custom description');
await click('[data-test-save-config="true"]');
assert.strictEqual(currentURL(), '/vault/access', 'successfully saves and navigates away');
await click('[data-test-auth-backend-link="token"]');
assert
.dom('[data-test-row-value="Description"]')
.hasText('My custom description', 'description was saved');
await runCmd(`delete sys/namespaces/${ns}`);
});
});
});
Loading
Loading