@@ -8,36 +8,10 @@ import { setupRenderingTest } from 'ember-qunit';
88import { render , fillIn , findAll , waitFor , click , find } from '@ember/test-helpers' ;
99import sinon from 'sinon' ;
1010import hbs from 'htmlbars-inline-precompile' ;
11- import Service from '@ember/service' ;
1211import { NAMESPACE_PICKER_SELECTORS } from 'vault/tests/helpers/namespace-picker' ;
1312import { GENERAL } from 'vault/tests/helpers/general-selectors' ;
1413import { setupMirage } from 'ember-cli-mirage/test-support' ;
15-
16- class StoreService extends Service {
17- findRecord ( modelType , id ) {
18- return new Promise ( ( resolve , reject ) => {
19- if ( modelType === 'capabilities' && id === 'sys/namespaces/' ) {
20- resolve ( ) ; // Simulate a successful response
21- } else {
22- reject ( { httpStatus : 404 , message : 'not found' } ) ; // Simulate an error response
23- }
24- } ) ;
25- }
26- }
27-
28- function getMockCapabilitiesModel ( canList ) {
29- // Mock for the Capabilities model
30- return {
31- path : 'sys/namespaces/' ,
32- capabilities : canList ? [ 'list' ] : [ ] ,
33- get ( property ) {
34- if ( property === 'canList' ) {
35- return this . capabilities . includes ( 'list' ) ;
36- }
37- return undefined ;
38- } ,
39- } ;
40- }
14+ import { capabilitiesStub , overrideResponse } from 'vault/tests/helpers/stubs' ;
4115
4216module ( 'Integration | Component | namespace-picker' , function ( hooks ) {
4317 setupRenderingTest ( hooks ) ;
@@ -52,12 +26,8 @@ module('Integration | Component | namespace-picker', function (hooks) {
5226 // the path in the namespace service denotes the current namespace context a user is in
5327 this . nsService . path = 'parent1/child1' ;
5428 this . server . get ( '/sys/internal/ui/namespaces' , ( ) => {
55- return {
56- data : { keys : [ 'parent1/' , 'parent1/child1/' ] } ,
57- } ;
29+ return { data : { keys : [ 'parent1/' , 'parent1/child1/' ] } } ;
5830 } ) ;
59-
60- this . owner . register ( 'service:store' , StoreService ) ;
6131 } ) ;
6232
6333 hooks . afterEach ( function ( ) {
@@ -77,6 +47,16 @@ module('Integration | Component | namespace-picker', function (hooks) {
7747 ) ;
7848 } ) ;
7949
50+ test ( 'it selects the current namespace' , async function ( assert ) {
51+ await render ( hbs `<NamespacePicker />` ) ;
52+ assert . dom ( GENERAL . toggleInput ( 'namespace-id' ) ) . hasText ( 'child1' , 'it just displays the namespace node' ) ;
53+ await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
54+ assert
55+ . dom ( NAMESPACE_PICKER_SELECTORS . link ( this . nsService . path ) )
56+ . hasAttribute ( 'aria-selected' , 'true' , 'the current namespace path is selected' ) ;
57+ assert . dom ( `${ NAMESPACE_PICKER_SELECTORS . link ( this . nsService . path ) } ${ GENERAL . icon ( 'check' ) } ` ) . exists ( ) ;
58+ } ) ;
59+
8060 test ( 'it filters namespace options based on search input' , async function ( assert ) {
8161 await render ( hbs `<NamespacePicker/>` ) ;
8262 await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
@@ -111,65 +91,43 @@ module('Integration | Component | namespace-picker', function (hooks) {
11191 ) ;
11292 } ) ;
11393
114- test ( 'it shows both action buttons when canList is true' , async function ( assert ) {
115- const storeStub = this . owner . lookup ( 'service:store' ) ;
116- sinon . stub ( storeStub , 'findRecord' ) . callsFake ( ( modelType , id ) => {
117- if ( modelType === 'capabilities' && id === 'sys/namespaces/' ) {
118- return Promise . resolve ( getMockCapabilitiesModel ( true ) ) ;
119- }
120- return Promise . reject ( ) ;
94+ module ( 'capabilities' , function ( hooks ) {
95+ hooks . beforeEach ( function ( ) {
96+ // the capabilities service prepends the user's root namespace to API paths when checking permissions.
97+ // For simplicity, test permissions from the "root" namespace context
98+ this . nsService . path = '' ;
12199 } ) ;
122100
123- await render ( hbs `<NamespacePicker />` ) ;
124- await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
101+ test ( 'it shows the "Manage" action when user has canList permissions' , async function ( assert ) {
102+ this . server . post ( '/sys/capabilities-self' , ( ) => capabilitiesStub ( 'sys/namespaces' , [ 'list' ] ) ) ;
125103
126- // Verify that the "Refresh List" button is visible
127- assert . dom ( NAMESPACE_PICKER_SELECTORS . refreshList ) . exists ( 'Refresh List button is visible' ) ;
128- assert . dom ( NAMESPACE_PICKER_SELECTORS . manageButton ) . exists ( 'Manage button is visible' ) ;
129- } ) ;
104+ await render ( hbs `<NamespacePicker />` ) ;
105+ await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
130106
131- test ( 'it hides the refresh button when canList is false' , async function ( assert ) {
132- const storeStub = this . owner . lookup ( 'service:store' ) ;
133- sinon . stub ( storeStub , 'findRecord' ) . callsFake ( ( modelType , id ) => {
134- if ( modelType === 'capabilities' && id === 'sys/namespaces/' ) {
135- return Promise . resolve ( getMockCapabilitiesModel ( false ) ) ;
136- }
137- return Promise . reject ( ) ;
107+ assert . dom ( NAMESPACE_PICKER_SELECTORS . manageButton ) . exists ( 'Manage button is visible' ) ;
138108 } ) ;
139109
140- await render ( hbs `<NamespacePicker />` ) ;
141- await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
110+ test ( 'it hides the "Manage" button when canList is false' , async function ( assert ) {
111+ this . server . post ( '/sys/capabilities-self' , capabilitiesStub ( `sys/namespaces` , [ 'deny' ] ) ) ;
112+ await render ( hbs `<NamespacePicker />` ) ;
113+ await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
142114
143- // Verify that the buttons are hidden
144- assert . dom ( NAMESPACE_PICKER_SELECTORS . refreshList ) . doesNotExist ( 'Refresh List button is hidden' ) ;
145- assert . dom ( NAMESPACE_PICKER_SELECTORS . manageButton ) . exists ( 'Manage button is hidden' ) ;
146- } ) ;
147-
148- test ( 'it hides both action buttons when the capabilities store throws an error' , async function ( assert ) {
149- const storeStub = this . owner . lookup ( 'service:store' ) ;
150- sinon . stub ( storeStub , 'findRecord' ) . callsFake ( ( ) => {
151- return Promise . reject ( ) ;
115+ // Verify that the buttons are hidden
116+ assert . dom ( NAMESPACE_PICKER_SELECTORS . manageButton ) . doesNotExist ( 'Manage button is hidden' ) ;
152117 } ) ;
153118
154- await render ( hbs `<NamespacePicker />` ) ;
155- await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
119+ test ( 'it shows "Manage" button when the capabilities request throws an error' , async function ( assert ) {
120+ // It's rare for the capabilities request to fail (if it does, it's usually because the request is made in the wrong namespace context).
121+ // If it fails, the UI should show resources and rely on the API to gate them appropriately.
122+ this . server . post ( '/sys/capabilities-self' , ( ) => overrideResponse ( 403 ) ) ;
156123
157- // Verify that the buttons are hidden
158- assert . dom ( NAMESPACE_PICKER_SELECTORS . refreshList ) . doesNotExist ( 'Refresh List button is hidden' ) ;
159- assert . dom ( NAMESPACE_PICKER_SELECTORS . manageButton ) . doesNotExist ( 'Manage button is hidden' ) ;
124+ await render ( hbs `<NamespacePicker />` ) ;
125+ await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
126+ assert . dom ( NAMESPACE_PICKER_SELECTORS . manageButton ) . exists ( ) ;
127+ } ) ;
160128 } ) ;
161129
162130 test ( 'it updates the namespace list after clicking "Refresh list"' , async function ( assert ) {
163- this . owner . lookup ( 'service:namespace' ) . set ( 'hasListPermissions' , true ) ;
164-
165- const storeStub = this . owner . lookup ( 'service:store' ) ;
166- sinon . stub ( storeStub , 'findRecord' ) . callsFake ( ( modelType , id ) => {
167- if ( modelType === 'capabilities' && id === 'sys/namespaces/' ) {
168- return Promise . resolve ( getMockCapabilitiesModel ( true ) ) ; // Return the mock model
169- }
170- return Promise . reject ( ) ;
171- } ) ;
172-
173131 await render ( hbs `<NamespacePicker />` ) ;
174132 await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
175133
@@ -180,7 +138,7 @@ module('Integration | Component | namespace-picker', function (hooks) {
180138 'Initially, three namespaces are displayed'
181139 ) ;
182140
183- // Re-stub request with a new namespace
141+ // Re-stub request from beforeEach hook with a new namespace
184142 this . server . get ( '/sys/internal/ui/namespaces' , ( ) => {
185143 return {
186144 data : { keys : [ 'parent1/' , 'parent1/child1/' , 'new-namespace/' ] } ,
@@ -221,4 +179,19 @@ module('Integration | Component | namespace-picker', function (hooks) {
221179 assert . dom ( NAMESPACE_PICKER_SELECTORS . link ( 'admin' ) ) . exists ( ) ;
222180 assert . dom ( NAMESPACE_PICKER_SELECTORS . link ( 'admin/child1' ) ) . exists ( ) ;
223181 } ) ;
182+
183+ test ( 'it selects the correct namespace when matching nodes exist' , async function ( assert ) {
184+ // stub response so that two namespaces have matching node names 'child1'
185+ this . server . get ( '/sys/internal/ui/namespaces' , ( ) => {
186+ return { data : { keys : [ 'parent1/' , 'parent1/child1' , 'anotherParent/' , 'anotherParent/child1' ] } } ;
187+ } ) ;
188+ await render ( hbs `<NamespacePicker />` ) ;
189+ assert . dom ( GENERAL . toggleInput ( 'namespace-id' ) ) . hasText ( 'child1' , 'it displays the namespace node' ) ;
190+ await click ( GENERAL . toggleInput ( 'namespace-id' ) ) ;
191+ assert
192+ . dom ( NAMESPACE_PICKER_SELECTORS . link ( this . nsService . path ) )
193+ . hasAttribute ( 'aria-selected' , 'true' , 'the current namespace path is selected' ) ;
194+ assert . dom ( '[aria-selected="true"]' ) . exists ( { count : 1 } , 'only one option is selected' ) ;
195+ assert . dom ( GENERAL . icon ( 'check' ) ) . exists ( { count : 1 } , 'only one check mark renders' ) ;
196+ } ) ;
224197} ) ;
0 commit comments