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

UIE-204 Narrow Ajax Usage pt24 (final) #5240

Merged
merged 3 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions src/appLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { initAuthTesting } from 'src/auth/app-load/init-auth-test';
import { initializeAuthMetrics } from 'src/auth/app-load/init-metrics';
import { initializeClientId } from 'src/auth/app-load/initializeClientId';
import { initializeSystemProperties } from 'src/auth/system-loader';
import { setupAjaxTestUtil } from 'src/libs/ajax';
import { isAxeEnabled } from 'src/libs/config';
import Main from 'src/pages/Main';

Expand All @@ -21,6 +22,8 @@ RModal.defaultStyles = { overlay: {}, content: {} };

window._ = _;

setupAjaxTestUtil();

initializeAuthListeners();
initializeAuthMetrics();
initAuthTesting();
Expand Down
44 changes: 44 additions & 0 deletions src/libs/ajax.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { asMockedFn, partial } from '@terra-ui-packages/test-utils';

import { AjaxTestingContract, setupAjaxTestUtil } from './ajax';
import { Apps, AppsAjaxContract } from './ajax/leonardo/Apps';
import { Runtimes, RuntimesAjaxContract } from './ajax/leonardo/Runtimes';
import { Workspaces, WorkspacesAjaxContract } from './ajax/workspaces/Workspaces';

jest.mock('src/libs/ajax/leonardo/Apps');
jest.mock('src/libs/ajax/leonardo/Runtimes');
jest.mock('src/libs/ajax/workspaces/Workspaces');

describe('setupAjaxTestUtil', () => {
beforeEach(() => {
asMockedFn(Apps).mockReturnValue(partial<AppsAjaxContract>({}));
asMockedFn(Runtimes).mockReturnValue(partial<RuntimesAjaxContract>({}));
asMockedFn(Workspaces).mockReturnValue(partial<WorkspacesAjaxContract>({}));
});

it('sets up Ajax data-call testing root', () => {
// Act
setupAjaxTestUtil();
const ajaxTestingContract = (window as any).Ajax() as AjaxTestingContract;

// Assert
expect(ajaxTestingContract).toBeDefined();
expect(ajaxTestingContract.Apps).toBeDefined();
expect(ajaxTestingContract.Runtimes).toBeDefined();
expect(ajaxTestingContract.Workspaces).toBeDefined();
});
it('passes along signal arg to sub-areas', () => {
// Arrange
const signal = new AbortController().signal;

// Act
setupAjaxTestUtil();
const ajaxTestingContract = (window as any).Ajax(signal) as AjaxTestingContract;

// Assert
expect(ajaxTestingContract).toBeDefined();
expect(Apps).toBeCalledWith(signal);
expect(Runtimes).toBeCalledWith(signal);
expect(Workspaces).toBeCalledWith(signal);
});
});
60 changes: 6 additions & 54 deletions src/libs/ajax.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,18 @@
import { AzureStorage } from 'src/libs/ajax/AzureStorage';
import { Billing } from 'src/libs/ajax/billing/Billing';
import { Catalog } from 'src/libs/ajax/Catalog';
import { DataRepo } from 'src/libs/ajax/DataRepo';
import { Dockstore } from 'src/libs/ajax/Dockstore';
import { DrsUriResolver } from 'src/libs/ajax/drs/DrsUriResolver';
import { ExternalCredentials } from 'src/libs/ajax/ExternalCredentials';
import { FirecloudBucket } from 'src/libs/ajax/firecloud/FirecloudBucket';
import { GoogleStorage } from 'src/libs/ajax/GoogleStorage';
import { Groups } from 'src/libs/ajax/Groups';
import { Apps } from 'src/libs/ajax/leonardo/Apps';
import { Disks } from 'src/libs/ajax/leonardo/Disks';
import { Runtimes } from 'src/libs/ajax/leonardo/Runtimes';
import { Methods } from 'src/libs/ajax/methods/Methods';
import { Metrics } from 'src/libs/ajax/Metrics';
import { OAuth2 } from 'src/libs/ajax/OAuth2';
import { SamResources } from 'src/libs/ajax/SamResources';
import { Support } from 'src/libs/ajax/Support';
import { Surveys } from 'src/libs/ajax/surveys/Surveys';
import { TermsOfService } from 'src/libs/ajax/TermsOfService';
import { User } from 'src/libs/ajax/User';
import { Cbas } from 'src/libs/ajax/workflows-app/Cbas';
import { CromIAM } from 'src/libs/ajax/workflows-app/CromIAM';
import { CromwellApp } from 'src/libs/ajax/workflows-app/CromwellApp';
import { WorkflowScript } from 'src/libs/ajax/workflows-app/WorkflowScript';
import { WorkspaceData } from 'src/libs/ajax/WorkspaceDataService';
import { WorkspaceManagerResources } from 'src/libs/ajax/WorkspaceManagerResources';
import { Workspaces } from 'src/libs/ajax/workspaces/Workspaces';

export const Ajax = (signal?: AbortSignal) => {
const AjaxTestingRoot = (signal?: AbortSignal) => {
return {
Apps: Apps(signal), // used for e2e testing
AzureStorage: AzureStorage(signal),
Billing: Billing(signal),
Buckets: GoogleStorage(signal), // used for e2e testing
Catalog: Catalog(signal),
Cbas: Cbas(signal),
CromIAM: CromIAM(signal),
CromwellApp: CromwellApp(signal),
DataRepo: DataRepo(signal),
Disks: Disks(signal),
Dockstore: Dockstore(signal),
DrsUriResolver: DrsUriResolver(signal),
ExternalCredentials: ExternalCredentials(signal),
FirecloudBucket: FirecloudBucket(signal),
Groups: Groups(signal),
Methods: Methods(signal),
Metrics: Metrics(signal),
OAuth2: OAuth2(signal),
Runtimes: Runtimes(signal), // used for e2e testing
SamResources: SamResources(signal),
Support: Support(signal),
Surveys: Surveys(signal),
TermsOfService: TermsOfService(signal),
User: User(signal),
WorkflowScript: WorkflowScript(signal),
WorkspaceData: WorkspaceData(signal),
WorkspaceManagerResources: WorkspaceManagerResources(signal),
Workspaces: Workspaces(signal), // used for e2e testing
};
};

export type AjaxContract = ReturnType<typeof Ajax>;
export type AjaxTestingContract = ReturnType<typeof AjaxTestingRoot>;

// Exposing Ajax for use by integration tests (and debugging, or whatever)
(window as any).Ajax = Ajax;
export const setupAjaxTestUtil = () => {
// Exposing Ajax for use by integration tests (and debugging, or whatever)
(window as any).Ajax = AjaxTestingRoot;
};
4 changes: 2 additions & 2 deletions src/libs/ajax/AzureStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { AnalysisFile, AnalysisFileMetadata } from 'src/analysis/useAnalysisFile
import { AbsolutePath, getDisplayName, getExtension, getFileName } from 'src/analysis/utils/file-utils';
import { runtimeToolLabels } from 'src/analysis/utils/tool-utils';
import { authOpts } from 'src/auth/auth-session';
import { Ajax } from 'src/libs/ajax';
import { fetchWorkspaceManager } from 'src/libs/ajax/ajax-common';
import { fetchOk } from 'src/libs/ajax/fetch/fetch-core';
import { WorkspaceManagerResources } from 'src/libs/ajax/WorkspaceManagerResources';
import { getConfig } from 'src/libs/config';
import * as Utils from 'src/libs/utils';
import { cloudProviderTypes } from 'src/workspaces/utils';
Expand Down Expand Up @@ -78,7 +78,7 @@ export const AzureStorage = (signal?: AbortSignal) => ({
* (which is an expected transient state while a workspace is being cloned).
*/
containerInfo: async (workspaceId: string): Promise<StorageContainerInfo> => {
const data = await Ajax(signal).WorkspaceManagerResources.controlledResources(workspaceId);
const data = await WorkspaceManagerResources(signal).controlledResources(workspaceId);
const container = _.find(
{
metadata: {
Expand Down
3 changes: 1 addition & 2 deletions src/libs/ajax/SamResources.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { jsonBody } from '@terra-ui-packages/data-client-core';
import _ from 'lodash/fp';
import { authOpts } from 'src/auth/auth-session';
import { Ajax } from 'src/libs/ajax';
import { fetchSam } from 'src/libs/ajax/ajax-common';
import { appIdentifier } from 'src/libs/ajax/fetch/fetch-core';

Expand Down Expand Up @@ -34,7 +33,7 @@ export const SamResources = (signal?: AbortSignal) => ({
object: string,
requesterPaysProject: RequesterPaysProject = undefined
): Promise<string> => {
return Ajax(signal).SamResources.getRequesterPaysSignedUrl(`gs://${bucket}/${object}`, requesterPaysProject);
return SamResources(signal).getRequesterPaysSignedUrl(`gs://${bucket}/${object}`, requesterPaysProject);
},

getResourcePolicies: async (fqResourceId: FullyQualifiedResourceId): Promise<object> => {
Expand Down
6 changes: 3 additions & 3 deletions src/libs/ajax/compute-image-providers/ComputeImageProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
runtimeToolLabels,
terraSupportedRuntimeImageIds,
} from 'src/analysis/utils/tool-utils';
import { Ajax } from 'src/libs/ajax';
import { GoogleStorage } from 'src/libs/ajax/GoogleStorage';
import { getConfig } from 'src/libs/config';

export interface ComputeImageProviderContract {
Expand Down Expand Up @@ -72,8 +72,8 @@ const normalizeImage: (rawImage: ComputeImageRaw) => ComputeImage = (rawImage) =

export const ComputeImageProvider: ComputeImageProviderContract = {
listImages: async (googleProject: string, signal?: AbortSignal): Promise<ComputeImage[]> => {
const fetchedImages: ComputeImageRaw[] = await Ajax(signal)
.Buckets.getObjectPreview(
const fetchedImages: ComputeImageRaw[] = await GoogleStorage(signal)
.getObjectPreview(
googleProject,
getConfig().terraDockerImageBucket,
getConfig().terraDockerVersionsFile,
Expand Down
79 changes: 36 additions & 43 deletions src/libs/ajax/data-table-providers/WdsDataTableProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { DeepPartial } from '@terra-ui-packages/core-utils';
import { Ajax } from 'src/libs/ajax';
import { Apps } from 'src/libs/ajax/leonardo/Apps';
import { Capabilities, WorkspaceData } from 'src/libs/ajax/WorkspaceDataService';
import { asMockedFn } from 'src/testing/test-utils';
import { Apps, AppsAjaxContract } from 'src/libs/ajax/leonardo/Apps';
import { Capabilities, WorkspaceData, WorkspaceDataAjaxContract } from 'src/libs/ajax/WorkspaceDataService';
import { asMockedFn, MockedFn, partial } from 'src/testing/test-utils';
import { cloudProviderTypes } from 'src/workspaces/utils';

import { ListAppItem } from '../leonardo/models/app-models';
Expand All @@ -22,7 +21,8 @@ import {
wdsToEntityServiceMetadata,
} from './WdsDataTableProvider';

jest.mock('src/libs/ajax');
jest.mock('src/libs/ajax/leonardo/Apps');
jest.mock('src/libs/ajax/WorkspaceDataService');

type ReactNotificationsComponentExports = typeof import('react-notifications-component');
jest.mock('react-notifications-component', (): DeepPartial<ReactNotificationsComponentExports> => {
Expand Down Expand Up @@ -97,12 +97,8 @@ const queryOptions: EntityQueryOptions = {
columnFilter: '',
};

type WorkspaceDataContract = ReturnType<typeof WorkspaceData>;
type AjaxContract = ReturnType<typeof Ajax>;
type AppsContract = ReturnType<typeof Apps>;

describe('WdsDataTableProvider', () => {
const getRecordsMockImpl: WorkspaceDataContract['getRecords'] = (
const getRecordsMockImpl: WorkspaceDataAjaxContract['getRecords'] = (
_root: string,
_instanceId: string,
_recordType: string,
Expand Down Expand Up @@ -150,20 +146,20 @@ describe('WdsDataTableProvider', () => {
return Promise.resolve(recordQueryResponse);
};

const getCapabilitiesMockImpl: WorkspaceDataContract['getCapabilities'] = (_root: string) => {
const getCapabilitiesMockImpl: WorkspaceDataAjaxContract['getCapabilities'] = (_root: string) => {
const Capabilities: Capabilities = {};
return Promise.resolve(Capabilities);
};

const deleteTableMockImpl: WorkspaceDataContract['deleteTable'] = (_instanceId: string, _recordType: string) => {
const deleteTableMockImpl: WorkspaceDataAjaxContract['deleteTable'] = (_instanceId: string, _recordType: string) => {
return Promise.resolve(new Response('', { status: 204 }));
};

const downloadTsvMockImpl: WorkspaceDataContract['downloadTsv'] = (_instanceId: string, _recordType: string) => {
const downloadTsvMockImpl: WorkspaceDataAjaxContract['downloadTsv'] = (_instanceId: string, _recordType: string) => {
return Promise.resolve(new Blob(['hello']));
};

const uploadTsvMockImpl: WorkspaceDataContract['uploadTsv'] = (
const uploadTsvMockImpl: WorkspaceDataAjaxContract['uploadTsv'] = (
_root: string,
_instanceId: string,
_recordType: string,
Expand All @@ -172,7 +168,7 @@ describe('WdsDataTableProvider', () => {
return Promise.resolve({ message: 'Upload Succeeded', recordsModified: 1 });
};

const updateRecordMockImpl: WorkspaceDataContract['updateRecord'] = (
const updateRecordMockImpl: WorkspaceDataAjaxContract['updateRecord'] = (
_root: string,
_instanceId: string,
_recordType: string,
Expand All @@ -190,37 +186,34 @@ describe('WdsDataTableProvider', () => {
return Promise.resolve(testProxyUrlResponse);
};

let getRecords: jest.MockedFunction<WorkspaceDataContract['getRecords']>;
let updateRecord: jest.MockedFunction<WorkspaceDataContract['updateRecord']>;
let getCapabilities: jest.MockedFunction<WorkspaceDataContract['getCapabilities']>;
let deleteTable: jest.MockedFunction<WorkspaceDataContract['deleteTable']>;
let downloadTsv: jest.MockedFunction<WorkspaceDataContract['downloadTsv']>;
let uploadTsv: jest.MockedFunction<WorkspaceDataContract['uploadTsv']>;
let listAppsV2: jest.MockedFunction<AppsContract['listAppsV2']>;
const getRecords: MockedFn<WorkspaceDataAjaxContract['getRecords']> = jest.fn();
const updateRecord: MockedFn<WorkspaceDataAjaxContract['updateRecord']> = jest.fn();
const getCapabilities: MockedFn<WorkspaceDataAjaxContract['getCapabilities']> = jest.fn();
const deleteTable: MockedFn<WorkspaceDataAjaxContract['deleteTable']> = jest.fn();
const downloadTsv: MockedFn<WorkspaceDataAjaxContract['downloadTsv']> = jest.fn();
const uploadTsv: MockedFn<WorkspaceDataAjaxContract['uploadTsv']> = jest.fn();
const listAppsV2: MockedFn<AppsAjaxContract['listAppsV2']> = jest.fn();

beforeEach(() => {
getRecords = jest.fn().mockImplementation(getRecordsMockImpl);
updateRecord = jest.fn().mockImplementation(updateRecordMockImpl);
getCapabilities = jest.fn().mockImplementation(getCapabilitiesMockImpl);
deleteTable = jest.fn().mockImplementation(deleteTableMockImpl);
downloadTsv = jest.fn().mockImplementation(downloadTsvMockImpl);
uploadTsv = jest.fn().mockImplementation(uploadTsvMockImpl);
listAppsV2 = jest.fn().mockImplementation(listAppsV2MockImpl);

asMockedFn(Ajax).mockImplementation(
() =>
({
WorkspaceData: {
getRecords,
updateRecord,
getCapabilities,
deleteTable,
downloadTsv,
uploadTsv,
} as Partial<WorkspaceDataContract>,
Apps: { listAppsV2 } as Partial<AppsContract>,
} as Partial<AjaxContract> as AjaxContract)
getRecords.mockImplementation(getRecordsMockImpl);
updateRecord.mockImplementation(updateRecordMockImpl);
getCapabilities.mockImplementation(getCapabilitiesMockImpl);
deleteTable.mockImplementation(deleteTableMockImpl);
downloadTsv.mockImplementation(downloadTsvMockImpl);
uploadTsv.mockImplementation(uploadTsvMockImpl);
listAppsV2.mockImplementation(listAppsV2MockImpl);

asMockedFn(WorkspaceData).mockReturnValue(
partial<WorkspaceDataAjaxContract>({
getRecords,
updateRecord,
getCapabilities,
deleteTable,
downloadTsv,
uploadTsv,
})
);
asMockedFn(Apps).mockReturnValue(partial<AppsAjaxContract>({ listAppsV2 }));
});

describe('transformAttributes', () => {
Expand Down
17 changes: 8 additions & 9 deletions src/libs/ajax/data-table-providers/WdsDataTableProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import _ from 'lodash/fp';
import { Ajax } from 'src/libs/ajax';
import {
AttributeArray,
DataTableFeatures,
Expand All @@ -15,7 +14,7 @@ import {
UploadParameters,
} from 'src/libs/ajax/data-table-providers/DataTableProvider';
import { LeoAppStatus, ListAppItem } from 'src/libs/ajax/leonardo/models/app-models';
import { Capabilities, Capability } from 'src/libs/ajax/WorkspaceDataService';
import { Capabilities, Capability, WorkspaceData } from 'src/libs/ajax/WorkspaceDataService';
import { notificationStore } from 'src/libs/state';
import * as Utils from 'src/libs/utils';
import { notifyDataImportProgress } from 'src/workspace-data/import-jobs';
Expand Down Expand Up @@ -283,7 +282,7 @@ export class WdsDataTableProvider implements DataTableProvider {
metadata: EntityMetadata
): Promise<EntityQueryResponse> => {
if (!this.proxyUrl) return Promise.reject('Proxy Url not loaded');
const wdsPage: RecordQueryResponse = await Ajax(signal).WorkspaceData.getRecords(
const wdsPage: RecordQueryResponse = await WorkspaceData(signal).getRecords(
this.proxyUrl,
this.workspaceId,
entityType,
Expand All @@ -301,17 +300,17 @@ export class WdsDataTableProvider implements DataTableProvider {

deleteTable = (entityType: string): Promise<Response> => {
if (!this.proxyUrl) return Promise.reject('Proxy Url not loaded');
return Ajax().WorkspaceData.deleteTable(this.proxyUrl, this.workspaceId, entityType);
return WorkspaceData().deleteTable(this.proxyUrl, this.workspaceId, entityType);
};

deleteColumn = (signal: AbortSignal, entityType: string, attributeName: string): Promise<Response> => {
if (!this.proxyUrl) return Promise.reject('Proxy URL not loaded');
return Ajax(signal).WorkspaceData.deleteColumn(this.proxyUrl, this.workspaceId, entityType, attributeName);
return WorkspaceData(signal).deleteColumn(this.proxyUrl, this.workspaceId, entityType, attributeName);
};

downloadTsv = (signal: AbortSignal, entityType: string): Promise<Blob> => {
if (!this.proxyUrl) return Promise.reject('Proxy Url not loaded');
return Ajax(signal).WorkspaceData.downloadTsv(this.proxyUrl, this.workspaceId, entityType);
return WorkspaceData(signal).downloadTsv(this.proxyUrl, this.workspaceId, entityType);
};

uploadTsv = (uploadParams: UploadParameters): Promise<TsvUploadResponse> => {
Expand All @@ -331,7 +330,7 @@ export class WdsDataTableProvider implements DataTableProvider {
);
}
}, 1000);
return Ajax().WorkspaceData.uploadTsv(
return WorkspaceData().uploadTsv(
this.proxyUrl,
uploadParams.workspaceId,
uploadParams.recordType,
Expand All @@ -342,7 +341,7 @@ export class WdsDataTableProvider implements DataTableProvider {
updateRecord = (recordEditParams: RecordEditParameters): Promise<RecordResponseBody> => {
if (!this.proxyUrl) return Promise.reject('Proxy Url not loaded');

return Ajax().WorkspaceData.updateRecord(
return WorkspaceData().updateRecord(
this.proxyUrl,
recordEditParams.instance,
recordEditParams.recordName,
Expand All @@ -353,7 +352,7 @@ export class WdsDataTableProvider implements DataTableProvider {

updateAttribute = (params: UpdateAttributeParameters): Promise<Blob> => {
if (!this.proxyUrl) return Promise.reject('Proxy Url not loaded');
return Ajax().WorkspaceData.updateAttribute(
return WorkspaceData().updateAttribute(
this.proxyUrl,
this.workspaceId,
params.entityType,
Expand Down
Loading
Loading