Files
vault/ui/tests/helpers/kv/kv-selectors.js
claire bontempo f634808ed4 UI: Implement KV patch+subkey [enterprise] (#28212)
* UI: Implement overview page for KV v2 (#28162)

* build json editor patch form

* finish patch component and tests

* add tab to each route

* and path route

* add overview tab to tests

* update overview to use updated_time instead of created_time

* redirect relevant secret.details to secret.index

* compute secretState in component instead of pass as arg

* add capabilities service

* add error handling to fetchSubkeys adapter request

* add overview tabs to test

* add subtext to overview card

* remaining redirects in secret edit

* remove create new version from popup menu

* fix breadcrumbs for overview

* separate adding capabilities service

* add service to kv engine

* Revert "separate adding capabilities service"

This reverts commit bb70b12ab7dbcde0fbd2d4d81768e5c8b1c420cc.

* Revert "add service to kv engine"

This reverts commit bfa880535ef7d529d7610936b2c1aae55673d23f.

* update navigation test

* consistently navigate to secret.index route to be explicit

* finish overview navigation tests

* add copyright header

* update delete tests

* fix nav testrs

* cleanup secret edit redirects

* remove redundant async/awaits

* fix create test

* edge case tests

* secret acceptance tests

* final component tests

* rename kvSecretDetails external route to kvSecretOverview

* add comment

* UI: Add patch route and implement Page::Secret::Patch page component (sidebranch) (#28192)

* add tab to each route

* and path route

* add overview tab to tests

* update overview to use updated_time instead of created_time

* redirect relevant secret.details to secret.index

* compute secretState in component instead of pass as arg

* add capabilities service

* add error handling to fetchSubkeys adapter request

* add patch route and put in page component

* add patch secret action to subkeys card

* fix component name

* add patch capability

* alphabetize computed capabilities

* update links, cleanup selectors

* fix more merge conflict stuff

* add capabilities test

* add models to patch link

* add test for patch route

* rename external route

* add error templates

* make notes about enterprise tests, filter one

* remove errors, transition (redirect) instead

* redirect patch routes

* UI: Move fetching secret data to child route (#28198)

* remove @secret from metadata details

* use metadata model instead of secret in paths page

* put delete back into kv/data adapter

* grant access in control group test

* update metadata route and permissions

* remove secret from parent route, only fetch in details route

* change more permissions to route perms, add tests

* revert overview redirect from list view

* wrap model in conditional for perms

* remove redundant canReadCustomMetadata check

* rename adapter method

* handle overview 404

* remove comment

* add customMetadata as an arg

* update grantAccess in test

* make version param easier to follow

* VAULT-30494 handle 404 jira

* refactor capabilities to return an object

* update create tests

* add test for default truthy capabilities

* remove destroy-all-versions from kv/data adapter

* UI: Add enterprise checks (#28215)

* add enterprise check for subkey card

* add max height and scroll to subkey card

* only fetch subkeys if enterprise

* remove check in overview

* add test

* Update ui/tests/integration/components/kv/page/kv-page-overview-test.js

* fix test failures (#28222)

* add assertion

* add optional chaining

* create/delete versioned secret in each module

* wait for transition

* add another waitUntil

* UI: Add patch latest version to toolbar (#28223)

* add patch latest version action to toolbar

* make isPatchAllowed arg all encompassing

* no longer need model check

* use hash so both promises fire at the same time

* add subkeys to policy

* Update ui/lib/kv/addon/routes/secret.js

* add changelog

* small cleanup items! (#28229)

* add conditional for enterprise checking tabs

* cleanup fetchMultiplePaths method

* add test

* remove todo comment, ticket created and design wants to hold off

* keep transition, update comments

* cleanup tests, add index to breadcrumbs

* add some test coverage

* toggle so value is readable
2024-08-29 16:38:39 -07:00

141 lines
6.2 KiB
JavaScript

/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
export const PAGE = {
// General selectors that are common between pages
title: '[data-test-header-title]',
breadcrumbs: '[data-test-breadcrumbs]',
breadcrumb: '[data-test-breadcrumbs] li',
breadcrumbAtIdx: (idx) => `[data-test-breadcrumbs] li:nth-child(${idx + 1}) a`,
infoRow: '[data-test-component="info-table-row"]',
infoRowValue: (label) => `[data-test-value-div="${label}"]`,
infoRowToggleMasked: (label) => `[data-test-value-div="${label}"] [data-test-button="toggle-masked"]`,
secretTab: (tab) => (tab ? `[data-test-secrets-tab="${tab}"]` : '[data-test-secrets-tab]'),
emptyStateTitle: '[data-test-empty-state-title]',
emptyStateMessage: '[data-test-empty-state-message]',
emptyStateActions: '[data-test-empty-state-actions]',
popup: '[data-test-popup-menu-trigger]',
error: {
title: '[data-test-page-error] h1',
message: '[data-test-page-error] p',
},
toolbar: 'nav.toolbar',
toolbarAction: 'nav.toolbar-actions .toolbar-link, nav.toolbar-actions .toolbar-button',
secretRow: '[data-test-component="info-table-row"]', // replace with infoRow
// specific page selectors
backends: {
link: (backend) => `[data-test-secrets-backend-link="${backend}"]`,
},
metadata: {
editBtn: '[data-test-edit-metadata]',
addCustomMetadataBtn: '[data-test-add-custom-metadata]',
customMetadataSection: '[data-test-kv-custom-metadata-section]',
secretMetadataSection: '[data-test-kv-metadata-section]',
deleteMetadata: '[data-test-kv-delete="delete-metadata"]',
},
detail: {
versionTimestamp: '[data-test-kv-version-tooltip-trigger]',
versionDropdown: '[data-test-version-dropdown]',
version: (number) => `[data-test-version="${number}"]`,
createNewVersion: '[data-test-create-new-version]',
patchLatest: '[data-test-patch-latest-version]',
delete: '[data-test-kv-delete="delete"]',
destroy: '[data-test-kv-delete="destroy"]',
undelete: '[data-test-kv-delete="undelete"]',
copy: '[data-test-copy-menu-trigger]',
wrap: '[data-test-wrap-button]',
deleteModal: '[data-test-delete-modal]',
deleteModalTitle: '[data-test-delete-modal] [data-test-modal-title]',
deleteOption: 'input#delete-version',
deleteOptionLatest: 'input#delete-latest-version',
deleteConfirm: '[data-test-delete-modal-confirm]',
syncAlert: (name) => (name ? `[data-test-sync-alert="${name}"]` : '[data-test-sync-alert]'),
},
edit: {
toggleDiff: '[data-test-toggle-input="Show diff"',
toggleDiffDescription: '[data-test-diff-description]',
},
list: {
createSecret: '[data-test-toolbar-create-secret]',
item: (secret) => (!secret ? '[data-test-list-item]' : `[data-test-list-item="${secret}"]`),
filter: `[data-test-kv-list-filter]`,
listMenuDelete: `[data-test-popup-metadata-delete]`,
overviewCard: '[data-test-overview-card-container="View secret"]',
overviewInput: '[data-test-view-secret] input',
overviewButton: '[data-test-submit-button]',
pagination: '[data-test-pagination]',
paginationInfo: '.hds-pagination-info',
paginationNext: '.hds-pagination-nav__arrow--direction-next',
paginationSelected: '.hds-pagination-nav__number--is-selected',
},
versions: {
icon: (version) => `[data-test-icon-holder="${version}"]`,
linkedBlock: (version) =>
version ? `[data-test-version-linked-block="${version}"]` : '[data-test-version-linked-block]',
versionMenu: (version) => `[data-test-version-linked-block="${version}"] [data-test-popup-menu-trigger]`,
createFromVersion: (version) => `[data-test-create-new-version-from="${version}"]`,
},
diff: {
visualDiff: '[data-test-visual-diff]',
added: `.jsondiffpatch-added`,
deleted: `.jsondiffpatch-deleted`,
},
create: {
metadataSection: '[data-test-metadata-section]',
},
paths: {
copyButton: (label) => `${PAGE.infoRowValue(label)} button`,
codeSnippet: (section) => `[data-test-commands="${section}"] code`,
snippetCopy: (section) => `[data-test-commands="${section}"] button`,
},
};
// Form/Interactive selectors that are common between pages and forms
export const FORM = {
inputByAttr: (attr) => `[data-test-input="${attr}"]`,
fieldByAttr: (attr) => `[data=test=field="${attr}"]`, // formfield
toggleJson: '[data-test-toggle-input="json"]',
toggleJsonValues: '[data-test-toggle-input="revealValues"]',
toggleMasked: '[data-test-button="toggle-masked"]',
toggleMetadata: '[data-test-metadata-toggle]',
jsonEditor: '[data-test-component="code-mirror-modifier"]',
ttlValue: (name) => `[data-test-ttl-value="${name}"]`,
toggleByLabel: (label) => `[data-test-ttl-toggle="${label}"]`,
dataInputLabel: ({ isJson = false }) =>
isJson ? '[data-test-component="json-editor-title"]' : '[data-test-kv-label]',
// <KvObjectEditor>
kvLabel: '[data-test-kv-label]',
kvRow: '[data-test-kv-row]',
keyInput: (idx = 0) => `[data-test-kv-key="${idx}"]`,
valueInput: (idx = 0) => `[data-test-kv-value="${idx}"]`,
maskedValueInput: (idx = 0) => `[data-test-kv-value="${idx}"] [data-test-textarea]`,
addRow: (idx = 0) => `[data-test-kv-add-row="${idx}"]`,
deleteRow: (idx = 0) => `[data-test-kv-delete-row="${idx}"]`,
// <KvPatchEditor>
patchEditorForm: '[data-test-kv-patch-editor]',
patchEdit: (idx = 0) => `[data-test-edit-button="${idx}"]`,
patchDelete: (idx = 0) => `[data-test-delete-button="${idx}"]`,
patchUndo: (idx = 0) => `[data-test-undo-button="${idx}"]`,
patchAdd: '[data-test-add-button]',
patchAlert: (type, idx) => `[data-test-alert-${type}="${idx}"]`,
// Alerts & validation
inlineAlert: '[data-test-inline-alert]',
validation: (attr) => `[data-test-field="${attr}"] [data-test-inline-alert]`,
messageError: '[data-test-message-error]',
validationWarning: '[data-test-validation-warning]',
invalidFormAlert: '[data-test-invalid-form-alert]',
versionAlert: '[data-test-secret-version-alert]',
noReadAlert: '[data-test-secret-no-read-alert]',
// Form btns
saveBtn: '[data-test-kv-save]',
cancelBtn: '[data-test-kv-cancel]',
};
export const parseJsonEditor = (find) => {
return JSON.parse(find(FORM.jsonEditor).innerText);
};
export const parseObject = (cm) => JSON.parse(cm().getValue());