From e67a092e4545a822dae9c9c10526fe5baae24c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristina=20Isabel=20Ca=C3=B1izales?= Date: Tue, 20 Aug 2024 15:50:56 -0300 Subject: [PATCH 1/6] fix: ignore expired orgs --- .../src/orgPicker/orgList.ts | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts index 7e730ebc06..d95c8ea1c1 100644 --- a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts +++ b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts @@ -4,7 +4,11 @@ * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { AuthFields, AuthInfo, OrgAuthorization } from '@salesforce/core-bundle'; +import { + AuthFields, + AuthInfo, + OrgAuthorization +} from '@salesforce/core-bundle'; import { CancelResponse, ConfigUtil, @@ -88,23 +92,22 @@ export class OrgList implements vscode.Disposable { // scratch orgs parented by other (non-default) devHub orgs continue; } - const isExpired = - authFields && authFields.expirationDate - ? today >= new Date(authFields.expirationDate) - : false; + const isExpired = authFields?.expirationDate + ? today >= new Date(authFields.expirationDate) + : false; + if (isExpired) { + // authListItem += ` - ${nls.localize( + // 'org_expired' + // )} ${String.fromCodePoint(0x274c)}`; // cross-mark + continue; + } const aliases = await ConfigUtil.getAllAliasesFor(orgAuth.username); - let authListItem = - aliases && aliases.length > 0 + const authListItem = + aliases?.length > 0 ? `${aliases.join(',')} - ${orgAuth.username}` : orgAuth.username; - if (isExpired) { - authListItem += ` - ${nls.localize( - 'org_expired' - )} ${String.fromCodePoint(0x274c)}`; // cross-mark - } - authList.push(authListItem); } return authList; @@ -112,7 +115,7 @@ export class OrgList implements vscode.Disposable { public async updateOrgList(): Promise { const orgAuthorizations = await this.getOrgAuthorizations(); - if (orgAuthorizations && orgAuthorizations.length === 0) { + if (orgAuthorizations?.length === 0) { return []; } const authUsernameList = await this.filterAuthInfo(orgAuthorizations); From 05c32812a0f8c21b813960363511ee99a56952e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristina=20Isabel=20Ca=C3=B1izales?= Date: Wed, 21 Aug 2024 21:28:38 -0300 Subject: [PATCH 2/6] chore: remove commented code and typo --- .../src/context/workspaceContextUtil.ts | 2 +- packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/salesforcedx-utils-vscode/src/context/workspaceContextUtil.ts b/packages/salesforcedx-utils-vscode/src/context/workspaceContextUtil.ts index 3176ce2c77..a465eb8251 100644 --- a/packages/salesforcedx-utils-vscode/src/context/workspaceContextUtil.ts +++ b/packages/salesforcedx-utils-vscode/src/context/workspaceContextUtil.ts @@ -100,7 +100,7 @@ export class WorkspaceContextUtil { this._orgId = ''; if (error instanceof Error) { console.log( - 'There was an problem getting the orgId of the default org: ', + 'There was a problem getting the orgId of the default org: ', error ); TelemetryService.getInstance().sendException( diff --git a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts index d95c8ea1c1..8bc23fae40 100644 --- a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts +++ b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts @@ -97,9 +97,7 @@ export class OrgList implements vscode.Disposable { : false; if (isExpired) { - // authListItem += ` - ${nls.localize( - // 'org_expired' - // )} ${String.fromCodePoint(0x274c)}`; // cross-mark + // If the scratch org is expired we don't want to see it in the org picker continue; } const aliases = await ConfigUtil.getAllAliasesFor(orgAuth.username); From 91cfd05036d35ef16bdd865a9703449806ce185a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristina=20Isabel=20Ca=C3=B1izales?= Date: Wed, 21 Aug 2024 21:47:34 -0300 Subject: [PATCH 3/6] test: update int test --- .../orgPicker/orgList.test.ts | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts b/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts index 73d75a357a..ebf6d3d5bf 100644 --- a/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts +++ b/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts @@ -4,7 +4,11 @@ * Licensed under the BSD 3-Clause license. * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { AuthInfo, OrgAuthorization, StateAggregator } from '@salesforce/core-bundle'; +import { + AuthInfo, + OrgAuthorization, + StateAggregator +} from '@salesforce/core-bundle'; import { ConfigUtil } from '@salesforce/salesforcedx-utils-vscode'; import { expect } from 'chai'; import { createSandbox, SinonStub } from 'sinon'; @@ -245,7 +249,7 @@ describe('orgList Tests', () => { expect(authList[0]).to.equal('alias1 - test-username1@example.com'); }); - it('should flag the org as expired if expiration date has passed', async () => { + it('should filter the list to ignore expired orgs', async () => { const oneDayMillis = 60 * 60 * 24 * 1000; const today = new Date(); const yesterday = new Date(today.getTime() - oneDayMillis); @@ -290,19 +294,11 @@ describe('orgList Tests', () => { const authList = await orgList.filterAuthInfo(authInfoObjects); - expect(authList[0]).to.equal( - 'test-scratchorg-today@example.com - ' + - nls.localize('org_expired') + - ' ' + - String.fromCodePoint(0x274c) + expect(authList).to.not.contain('test-scratchorg-today@example.com'); + expect(authList).to.not.contain( + 'test-scratchorg-yesterday@example.com' ); - expect(authList[1]).to.equal( - 'test-scratchorg-yesterday@example.com - ' + - nls.localize('org_expired') + - ' ' + - String.fromCodePoint(0x274c) - ); - expect(authList[2]).to.equal('test-scratchorg-tomorrow@example.com'); + expect(authList[0]).to.equal('test-scratchorg-tomorrow@example.com'); }); }); describe('Set Default Org', () => { From ca6afa61a76b922dcda60c8611f93dfba0e706bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristina=20Isabel=20Ca=C3=B1izales?= Date: Thu, 22 Aug 2024 11:54:47 -0300 Subject: [PATCH 4/6] chore: remove code not needed --- .../src/orgPicker/orgList.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts index 8bc23fae40..3c3a624150 100644 --- a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts +++ b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts @@ -65,7 +65,6 @@ export class OrgList implements vscode.Disposable { const targetDevHub = await OrgAuthInfo.getDevHubUsername(); const authList = []; - const today = new Date(); for (const orgAuth of orgAuthorizations) { // When this is called right after logging out of an org, there can // still be a cached Org Auth in the list with a "No auth information found" @@ -92,11 +91,8 @@ export class OrgList implements vscode.Disposable { // scratch orgs parented by other (non-default) devHub orgs continue; } - const isExpired = authFields?.expirationDate - ? today >= new Date(authFields.expirationDate) - : false; - if (isExpired) { + if (orgAuth.isExpired === true) { // If the scratch org is expired we don't want to see it in the org picker continue; } @@ -112,11 +108,9 @@ export class OrgList implements vscode.Disposable { } public async updateOrgList(): Promise { - const orgAuthorizations = await this.getOrgAuthorizations(); - if (orgAuthorizations?.length === 0) { - return []; - } - const authUsernameList = await this.filterAuthInfo(orgAuthorizations); + const authUsernameList = await this.filterAuthInfo( + await this.getOrgAuthorizations() + ); return authUsernameList; } From bbfaf368fe0d04464850acdcf5a94f1d3044b4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristina=20Isabel=20Ca=C3=B1izales?= Date: Thu, 22 Aug 2024 16:57:41 -0300 Subject: [PATCH 5/6] chore: use org.aliases instead of fetching them and update tests --- .../src/orgPicker/orgList.ts | 3 +- .../orgPicker/orgList.test.ts | 31 +++++++++---------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts index 3c3a624150..258024fa6b 100644 --- a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts +++ b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts @@ -11,7 +11,6 @@ import { } from '@salesforce/core-bundle'; import { CancelResponse, - ConfigUtil, ContinueResponse, OrgUserInfo } from '@salesforce/salesforcedx-utils-vscode'; @@ -96,7 +95,7 @@ export class OrgList implements vscode.Disposable { // If the scratch org is expired we don't want to see it in the org picker continue; } - const aliases = await ConfigUtil.getAllAliasesFor(orgAuth.username); + const aliases = orgAuth.aliases || []; const authListItem = aliases?.length > 0 ? `${aliases.join(',')} - ${orgAuth.username}` diff --git a/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts b/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts index ebf6d3d5bf..589d912bff 100644 --- a/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts +++ b/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts @@ -39,8 +39,8 @@ describe('orgList Tests', () => { it('should return a list of FileInfo objects when given an array of file names', async () => { // Arrange const authFilesArray = [ - { username: 'test-username1@example.com' }, - { username: 'test-username2@example.com' } + { username: 'test-username1@example.com', aliases: ['alias1'] }, + { username: 'test-username2@example.com', aliases: ['alias2'] } ]; getAuthInfoListAllAuthorizationsStub.resolves(authFilesArray); const orgList = new OrgList(); @@ -71,7 +71,6 @@ describe('orgList Tests', () => { let getUsernameStub: SinonStub; let stateAggregatorCreateStub: SinonStub; let getAllStub: SinonStub; - let getAllAliasesForStub: SinonStub; let getAuthFieldsForStub: SinonStub; const orgList = new OrgList(); @@ -91,7 +90,6 @@ describe('orgList Tests', () => { .stub(StateAggregator, 'create') .resolves(fakeStateAggregator); - getAllAliasesForStub = sandbox.stub(ConfigUtil, 'getAllAliasesFor'); getAuthFieldsForStub = sandbox.stub( OrgList.prototype, 'getAuthFieldsFor' @@ -120,7 +118,8 @@ describe('orgList Tests', () => { const dummyOrgAuth1 = getFakeOrgAuthorization({ orgId: '000', - username: 'test-username1@example.com' + username: 'test-username1@example.com', + aliases: ['alias1'] }); const dummyOrgAuth2 = getFakeOrgAuthorization({ orgId: '111', @@ -133,13 +132,15 @@ describe('orgList Tests', () => { }); const dummyScratchOrgAuth2 = getFakeOrgAuthorization({ orgId: '111', - username: 'test-scratchorg2@example.com' + username: 'test-scratchorg2@example.com', + aliases: ['anAlias'] }); const dummyScratchOrgAuthWithError = getFakeOrgAuthorization({ orgId: '222', username: 'test-scratchorg3@example.com', error: - 'No authorization information found for test-scratchorg3@example.com.' + 'No authorization information found for test-scratchorg3@example.com.', + aliases: ['anAlias'] }); const dummyDevHubUsername1 = 'test-devhub1@example.com'; @@ -213,9 +214,6 @@ describe('orgList Tests', () => { .returns({ devHubUsername: dummyDevHubUsername1 }); - getAllAliasesForStub - .withArgs(authInfoObjectsWithOneError[0].username) - .returns([AN_ALIAS]); getDevHubUsernameStub.resolves(dummyDevHubUsername1); const authList = await orgList.filterAuthInfo( @@ -223,7 +221,6 @@ describe('orgList Tests', () => { ); expect(getDevHubUsernameStub.calledOnce).to.equal(true); expect(authList.length).to.equal(1); - expect(authList[0].includes(AN_ALIAS)).to.equal(true); expect(authList[0].includes(dummyScratchOrgAuth1.username)).to.equal( true ); @@ -237,9 +234,6 @@ describe('orgList Tests', () => { dummyOrgAuth2 ]; getAllStub.withArgs(dummyOrgAuth1.username).returns(['alias1']); - getAllAliasesForStub - .withArgs(dummyOrgAuth1.username) - .returns(['alias1']); getAuthFieldsForStub.withArgs(authInfoObjects[0].username).returns({}); // Act @@ -258,15 +252,18 @@ describe('orgList Tests', () => { const authInfoObjects: OrgAuthorization[] = [ getFakeOrgAuthorization({ orgId: '000', - username: 'test-scratchorg-today@example.com' + username: 'test-scratchorg-today@example.com', + isExpired: true }), getFakeOrgAuthorization({ orgId: '111', - username: 'test-scratchorg-yesterday@example.com' + username: 'test-scratchorg-yesterday@example.com', + isExpired: true }), getFakeOrgAuthorization({ orgId: '222', - username: 'test-scratchorg-tomorrow@example.com' + username: 'test-scratchorg-tomorrow@example.com', + isExpired: false }) ]; From 838ef09a3b3b69ed7019ebe37fdc023594d942fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristina=20Isabel=20Ca=C3=B1izales?= Date: Thu, 22 Aug 2024 19:37:21 -0300 Subject: [PATCH 6/6] test: add jest test for OrgList.filterAuthInfo() --- .../src/orgPicker/orgList.ts | 2 +- .../test/jest/orgPicker/orgPicker.test.ts | 144 ++++++++++++++++++ .../orgPicker/orgList.test.ts | 2 - 3 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 packages/salesforcedx-vscode-core/test/jest/orgPicker/orgPicker.test.ts diff --git a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts index 258024fa6b..e5a9d2ee68 100644 --- a/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts +++ b/packages/salesforcedx-vscode-core/src/orgPicker/orgList.ts @@ -97,7 +97,7 @@ export class OrgList implements vscode.Disposable { } const aliases = orgAuth.aliases || []; const authListItem = - aliases?.length > 0 + aliases.length > 0 ? `${aliases.join(',')} - ${orgAuth.username}` : orgAuth.username; diff --git a/packages/salesforcedx-vscode-core/test/jest/orgPicker/orgPicker.test.ts b/packages/salesforcedx-vscode-core/test/jest/orgPicker/orgPicker.test.ts new file mode 100644 index 0000000000..4f652cdc86 --- /dev/null +++ b/packages/salesforcedx-vscode-core/test/jest/orgPicker/orgPicker.test.ts @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2024, salesforce.com, inc. + * All rights reserved. + * Licensed under the BSD 3-Clause license. + * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause + */ +import { AuthFields, OrgAuthorization } from '@salesforce/core-bundle'; +import * as vscode from 'vscode'; +import { OrgList } from '../../../src/orgPicker'; +import { OrgAuthInfo } from '../../../src/util'; + +describe('OrgList - filterAuthInfo', () => { + let orgList: OrgList; + let createFileSystemWatcherMock: jest.SpyInstance; + let getDevHubUsernameMock: jest.SpyInstance; + let getAuthFieldsForMock: jest.SpyInstance; + let mockWatcher: any; + + const dummyDevHubUsername = 'test-devhub@example.com'; + + const createOrgAuthorization = ( + overrides: Partial = {} + ): OrgAuthorization => ({ + orgId: '000', + username: 'test-username@example.com', + oauthMethod: 'unknown', + aliases: [], + configs: [], + isScratchOrg: undefined, + isDevHub: undefined, + isSandbox: undefined, + instanceUrl: undefined, + accessToken: undefined, + error: undefined, + isExpired: false, + ...overrides + }); + + beforeEach(() => { + mockWatcher = { + onDidChange: jest.fn(), + onDidCreate: jest.fn(), + onDidDelete: jest.fn() + }; + createFileSystemWatcherMock = ( + vscode.workspace.createFileSystemWatcher as any + ).mockReturnValue(mockWatcher); + (vscode.window.createStatusBarItem as jest.Mock).mockReturnValue({ + command: '', + text: '', + tooltip: '', + show: jest.fn(), + dispose: jest.fn() + }); + orgList = new OrgList(); + getAuthFieldsForMock = jest.spyOn(OrgList.prototype, 'getAuthFieldsFor'); + getDevHubUsernameMock = jest.spyOn(OrgAuthInfo, 'getDevHubUsername'); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should filter out orgs with the scratchAdminUsername field', async () => { + const orgAuth = createOrgAuthorization(); + const orgAuths = [orgAuth]; + getAuthFieldsForMock.mockResolvedValueOnce({ + scratchAdminUsername: 'admin@example.com' + } as AuthFields); + getDevHubUsernameMock.mockResolvedValueOnce(null); + + const result = await orgList.filterAuthInfo(orgAuths); + + expect(result).toEqual([]); + }); + + it('should filter out scratch orgs parented by non-default Dev Hubs', async () => { + const orgAuth = createOrgAuthorization({ isScratchOrg: true }); + const orgAuths = [orgAuth]; + getAuthFieldsForMock.mockResolvedValueOnce({ + devHubUsername: 'other-devhub@example.com' + } as AuthFields); + getDevHubUsernameMock.mockResolvedValueOnce(dummyDevHubUsername); + + const result = await orgList.filterAuthInfo(orgAuths); + + expect(result).toEqual([]); + }); + + it('should filter out expired orgs', async () => { + const expiredOrgAuth = createOrgAuthorization({ + username: 'expired-org@example.com', + isExpired: true + }); + const orgAuths = [expiredOrgAuth]; + getAuthFieldsForMock.mockResolvedValueOnce({} as AuthFields); + getDevHubUsernameMock.mockResolvedValueOnce(dummyDevHubUsername); + + const result = await orgList.filterAuthInfo(orgAuths); + + expect(result).toEqual([]); + }); + + it('should include aliases in the result if available', async () => { + const orgAuth = createOrgAuthorization({ + username: 'test-username@example.com', + aliases: ['alias1'] + }); + const orgAuths = [orgAuth]; + getAuthFieldsForMock.mockResolvedValueOnce({} as AuthFields); + getDevHubUsernameMock.mockResolvedValueOnce(null); + + const result = await orgList.filterAuthInfo(orgAuths); + + expect(result).toEqual(['alias1 - test-username@example.com']); + }); + + it('should filter out org authorizations with errors', async () => { + const orgAuthWithError = createOrgAuthorization({ + username: 'error-org@example.com', + error: 'Some error' + }); + const orgAuths = [orgAuthWithError]; + getAuthFieldsForMock.mockResolvedValueOnce({} as AuthFields); + getDevHubUsernameMock.mockResolvedValueOnce(null); + + const result = await orgList.filterAuthInfo(orgAuths); + + expect(result).toEqual([]); + }); + + it('should return a list of valid org authorizations', async () => { + const validOrgAuth = createOrgAuthorization({ + username: 'valid-org@example.com' + }); + const orgAuths = [validOrgAuth]; + getAuthFieldsForMock.mockResolvedValueOnce({} as AuthFields); + getDevHubUsernameMock.mockResolvedValueOnce(dummyDevHubUsername); + + const result = await orgList.filterAuthInfo(orgAuths); + + expect(result).toEqual(['valid-org@example.com']); + }); +}); diff --git a/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts b/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts index 589d912bff..fa7ed98811 100644 --- a/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts +++ b/packages/salesforcedx-vscode-core/test/vscode-integration/orgPicker/orgList.test.ts @@ -9,7 +9,6 @@ import { OrgAuthorization, StateAggregator } from '@salesforce/core-bundle'; -import { ConfigUtil } from '@salesforce/salesforcedx-utils-vscode'; import { expect } from 'chai'; import { createSandbox, SinonStub } from 'sinon'; import * as vscode from 'vscode'; @@ -18,7 +17,6 @@ import { OrgList } from '../../../src/orgPicker'; import * as util from '../../../src/util'; import { OrgAuthInfo } from '../../../src/util'; -const AN_ALIAS = 'anAlias'; const sandbox = createSandbox(); describe('orgList Tests', () => {