diff --git a/awx/ui_next/src/api/models/CredentialTypes.js b/awx/ui_next/src/api/models/CredentialTypes.js index 65906cdcbd..d2d993091c 100644 --- a/awx/ui_next/src/api/models/CredentialTypes.js +++ b/awx/ui_next/src/api/models/CredentialTypes.js @@ -5,6 +5,28 @@ class CredentialTypes extends Base { super(http); this.baseUrl = '/api/v2/credential_types/'; } + + async loadAllTypes( + acceptableKinds = ['machine', 'cloud', 'net', 'ssh', 'vault'] + ) { + const pageSize = 200; + // The number of credential types a user can have is unlimited. In practice, it is unlikely for + // users to have more than a page at the maximum request size. + const { + data: { next, results }, + } = await this.read({ page_size: pageSize }); + let nextResults = []; + if (next) { + const { data } = await this.read({ + page_size: pageSize, + page: 2, + }); + nextResults = data.results; + } + return results + .concat(nextResults) + .filter(type => acceptableKinds.includes(type.kind)); + } } export default CredentialTypes; diff --git a/awx/ui_next/src/api/models/CredentialTypes.test.js b/awx/ui_next/src/api/models/CredentialTypes.test.js new file mode 100644 index 0000000000..5cb038912e --- /dev/null +++ b/awx/ui_next/src/api/models/CredentialTypes.test.js @@ -0,0 +1,65 @@ +import CredentialTypes from './CredentialTypes'; + +const typesData = [{ id: 1, kind: 'machine' }, { id: 2, kind: 'cloud' }]; + +describe('CredentialTypesAPI', () => { + test('should load all types', async () => { + const getPromise = () => + Promise.resolve({ + data: { + results: typesData, + }, + }); + const mockHttp = { get: jest.fn(getPromise) }; + const CredentialTypesAPI = new CredentialTypes(mockHttp); + + const types = await CredentialTypesAPI.loadAllTypes(); + + expect(mockHttp.get).toHaveBeenCalledTimes(1); + expect(mockHttp.get.mock.calls[0]).toEqual([ + `/api/v2/credential_types/`, + { params: { page_size: 200 } }, + ]); + expect(types).toEqual(typesData); + }); + + test('should load all types (2 pages)', async () => { + const getPromise = () => + Promise.resolve({ + data: { + results: typesData, + next: 2, + }, + }); + const mockHttp = { get: jest.fn(getPromise) }; + const CredentialTypesAPI = new CredentialTypes(mockHttp); + + const types = await CredentialTypesAPI.loadAllTypes(); + + expect(mockHttp.get).toHaveBeenCalledTimes(2); + expect(mockHttp.get.mock.calls[0]).toEqual([ + `/api/v2/credential_types/`, + { params: { page_size: 200 } }, + ]); + expect(mockHttp.get.mock.calls[1]).toEqual([ + `/api/v2/credential_types/`, + { params: { page_size: 200, page: 2 } }, + ]); + expect(types).toHaveLength(4); + }); + + test('should filter by acceptable kinds', async () => { + const getPromise = () => + Promise.resolve({ + data: { + results: typesData, + }, + }); + const mockHttp = { get: jest.fn(getPromise) }; + const CredentialTypesAPI = new CredentialTypes(mockHttp); + + const types = await CredentialTypesAPI.loadAllTypes(['machine']); + + expect(types).toEqual([typesData[0]]); + }); +}); diff --git a/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.jsx b/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.jsx index 58bdf359cb..c153b1d610 100644 --- a/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.jsx +++ b/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.jsx @@ -17,27 +17,6 @@ const QS_CONFIG = getQSConfig('credentials', { order_by: 'name', }); -async function loadCredentialTypes() { - const pageSize = 200; - const acceptableKinds = ['machine', 'cloud', 'net', 'ssh', 'vault']; - // The number of credential types a user can have is unlimited. In practice, it is unlikely for - // users to have more than a page at the maximum request size. - const { - data: { next, results }, - } = await CredentialTypesAPI.read({ page_size: pageSize }); - let nextResults = []; - if (next) { - const { data } = await CredentialTypesAPI.read({ - page_size: pageSize, - page: 2, - }); - nextResults = data.results; - } - return results - .concat(nextResults) - .filter(type => acceptableKinds.includes(type.kind)); -} - async function loadCredentials(params, selectedCredentialTypeId) { params.credential_type = selectedCredentialTypeId || 1; const { data } = await CredentialsAPI.read(params); @@ -54,7 +33,7 @@ function MultiCredentialsLookup(props) { useEffect(() => { (async () => { try { - const types = await loadCredentialTypes(); + const types = await CredentialTypesAPI.loadAllTypes(); setCredentialTypes(types); const match = types.find(type => type.kind === 'ssh') || types[0]; setSelectedType(match); diff --git a/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.test.jsx b/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.test.jsx index fa8eb5a15f..08fcf87b18 100644 --- a/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.test.jsx +++ b/awx/ui_next/src/components/Lookup/MultiCredentialsLookup.test.jsx @@ -18,21 +18,16 @@ describe('', () => { ]; beforeEach(() => { - CredentialTypesAPI.read.mockResolvedValueOnce({ - data: { - results: [ - { - id: 400, - kind: 'ssh', - namespace: 'biz', - name: 'Amazon Web Services', - }, - { id: 500, kind: 'vault', namespace: 'buzz', name: 'Vault' }, - { id: 600, kind: 'machine', namespace: 'fuzz', name: 'Machine' }, - ], - count: 2, + CredentialTypesAPI.loadAllTypes.mockResolvedValueOnce([ + { + id: 400, + kind: 'ssh', + namespace: 'biz', + name: 'Amazon Web Services', }, - }); + { id: 500, kind: 'vault', namespace: 'buzz', name: 'Vault' }, + { id: 600, kind: 'machine', namespace: 'fuzz', name: 'Machine' }, + ]); CredentialsAPI.read.mockResolvedValueOnce({ data: { results: [ @@ -52,7 +47,7 @@ describe('', () => { wrapper.unmount(); }); - test('MultiCredentialsLookup renders properly', async () => { + test('should load credential types', async () => { const onChange = jest.fn(); await act(async () => { wrapper = mountWithContexts( @@ -64,8 +59,9 @@ describe('', () => { /> ); }); + wrapper.update(); expect(wrapper.find('MultiCredentialsLookup')).toHaveLength(1); - expect(CredentialTypesAPI.read).toHaveBeenCalled(); + expect(CredentialTypesAPI.loadAllTypes).toHaveBeenCalled(); }); test('onChange is called when you click to remove a credential from input', async () => { @@ -118,12 +114,12 @@ describe('', () => { count: 1, }, }); - expect(CredentialsAPI.read).toHaveBeenCalledTimes(2); + expect(CredentialsAPI.read).toHaveBeenCalledTimes(1); await act(async () => { select.invoke('onChange')({}, 500); }); wrapper.update(); - expect(CredentialsAPI.read).toHaveBeenCalledTimes(3); + expect(CredentialsAPI.read).toHaveBeenCalledTimes(2); expect(wrapper.find('OptionsList').prop('options')).toEqual([ { id: 1, kind: 'cloud', name: 'New Cred', url: 'www.google.com' }, ]);