Migrate unit test to DocumentsTabV2

This commit is contained in:
Laurent Nguyen 2024-04-30 18:26:15 +02:00
parent 6c3aa7e625
commit 3c6c32ecc2
2 changed files with 146 additions and 44 deletions

View File

@ -0,0 +1,99 @@
import { buildQuery, showPartitionKey } from "Explorer/Tabs/DocumentsTabV2/DocumentsTabV2";
import * as ko from "knockout";
import { DatabaseAccount } from "../../../Contracts/DataModels";
import * as ViewModels from "../../../Contracts/ViewModels";
import { updateUserContext } from "../../../UserContext";
import Explorer from "../../Explorer";
describe("Documents tab", () => {
describe("buildQuery", () => {
it("should generate the right select query for SQL API", () => {
expect(buildQuery(false, "")).toContain("select");
});
});
describe("showPartitionKey", () => {
const explorer = new Explorer();
const mongoExplorer = new Explorer();
updateUserContext({
databaseAccount: {
properties: {
capabilities: [{ name: "EnableGremlin" }],
},
} as DatabaseAccount,
});
const collectionWithoutPartitionKey = <ViewModels.Collection>(<unknown>{
id: ko.observable<string>("foo"),
database: {
id: ko.observable<string>("foo"),
},
container: explorer,
});
const collectionWithSystemPartitionKey = <ViewModels.Collection>(<unknown>{
id: ko.observable<string>("foo"),
database: {
id: ko.observable<string>("foo"),
},
partitionKey: {
paths: ["/foo"],
kind: "Hash",
version: 2,
systemKey: true,
},
container: explorer,
});
const collectionWithNonSystemPartitionKey = <ViewModels.Collection>(<unknown>{
id: ko.observable<string>("foo"),
database: {
id: ko.observable<string>("foo"),
},
partitionKey: {
paths: ["/foo"],
kind: "Hash",
version: 2,
systemKey: false,
},
container: explorer,
});
const mongoCollectionWithSystemPartitionKey = <ViewModels.Collection>(<unknown>{
id: ko.observable<string>("foo"),
database: {
id: ko.observable<string>("foo"),
},
partitionKey: {
paths: ["/foo"],
kind: "Hash",
version: 2,
systemKey: true,
},
container: mongoExplorer,
});
it("should be false for null or undefined collection", () => {
expect(showPartitionKey(undefined, false)).toBe(false);
expect(showPartitionKey(null, false)).toBe(false);
expect(showPartitionKey(undefined, true)).toBe(false);
expect(showPartitionKey(null, true)).toBe(false);
});
it("should be false for null or undefined partitionKey", () => {
expect(showPartitionKey(collectionWithoutPartitionKey, false)).toBe(false);
});
it("should be true for non-Mongo accounts with system partitionKey", () => {
expect(showPartitionKey(collectionWithSystemPartitionKey, false)).toBe(true);
});
it("should be false for Mongo accounts with system partitionKey", () => {
expect(showPartitionKey(mongoCollectionWithSystemPartitionKey, true)).toBe(false);
});
it("should be true for non-system partitionKey", () => {
expect(showPartitionKey(collectionWithNonSystemPartitionKey, false)).toBe(true);
});
});
});

View File

@ -375,6 +375,37 @@ const _loadNextPageInternal = (
return iterator.fetchNext().then((response) => response.resources); return iterator.fetchNext().then((response) => response.resources);
}; };
// Export for testing purposes
export const showPartitionKey = (collection: ViewModels.CollectionBase, isPreferredApiMongoDB: boolean) => {
if (!collection) {
return false;
}
if (!collection.partitionKey) {
return false;
}
if (collection.partitionKey.systemKey && isPreferredApiMongoDB) {
return false;
}
return true;
};
// Export for testing purposes
export const buildQuery = (
isMongo: boolean,
filter: string,
partitionKeyProperties?: string[],
partitionKey?: DataModels.PartitionKey,
): string => {
if (isMongo) {
return filter || "{}";
}
return QueryUtils.buildDocumentsQuery(filter, partitionKeyProperties, partitionKey);
};
const DocumentsTabComponent: React.FunctionComponent<{ const DocumentsTabComponent: React.FunctionComponent<{
isPreferredApiMongoDB: boolean; isPreferredApiMongoDB: boolean;
documentIds: DocumentId[]; // TODO: this contains ko observables. We need to convert them to React state. documentIds: DocumentId[]; // TODO: this contains ko observables. We need to convert them to React state.
@ -882,18 +913,11 @@ const DocumentsTabComponent: React.FunctionComponent<{
[isPreferredApiMongoDB], [isPreferredApiMongoDB],
); );
let buildQuery = useCallback(
(filter: string): string => {
return QueryUtils.buildDocumentsQuery(filter, partitionKeyProperties, partitionKey);
},
[partitionKeyProperties, partitionKey],
);
const createIterator = useCallback((): QueryIterator<ItemDefinition & Resource> => { const createIterator = useCallback((): QueryIterator<ItemDefinition & Resource> => {
const _queryAbortController = new AbortController(); const _queryAbortController = new AbortController();
setQueryAbortController(_queryAbortController); setQueryAbortController(_queryAbortController);
const filter: string = filterContent.trim(); const filter: string = filterContent.trim();
const query: string = buildQuery(filter); const query: string = buildQuery(isPreferredApiMongoDB, filter, partitionKeyProperties, partitionKey);
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const options: any = {}; const options: any = {};
// TODO: Property 'enableCrossPartitionQuery' does not exist on type 'FeedOptions'. // TODO: Property 'enableCrossPartitionQuery' does not exist on type 'FeedOptions'.
@ -908,7 +932,7 @@ const DocumentsTabComponent: React.FunctionComponent<{
return isQueryCopilotSampleContainer return isQueryCopilotSampleContainer
? querySampleDocuments(query, options) ? querySampleDocuments(query, options)
: queryDocuments(_collection.databaseId, _collection.id(), query, options); : queryDocuments(_collection.databaseId, _collection.id(), query, options);
}, [filterContent, buildQuery, resourceTokenPartitionKey, isQueryCopilotSampleContainer, _collection]); }, [isPreferredApiMongoDB, filterContent, resourceTokenPartitionKey, isQueryCopilotSampleContainer, _collection]);
/** /**
* Query first page of documents * Query first page of documents
@ -1115,23 +1139,6 @@ const DocumentsTabComponent: React.FunctionComponent<{
} }
}; };
// TODO: use this when generating column headers
const showPartitionKey = (() => {
if (!_collection) {
return false;
}
if (!_collection.partitionKey) {
return false;
}
if (_collection.partitionKey.systemKey && isPreferredApiMongoDB) {
return false;
}
return true;
})();
const _isQueryCopilotSampleContainer = const _isQueryCopilotSampleContainer =
_collection?.isSampleCollection && _collection?.isSampleCollection &&
_collection?.databaseId === QueryCopilotSampleDatabaseId && _collection?.databaseId === QueryCopilotSampleDatabaseId &&
@ -1259,7 +1266,7 @@ const DocumentsTabComponent: React.FunctionComponent<{
const columnHeaders = { const columnHeaders = {
idHeader: isPreferredApiMongoDB ? "_id" : "id", idHeader: isPreferredApiMongoDB ? "_id" : "id",
partitionKeyHeaders: (showPartitionKey && partitionKeyPropertyHeaders) || [], partitionKeyHeaders: (showPartitionKey(_collection, isPreferredApiMongoDB) && partitionKeyPropertyHeaders) || [],
}; };
const onSelectedRowsChange = (selectedRows: Set<TableRowId>) => { const onSelectedRowsChange = (selectedRows: Set<TableRowId>) => {
@ -1549,15 +1556,11 @@ const DocumentsTabComponent: React.FunctionComponent<{
.finally(() => setIsExecuting(false)); .finally(() => setIsExecuting(false));
}; };
buildQuery = (filter: string): string => {
return filter || "{}";
};
loadNextPage = (): Promise<unknown> => { loadNextPage = (): Promise<unknown> => {
setIsExecuting(true); setIsExecuting(true);
onExecutionErrorChange(false); onExecutionErrorChange(false);
const filter: string = filterContent.trim(); const filter: string = filterContent.trim();
const query: string = buildQuery(filter); const query: string = buildQuery(isPreferredApiMongoDB, filter);
return MongoProxyClient.queryDocuments( return MongoProxyClient.queryDocuments(
_collection.databaseId, _collection.databaseId,
@ -1668,12 +1671,12 @@ const DocumentsTabComponent: React.FunctionComponent<{
<div <div
className="tab-pane active" className="tab-pane active"
/* data-bind=" /* data-bind="
setTemplateReady: true, setTemplateReady: true,
attr:{ attr:{
id: tabId id: tabId
}, },
visible: isActive" visible: isActive"
*/ */
role="tabpanel" role="tabpanel"
style={{ display: "flex" }} style={{ display: "flex" }}
> >
@ -1766,9 +1769,9 @@ const DocumentsTabComponent: React.FunctionComponent<{
onClick={() => refreshDocumentsGrid(true)} onClick={() => refreshDocumentsGrid(true)}
disabled={!applyFilterButton.enabled} disabled={!applyFilterButton.enabled}
/* data-bind=" /* data-bind="
click: refreshDocumentsGrid.bind($data, true), click: refreshDocumentsGrid.bind($data, true),
enable: applyFilterButton.enabled" enable: applyFilterButton.enabled"
*/ */
aria-label="Apply filter" aria-label="Apply filter"
tabIndex={0} tabIndex={0}
> >
@ -1781,9 +1784,9 @@ const DocumentsTabComponent: React.FunctionComponent<{
style={filterButtonStyle} style={filterButtonStyle}
appearance="primary" appearance="primary"
/* data-bind=" /* data-bind="
visible: !isPreferredApiMongoDB && isExecuting, visible: !isPreferredApiMongoDB && isExecuting,
click: onAbortQueryClick" click: onAbortQueryClick"
*/ */
aria-label="Cancel Query" aria-label="Cancel Query"
onClick={() => queryAbortController.abort()} onClick={() => queryAbortController.abort()}
tabIndex={0} tabIndex={0}