Skip to content

Commit

Permalink
fix: "Show Config" button in error dialog does not work during initia…
Browse files Browse the repository at this point in the history
…lization (#3274)

* fix: check if profileInfo is nullish during v1 migration

Signed-off-by: Trae Yelovich <[email protected]>

* chore: update ZE changelog

Signed-off-by: Trae Yelovich <[email protected]>

* tests: integration test for broken config

Signed-off-by: Trae Yelovich <[email protected]>

* add unit test for nullish profileinfo

Signed-off-by: Trae Yelovich <[email protected]>

* fix transient failures in UpdateCredentials scenario

Signed-off-by: Trae Yelovich <[email protected]>

* remove extra join import in wdio conf

Signed-off-by: Trae Yelovich <[email protected]>

* make integration test more reliable

Signed-off-by: Trae Yelovich <[email protected]>

* move getprofileinfo call into try/catch during profiles init

Signed-off-by: Trae Yelovich <[email protected]>

* test: open notification center to check for dialog

Signed-off-by: Trae Yelovich <[email protected]>

* add license header to test; add another null check

Signed-off-by: Trae Yelovich <[email protected]>

* add typedoc to ProfilesUtils.getProfileInfo

Signed-off-by: Trae Yelovich <[email protected]>

* setupDefaultCredentialManager: log err msgs, update typedoc

Signed-off-by: Trae Yelovich <[email protected]>

* test: promptUserWithNoConfigs, nullish profileInfo case

Signed-off-by: Trae Yelovich <[email protected]>

* refactor typedoc for setupDefaultCredentialManager

Signed-off-by: Trae Yelovich <[email protected]>

---------

Signed-off-by: Trae Yelovich <[email protected]>
  • Loading branch information
traeok authored Oct 24, 2024
1 parent 5e1b8e3 commit 5d2dce4
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 8 deletions.
1 change: 1 addition & 0 deletions packages/zowe-explorer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ All notable changes to the "vscode-extension-for-zowe" extension will be documen

- `DatasetFSProvider.stat()` will now throw a `FileNotFound` error for extenders trying to fetch an MVS resource that does not exist. [#3252](https://github.com/zowe/zowe-explorer-vscode/issues/3252)
- Fixed an issue where renaming or deleting a USS file or data set did not update the opened editor. [#3260](https://github.com/zowe/zowe-explorer-vscode/issues/3260)
- Fixed an issue during initialization where a broken team configuration file caused the "Show Config" action in the error dialog to stop working. [#3273](https://github.com/zowe/zowe-explorer-vscode/issues/3273)
- Fixed issue where switching the authentication methods would cause `Cannot read properties of undefined` error. [#3142](https://github.com/zowe/zowe-explorer-vscode/issues/3142)

## `3.0.2`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Feature: Show Config Error Dialog

Scenario: Initializing Zowe Explorer with a broken profile
When a user opens Zowe Explorer
Then the Show Config dialog should appear
When the user clicks on the "Show Config" button
Then the config should appear in the editor
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/

import { Then, When } from "@cucumber/cucumber";
import { getZoweExplorerContainer } from "../../../../__common__/shared.wdio";
import { Notification, Workbench } from "wdio-vscode-service";

When("a user opens Zowe Explorer", async function () {
this.zoweExplorerPane = await getZoweExplorerContainer();
await expect(this.zoweExplorerPane).toBeDefined();
});

Then("the Show Config dialog should appear", async function () {
this.workbench = await browser.getWorkbench();
let notification: Notification;
const notificationCenter = await (this.workbench as Workbench).openNotificationsCenter();
await notificationCenter.wait(60000);
await browser.waitUntil(async () => {
const notifications: Notification[] = await notificationCenter.getNotifications("error" as any);
for (const n of notifications) {
if ((await n.getMessage()).startsWith("Error encountered when loading your Zowe config.")) {
notification = n;
return true;
}
}

return false;
});
await expect(notification).toBeDefined();
this.configErrorDialog = notification;
await (this.configErrorDialog as Notification).wait();
});

When('the user clicks on the "Show Config" button', async function () {
const button = await this.configErrorDialog.elem.$("a[role='button']");
await expect(button).toBeClickable();
await button.click();
});

Then("the config should appear in the editor", async function () {
const editorView = (this.workbench as Workbench).getEditorView();
await editorView.wait();
await browser.waitUntil(async () => (await editorView.getOpenEditorTitles()).length > 0);
const editorTitles = await editorView.getOpenEditorTitles();
await expect(editorTitles.some((editorTitle) => editorTitle.includes("zowe.config.json"))).toBe(true);
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import * as fs from "fs";
import * as path from "path";
import { AfterAll, Then, When } from "@cucumber/cucumber";
import { paneDivForTree } from "../../../../__common__/shared.wdio";
import { TreeItem } from "wdio-vscode-service";
import quickPick from "../../../../__pageobjects__/QuickPick";
import { Key } from "webdriverio";

Expand Down Expand Up @@ -54,9 +53,17 @@ When(/a user who has profile with (.*) auth in team config/, function (authType:
});
When("the user has a profile in their Data Sets tree", async function () {
this.treePane = await paneDivForTree("Data Sets");
this.profileNode = (await this.treePane.getVisibleItems()).pop() as TreeItem;
await expect(this.profileNode).toBeDefined();
await expect(await this.profileNode.getLabel()).toContain(this.authType);
await browser.waitUntil(async () => {
const visibleItems = await this.treePane.getVisibleItems();
for (const item of visibleItems) {
if ((await item.getLabel()) === `zosmf_${this.authType as string}`) {
this.profileNode = item;
return true;
}
}

return false;
});
});
When("a user clicks search button for the profile", async function () {
await this.profileNode.elem.moveTo();
Expand Down
19 changes: 19 additions & 0 deletions packages/zowe-explorer/__tests__/__integration__/bdd/wdio.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { Options } from "@wdio/types";
import { join as joinPath, resolve as resolvePath } from "path";
import { emptyDirSync } from "fs-extra";
import { baseConfig } from "../../__common__/base.wdio.conf";
import { renameSync, rmSync, writeFileSync } from "fs";

const dataDir = joinPath(__dirname, "..", "..", "__common__", ".wdio-vscode-service", "data");
const screenshotDir = joinPath(__dirname, "results", "screenshots");
Expand Down Expand Up @@ -152,6 +153,24 @@ export const config: Options.Testrunner = {
emptyDirSync(screenshotDir);
},

beforeFeature: async function (uri, feature) {
if (feature.name === "Show Config Error Dialog") {
const configPath = joinPath(process.env["ZOWE_CLI_HOME"], "zowe.config.json");
const backupConfigPath = joinPath(process.env["ZOWE_CLI_HOME"], "zowe.config.bkp");
renameSync(configPath, backupConfigPath);
writeFileSync(configPath, "invalidjson");
}
},

afterFeature: async function (uri, feature) {
if (feature.name === "Show Config Error Dialog") {
const backupConfigPath = joinPath(process.env["ZOWE_CLI_HOME"], "zowe.config.bkp");
const configPath = joinPath(process.env["ZOWE_CLI_HOME"], "zowe.config.json");
rmSync(configPath);
renameSync(backupConfigPath, configPath);
}
},

afterStep: async function (step, scenario, result, context) {
if (!result.passed) {
await browser.saveScreenshot(joinPath(screenshotDir, `${scenario.name} - ${step.text}.png`));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,20 @@ describe("ProfilesUtils unit tests", () => {
};
}

it("should return early if profileInfo is nullish", async () => {
const blockMocks = getBlockMocks();
blockMocks.getValueMock.mockReturnValueOnce(Definitions.V1MigrationStatus.JustMigrated);
blockMocks.setValueMock.mockImplementation();
const getProfInfoMock = jest.spyOn(ProfilesUtils, "getProfileInfo").mockResolvedValue(undefined as any);
const onlyV1ProfilesExistMock = new MockedProperty(imperative.ProfileInfo, "onlyV1ProfilesExist", { get: () => true });
await ProfilesUtils.handleV1MigrationStatus();
expect(getProfInfoMock).toHaveBeenCalled();
expect(onlyV1ProfilesExistMock.mock).not.toHaveBeenCalled();
blockMocks.getValueMock.mockRestore();
blockMocks.setValueMock.mockRestore();
onlyV1ProfilesExistMock[Symbol.dispose]();
});

it("should call executeCommand with zowe.ds.addSession if the migration status is CreateConfigSelected", async () => {
const blockMocks = getBlockMocks();
const executeCommandMock = jest.spyOn(vscode.commands, "executeCommand").mockImplementation();
Expand Down Expand Up @@ -1256,6 +1270,13 @@ describe("ProfilesUtils unit tests", () => {
});

describe("promptUserWithNoConfigs", () => {
it("returns early if profileInfo is nullish", async () => {
const profInfoMock = jest.spyOn(ProfilesUtils, "getProfileInfo").mockResolvedValue(undefined as any);
const showMessageSpy = jest.spyOn(Gui, "showMessage");
await ProfilesUtils.promptUserWithNoConfigs();
expect(showMessageSpy).not.toHaveBeenCalled();
profInfoMock.mockRestore();
});
it("prompts the user if they don't have any Zowe client configs", async () => {
const profInfoMock = jest.spyOn(ProfilesUtils, "getProfileInfo").mockResolvedValue({
getTeamConfig: () => ({ exists: false }),
Expand Down
2 changes: 1 addition & 1 deletion packages/zowe-explorer/src/configuration/Profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ export class Profiles extends ProfilesCache {
Constants.PROFILES_CACHE = Profiles.loader;
try {
await Profiles.loader.refresh(ZoweExplorerApiRegister.getInstance());
await Profiles.getInstance().getProfileInfo();
} catch (err) {
ZoweLogger.error(err);
ZoweExplorerExtender.showZoweConfigError(err.message);
}
await Profiles.getInstance().getProfileInfo();
return Profiles.loader;
}

Expand Down
22 changes: 19 additions & 3 deletions packages/zowe-explorer/src/utils/ProfilesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ export class ProfilesUtils {

/**
* Use the default credential manager in Zowe Explorer and setup before use
* @returns Promise<imperative.ProfileInfo> the object of profileInfo using the default credential manager
* @returns {imperative.ProfileInfo} a ProfileInfo instance using the default credential manager,
* or undefined if an error occurred unrelated to credential manager initialization
*/
public static async setupDefaultCredentialManager(): Promise<imperative.ProfileInfo> {
try {
Expand All @@ -204,6 +205,9 @@ export class ProfilesUtils {
if (err instanceof imperative.ProfInfoErr && err.errorCode === imperative.ProfInfoErr.LOAD_CRED_MGR_FAILED) {
await ProfilesUtils.promptAndDisableCredentialManagement();
}
if (err instanceof Error) {
ZoweLogger.error(err.message);
}
// Ignore other types of errors since they will be handled later
}
}
Expand Down Expand Up @@ -295,6 +299,10 @@ export class ProfilesUtils {
);
}

/**
* Creates an instance of ProfileInfo and calls `readProfilesFromDisk` to load profiles.
* @returns An instance of `ProfileInfo`, or `undefined` if there was an error.
*/
public static async getProfileInfo(): Promise<imperative.ProfileInfo> {
ZoweLogger.trace("ProfilesUtils.getProfileInfo called.");
const hasSecureCredentialManagerEnabled: boolean = SettingsConfig.getDirectValue<boolean>(Constants.SETTINGS_SECURE_CREDENTIALS_ENABLED);
Expand Down Expand Up @@ -367,13 +375,17 @@ export class ProfilesUtils {
// VS Code registers our updated TreeView IDs. Otherwise, VS Code's "Refresh Extensions" option will break v3 init.
const ussPersistentSettings = vscode.workspace.getConfiguration("Zowe-USS-Persistent");
const upgradingFromV1 = ZoweLocalStorage.getValue<Definitions.V1MigrationStatus>(Definitions.LocalStorageKey.V1_MIGRATION_STATUS);
const mProfileInfo = await ProfilesUtils.getProfileInfo();
const profileInfo = await ProfilesUtils.getProfileInfo();
if (profileInfo == null) {
return;
}

if (ussPersistentSettings != null && upgradingFromV1 == null && imperative.ProfileInfo.onlyV1ProfilesExist) {
await ZoweLocalStorage.setValue(Definitions.LocalStorageKey.V1_MIGRATION_STATUS, Definitions.V1MigrationStatus.JustMigrated);
await vscode.commands.executeCommand("workbench.action.reloadWindow");
}

if (upgradingFromV1 == null || mProfileInfo.getTeamConfig().exists || !imperative.ProfileInfo.onlyV1ProfilesExist) {
if (upgradingFromV1 == null || profileInfo.getTeamConfig().exists || !imperative.ProfileInfo.onlyV1ProfilesExist) {
return;
}
const userSelection = await this.v1ProfileOptions();
Expand All @@ -391,6 +403,10 @@ export class ProfilesUtils {
*/
public static async promptUserWithNoConfigs(): Promise<void> {
const profInfo = await ProfilesUtils.getProfileInfo();
if (profInfo == null) {
return;
}

if (!profInfo.getTeamConfig().exists && !imperative.ProfileInfo.onlyV1ProfilesExist) {
Gui.showMessage(
vscode.l10n.t("No Zowe client configurations were detected. Click 'Create New' to create a new Zowe team configuration."),
Expand Down

0 comments on commit 5d2dce4

Please sign in to comment.