diff --git a/extensions/ql-vscode/test/factories/data-extension/external-api-factories.ts b/extensions/ql-vscode/test/factories/data-extension/external-api-factories.ts new file mode 100644 index 00000000000..fb245e8c514 --- /dev/null +++ b/extensions/ql-vscode/test/factories/data-extension/external-api-factories.ts @@ -0,0 +1,57 @@ +import { + Usage, + ExternalApiUsage, + CallClassification, +} from "../../../src/data-extensions-editor/external-api-usage"; +import { ModeledMethodType } from "../../../src/data-extensions-editor/modeled-method"; +import { ResolvableLocationValue } from "../../../src/common/bqrs-cli-types"; + +export function createExternalApiUsage({ + library = "test", + supported = true, + supportedType = "none" as ModeledMethodType, + usages = [], + signature = "test", + packageName = "test", + typeName = "test", + methodName = "test", + methodParameters = "test", +}: { + library?: string; + supported?: boolean; + supportedType?: ModeledMethodType; + usages?: Usage[]; + signature?: string; + packageName?: string; + typeName?: string; + methodName?: string; + methodParameters?: string; +} = {}): ExternalApiUsage { + return { + library, + supported, + supportedType, + usages, + signature, + packageName, + typeName, + methodName, + methodParameters, + }; +} + +export function createUsage({ + classification = CallClassification.Unknown, + label = "test", + url = {} as ResolvableLocationValue, +}: { + classification?: CallClassification; + label?: string; + url?: ResolvableLocationValue; +} = {}): Usage { + return { + classification, + label, + url, + }; +} diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/model-details/model-details-data-provider.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/model-details/model-details-data-provider.test.ts index 0bc4405b561..4564b68b3e9 100644 --- a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/model-details/model-details-data-provider.test.ts +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/model-details/model-details-data-provider.test.ts @@ -2,20 +2,28 @@ import { CodeQLCliServer } from "../../../../../src/codeql-cli/cli"; import { ExternalApiUsage } from "../../../../../src/data-extensions-editor/external-api-usage"; import { ModelDetailsDataProvider } from "../../../../../src/data-extensions-editor/model-details/model-details-data-provider"; import { DatabaseItem } from "../../../../../src/databases/local-databases"; +import { + createExternalApiUsage, + createUsage, +} from "../../../../factories/data-extension/external-api-factories"; import { mockedObject } from "../../../utils/mocking.helpers"; describe("ModelDetailsDataProvider", () => { const mockCliServer = mockedObject({}); + let dataProvider: ModelDetailsDataProvider; + + beforeEach(() => { + dataProvider = new ModelDetailsDataProvider(mockCliServer); + }); describe("setState", () => { - const hideModeledApis: boolean = false; + const hideModeledApis = false; const externalApiUsages: ExternalApiUsage[] = []; const dbItem = mockedObject({ getSourceLocationPrefix: () => "test", }); it("should not emit onDidChangeTreeData event when state has not changed", async () => { - const dataProvider = new ModelDetailsDataProvider(mockCliServer); await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis); const onDidChangeTreeDataListener = jest.fn(); @@ -29,7 +37,6 @@ describe("ModelDetailsDataProvider", () => { it("should emit onDidChangeTreeData event when externalApiUsages has changed", async () => { const externalApiUsages2: ExternalApiUsage[] = []; - const dataProvider = new ModelDetailsDataProvider(mockCliServer); await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis); const onDidChangeTreeDataListener = jest.fn(); @@ -45,7 +52,6 @@ describe("ModelDetailsDataProvider", () => { getSourceLocationPrefix: () => "test", }); - const dataProvider = new ModelDetailsDataProvider(mockCliServer); await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis); const onDidChangeTreeDataListener = jest.fn(); @@ -57,7 +63,6 @@ describe("ModelDetailsDataProvider", () => { }); it("should emit onDidChangeTreeData event when hideModeledApis has changed", async () => { - const dataProvider = new ModelDetailsDataProvider(mockCliServer); await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis); const onDidChangeTreeDataListener = jest.fn(); @@ -74,7 +79,6 @@ describe("ModelDetailsDataProvider", () => { }); const externalApiUsages2: ExternalApiUsage[] = []; - const dataProvider = new ModelDetailsDataProvider(mockCliServer); await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis); const onDidChangeTreeDataListener = jest.fn(); @@ -89,4 +93,45 @@ describe("ModelDetailsDataProvider", () => { expect(onDidChangeTreeDataListener).toHaveBeenCalledTimes(1); }); }); + + describe("getChildren", () => { + const supportedExternalApiUsage = createExternalApiUsage({ + supported: true, + }); + + const unsupportedExternalApiUsage = createExternalApiUsage({ + supported: false, + }); + + const externalApiUsages: ExternalApiUsage[] = [ + supportedExternalApiUsage, + unsupportedExternalApiUsage, + ]; + const dbItem = mockedObject({ + getSourceLocationPrefix: () => "test", + }); + + const usage = createUsage({}); + + it("should return [] if item is a usage", async () => { + expect(dataProvider.getChildren(usage)).toEqual([]); + }); + + it("should return usages if item is external api usage", async () => { + const externalApiUsage = createExternalApiUsage({ usages: [usage] }); + expect(dataProvider.getChildren(externalApiUsage)).toEqual([usage]); + }); + + it("should show all externalApiUsages if hideModeledApis is false and looking at the root", async () => { + const hideModeledApis = false; + await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis); + expect(dataProvider.getChildren().length).toEqual(2); + }); + + it("should filter externalApiUsages if hideModeledApis is true and looking at the root", async () => { + const hideModeledApis = true; + await dataProvider.setState(externalApiUsages, dbItem, hideModeledApis); + expect(dataProvider.getChildren().length).toEqual(1); + }); + }); }); diff --git a/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/model-details/model-details-panel.test.ts b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/model-details/model-details-panel.test.ts new file mode 100644 index 00000000000..2b3ac10dde7 --- /dev/null +++ b/extensions/ql-vscode/test/vscode-tests/no-workspace/data-extensions-editor/model-details/model-details-panel.test.ts @@ -0,0 +1,73 @@ +import { window, TreeView } from "vscode"; +import { CodeQLCliServer } from "../../../../../src/codeql-cli/cli"; +import { ExternalApiUsage } from "../../../../../src/data-extensions-editor/external-api-usage"; +import { ModelDetailsPanel } from "../../../../../src/data-extensions-editor/model-details/model-details-panel"; +import { DatabaseItem } from "../../../../../src/databases/local-databases"; +import { mockedObject } from "../../../utils/mocking.helpers"; +import { + createExternalApiUsage, + createUsage, +} from "../../../../factories/data-extension/external-api-factories"; + +describe("ModelDetailsPanel", () => { + const mockCliServer = mockedObject({}); + const dbItem = mockedObject({ + getSourceLocationPrefix: () => "test", + }); + + describe("setState", () => { + const hideModeledApis = false; + const externalApiUsages: ExternalApiUsage[] = [createExternalApiUsage()]; + + it("should update the tree view with the correct batch number", async () => { + const mockTreeView = { + badge: undefined, + } as TreeView; + jest.spyOn(window, "createTreeView").mockReturnValue(mockTreeView); + + const panel = new ModelDetailsPanel(mockCliServer); + await panel.setState(externalApiUsages, dbItem, hideModeledApis); + + expect(mockTreeView.badge?.value).toBe(1); + }); + }); + + describe("revealItem", () => { + let mockTreeView: TreeView; + + const hideModeledApis: boolean = false; + const usage = createUsage(); + + beforeEach(() => { + mockTreeView = { + reveal: jest.fn(), + } as unknown as TreeView; + jest.spyOn(window, "createTreeView").mockReturnValue(mockTreeView); + }); + + it("should reveal the correct item in the tree view", async () => { + const externalApiUsages = [ + createExternalApiUsage({ + usages: [usage], + }), + ]; + + const panel = new ModelDetailsPanel(mockCliServer); + await panel.setState(externalApiUsages, dbItem, hideModeledApis); + + await panel.revealItem(usage); + + expect(mockTreeView.reveal).toHaveBeenCalledWith(usage); + }); + + it("should do nothing if usage cannot be found", async () => { + const externalApiUsages = [createExternalApiUsage({})]; + const panel = new ModelDetailsPanel(mockCliServer); + await panel.setState(externalApiUsages, dbItem, hideModeledApis); + + await panel.revealItem(usage); + + expect(mockTreeView.reveal).not.toHaveBeenCalled(); + }); + }); +});