@salesforce/core 3.30.13 → 3.31.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -33,12 +33,11 @@ Here you can mock authorization for a Salesforce scratch org.
33
33
 
34
34
  ```typescript
35
35
  import { strictEqual } from 'assert';
36
- import { MockTestOrgData, testSetup } from '@salesforce/core/lib/testSetup';
36
+ import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup';
37
37
  import { AuthInfo } from '@salesforce/core';
38
38
 
39
- const $$ = testSetup();
40
-
41
39
  describe('Mocking Auth data', () => {
40
+ const $$ = new TestContext();
42
41
  it('example', async () => {
43
42
  const testData = new MockTestOrgData();
44
43
  await $$.stubAuths(testData);
@@ -52,15 +51,14 @@ After having a valid AuthInfo object you can then create fake connections to a S
52
51
 
53
52
  ```typescript
54
53
  import { AuthInfo, Connection, SfError } from '@salesforce/core';
55
- import { MockTestOrgData, testSetup } from '@salesforce/core/lib/testSetup';
54
+ import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup';
56
55
  import { AnyJson, ensureJsonMap, JsonMap } from '@salesforce/ts-types';
57
56
  import { ensureString } from '@salesforce/ts-types';
58
57
  import { deepStrictEqual } from 'assert';
59
58
  import { QueryResult } from 'jsforce';
60
59
 
61
- const $$ = testSetup();
62
-
63
60
  describe('Mocking a force server call', () => {
61
+ const $$ = new TestContext();
64
62
  it('example', async () => {
65
63
  const records: AnyJson = { records: ['123456', '234567'] };
66
64
  const testData = new MockTestOrgData();
@@ -88,12 +86,11 @@ You can mock the contents of various config files
88
86
 
89
87
  ```typescript
90
88
  import { strictEqual } from 'assert';
91
- import { MockTestOrgData, testSetup } from '@salesforce/core/lib/testSetup';
89
+ import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup';
92
90
  import { StateAggregator, OrgConfigProperties } from '@salesforce/core';
93
91
 
94
- const $$ = testSetup();
95
-
96
92
  describe('Mocking Aliases', () => {
93
+ const $$ = new TestContext();
97
94
  it('example', async () => {
98
95
  const testData = new MockTestOrgData();
99
96
  await $$.stubAliases({ myAlias: testData.username });
@@ -128,12 +125,11 @@ Sinon `stub`s and `spy`s must be cleaned up after test invocations. To ease the
128
125
  ```typescript
129
126
  import { strictEqual } from 'assert';
130
127
 
131
- import { testSetup } from '@salesforce/core/lib/testSetup';
128
+ import { TestContext } from '@salesforce/core/lib/testSetup';
132
129
  import * as os from 'os';
133
130
 
134
- const $$ = testSetup();
135
-
136
131
  describe('Using the built in Sinon sandbox.', () => {
132
+ const $$ = new TestContext();
137
133
  it('example', async () => {
138
134
  const unsupportedOS = 'LEO';
139
135
  $$.SANDBOX.stub(os, 'platform').returns(unsupportedOS);
@@ -198,11 +194,9 @@ It's also useful to check expected values and content from log lines. TestSetup
198
194
 
199
195
  ```typescript
200
196
  import { Logger, LogLine } from '@salesforce/core';
201
- import { testSetup } from '@salesforce/core/lib/testSetup';
197
+ import { TestContext } from '@salesforce/core/lib/testSetup';
202
198
  import { strictEqual } from 'assert';
203
199
 
204
- const $$ = testSetup();
205
-
206
200
  const TEST_STRING = 'foo was here';
207
201
 
208
202
  class TestObject {
@@ -216,6 +210,7 @@ class TestObject {
216
210
  }
217
211
 
218
212
  describe('Testing log lines', () => {
213
+ const $$ = new TestContext();
219
214
  it('example', async () => {
220
215
  const obj = new TestObject($$.TEST_LOGGER);
221
216
  obj.method();
@@ -39,7 +39,7 @@ export declare class TokenAccessor extends AsyncOptionalCreatable {
39
39
  * @param name
40
40
  * @param token
41
41
  */
42
- set(name: string, token: SfToken): void;
42
+ set(name: string, token: Partial<SfToken>): void;
43
43
  /**
44
44
  * Update the token for the provided name.
45
45
  *
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { EventEmitter } from 'events';
3
- import * as sinonType from 'sinon';
3
+ import { SinonSandbox, SinonStatic, SinonStub } from 'sinon';
4
4
  import { AnyJson, JsonMap, Optional } from '@salesforce/ts-types';
5
5
  import { ConfigContents } from './config/configStore';
6
6
  import { Connection } from './org/connection';
@@ -15,13 +15,13 @@ import { AliasGroup } from './config/aliasesConfig';
15
15
  * on the TestContext.
16
16
  */
17
17
  export interface SandboxTypes {
18
- DEFAULT: sinon.SinonSandbox;
19
- CRYPTO: sinon.SinonSandbox;
20
- CONFIG: sinon.SinonSandbox;
21
- PROJECT: sinon.SinonSandbox;
22
- CONNECTION: sinon.SinonSandbox;
23
- FS: sinonType.SinonSandbox;
24
- ORGS: sinonType.SinonSandbox;
18
+ DEFAULT: SinonSandbox;
19
+ CRYPTO: SinonSandbox;
20
+ CONFIG: SinonSandbox;
21
+ PROJECT: SinonSandbox;
22
+ CONNECTION: SinonSandbox;
23
+ FS: SinonSandbox;
24
+ ORGS: SinonSandbox;
25
25
  }
26
26
  /**
27
27
  * Different hooks into {@link ConfigFile} used for testing instead of doing file IO.
@@ -55,15 +55,15 @@ export interface ConfigStub {
55
55
  updateContents?: () => Promise<JsonMap>;
56
56
  }
57
57
  /**
58
- * Different configuration options when running before each
58
+ * Instantiate a @salesforce/core test context.
59
59
  */
60
- export interface TestContext {
60
+ export declare class TestContext {
61
61
  /**
62
62
  * The default sandbox is cleared out before each test run.
63
63
  *
64
- * **See** [sinon sandbox]{@link http://sinonjs.org/releases/v1.17.7/sandbox/}.
64
+ * **See** [sinon sandbox]{@link https://sinonjs.org/releases/v14/sandbox/}.
65
65
  */
66
- SANDBOX: sinonType.SinonSandbox;
66
+ SANDBOX: SinonSandbox;
67
67
  /**
68
68
  * An object of different sandboxes. Used when
69
69
  * needing to restore parts of the system for customized testing.
@@ -77,10 +77,6 @@ export interface TestContext {
77
77
  * id A unique id for the test run.
78
78
  */
79
79
  id: string;
80
- /**
81
- * A function that returns unique strings.
82
- */
83
- uniqid: () => string;
84
80
  /**
85
81
  * An object used in tests that interact with config files.
86
82
  */
@@ -93,54 +89,56 @@ export interface TestContext {
93
89
  TokensConfig?: ConfigStub;
94
90
  };
95
91
  /**
96
- * An record of stubs created during instantaion.
92
+ * A record of stubs created during instantiation.
97
93
  */
98
- stubs: {
99
- configRead?: sinonType.SinonStub;
100
- configReadSync?: sinonType.SinonStub;
101
- configWriteSync?: sinonType.SinonStub;
102
- configWrite?: sinonType.SinonStub;
103
- configExists?: sinonType.SinonStub;
104
- configRemove?: sinonType.SinonStub;
105
- };
94
+ stubs: Record<string, SinonStub>;
95
+ constructor(options?: {
96
+ sinon?: SinonStatic;
97
+ sandbox?: SinonSandbox;
98
+ setup?: boolean;
99
+ });
100
+ /**
101
+ * Generate unique string.
102
+ */
103
+ uniqid(): string;
106
104
  /**
107
105
  * A function used when resolving the local path. Calls localPathResolverSync by default.
108
106
  *
109
107
  * @param uid Unique id.
110
108
  */
111
- localPathRetriever: (uid: string) => Promise<string>;
109
+ localPathRetriever(uid: string): Promise<string>;
112
110
  /**
113
111
  * A function used when resolving the local path.
114
112
  *
115
113
  * @param uid Unique id.
116
114
  */
117
- localPathRetrieverSync: (uid: string) => string;
115
+ localPathRetrieverSync(uid: string): string;
118
116
  /**
119
117
  * A function used when resolving the global path. Calls globalPathResolverSync by default.
120
118
  *
121
119
  * @param uid Unique id.
122
120
  */
123
- globalPathRetriever: (uid: string) => Promise<string>;
121
+ globalPathRetriever(uid: string): Promise<string>;
124
122
  /**
125
123
  * A function used when resolving the global path.
126
124
  *
127
125
  * @param uid Unique id.
128
126
  */
129
- globalPathRetrieverSync: (uid: string) => string;
127
+ globalPathRetrieverSync(uid: string): string;
130
128
  /**
131
129
  * A function used for resolving paths. Calls localPathRetriever and globalPathRetriever.
132
130
  *
133
131
  * @param isGlobal `true` if the config is global.
134
132
  * @param uid user id.
135
133
  */
136
- rootPathRetriever: (isGlobal: boolean, uid?: string) => Promise<string>;
134
+ rootPathRetriever(isGlobal: boolean, uid?: string): Promise<string>;
137
135
  /**
138
136
  * A function used for resolving paths. Calls localPathRetrieverSync and globalPathRetrieverSync.
139
137
  *
140
138
  * @param isGlobal `true` if the config is global.
141
139
  * @param uid user id.
142
140
  */
143
- rootPathRetrieverSync: (isGlobal: boolean, uid?: string) => string;
141
+ rootPathRetrieverSync(isGlobal: boolean, uid?: string): string;
144
142
  /**
145
143
  * Used to mock http request to Salesforce.
146
144
  *
@@ -149,7 +147,7 @@ export interface TestContext {
149
147
  *
150
148
  * **See** {@link Connection.request}
151
149
  */
152
- fakeConnectionRequest: (request: AnyJson, options?: AnyJson) => Promise<AnyJson>;
150
+ fakeConnectionRequest(request: AnyJson, options?: AnyJson): Promise<AnyJson>;
153
151
  /**
154
152
  * Gets a config stub contents by name.
155
153
  *
@@ -167,7 +165,7 @@ export interface TestContext {
167
165
  /**
168
166
  * Set stubs for working in the context of a SfProject
169
167
  */
170
- inProject(inProject: boolean): void;
168
+ inProject(inProject?: boolean): void;
171
169
  /**
172
170
  * Stub salesforce org authorizations.
173
171
  */
@@ -175,7 +173,7 @@ export interface TestContext {
175
173
  /**
176
174
  * Stub salesforce sandbox authorizations.
177
175
  */
178
- stubSandboxes(...orgs: MockTestSandboxData[]): Promise<void>;
176
+ stubSandboxes(...sandboxes: MockTestSandboxData[]): Promise<void>;
179
177
  /**
180
178
  * Stub the aliases in the global aliases config file.
181
179
  */
@@ -188,6 +186,14 @@ export interface TestContext {
188
186
  * Stub the tokens in the global token config file.
189
187
  */
190
188
  stubTokens(tokens: Record<string, string>): void;
189
+ restore(): void;
190
+ init(): void;
191
+ /**
192
+ * Add beforeEach and afterEach hooks to init the stubs and restore them.
193
+ * This is called automatically when the class is instantiated unless the setup option is set to false.
194
+ */
195
+ setup(): void;
196
+ private requireSinon;
191
197
  }
192
198
  /**
193
199
  * A function to generate a unique id and return it in the context of a template, if supplied.
@@ -215,16 +221,16 @@ export declare function uniqid(options?: {
215
221
  * const $$ = instantiateContext();
216
222
  *
217
223
  * beforeEach(() => {
218
- * stubContext($$);
224
+ * $$.init()
219
225
  * });
220
226
  *
221
227
  * afterEach(() => {
222
- * restoreContext($$);
228
+ * $$.restore();
223
229
  * });
224
230
  * ```
225
231
  * @param sinon
226
232
  */
227
- export declare const instantiateContext: (sinon?: any) => TestContext;
233
+ export declare const instantiateContext: (sinon?: SinonStatic) => TestContext;
228
234
  /**
229
235
  * Stub a @salesforce/core test context. This will mock out logging to a file, config file reading and writing,
230
236
  * local and global path resolution, and http request using connection (soon)*.
@@ -240,16 +246,16 @@ export declare const instantiateContext: (sinon?: any) => TestContext;
240
246
  * const $$ = instantiateContext();
241
247
  *
242
248
  * beforeEach(() => {
243
- * stubContext($$);
249
+ * $$.init()
244
250
  * });
245
251
  *
246
252
  * afterEach(() => {
247
- * restoreContext($$);
253
+ * $$.restore();
248
254
  * });
249
255
  * ```
250
256
  * @param testContext
251
257
  */
252
- export declare const stubContext: (testContext: TestContext) => Record<string, sinonType.SinonStub>;
258
+ export declare const stubContext: (testContext: TestContext) => Record<string, SinonStub>;
253
259
  /**
254
260
  * Restore a @salesforce/core test context. This is automatically stubbed in the global beforeEach created by
255
261
  * `const $$ = testSetup()` but is useful if you don't want to have a global stub of @salesforce/core and you
@@ -260,23 +266,40 @@ export declare const stubContext: (testContext: TestContext) => Record<string, s
260
266
  * const $$ = instantiateContext();
261
267
  *
262
268
  * beforeEach(() => {
263
- * stubContext($$);
269
+ * $$.init()
264
270
  * });
265
271
  *
266
272
  * afterEach(() => {
267
- * restoreContext($$);
273
+ * $$.restore();
268
274
  * });
269
275
  * ```
270
276
  * @param testContext
271
277
  */
272
278
  export declare const restoreContext: (testContext: TestContext) => void;
273
279
  /**
280
+ * @deprecated Use TestContext instead.
281
+ * Using testSetup will create globals stubs that could lead to erratic test behavior.
282
+ *
283
+ * This example shows you how to use TestContext:
284
+ * @example
285
+ * ```
286
+ * const $$ = new TestContext();
287
+ *
288
+ * beforeEach(() => {
289
+ * $$.init();
290
+ * });
291
+ *
292
+ * afterEach(() => {
293
+ * $$.restore();
294
+ * });
295
+ * ```
296
+ *
274
297
  * Use to mock out different pieces of sfdx-core to make testing easier. This will mock out
275
298
  * logging to a file, config file reading and writing, local and global path resolution, and
276
299
  * *http request using connection (soon)*.
277
300
  *
278
301
  * **Note:** The testSetup should be outside of the describe. If you need to stub per test, use
279
- * `instantiateContext`, `stubContext`, and `restoreContext`.
302
+ * `TestContext`.
280
303
  * ```
281
304
  * // In a mocha tests
282
305
  * import testSetup from '@salesforce/core/lib/testSetup';
@@ -292,13 +315,13 @@ export declare const restoreContext: (testContext: TestContext) => void;
292
315
  * $$.stubAliases({ 'myTestAlias': 'user@company.com' });
293
316
  *
294
317
  * // Will use the contents set above.
295
- * const username = (await StateAggregator.getInstance()).aliases.resolveUseranme('myTestAlias');
318
+ * const username = (await StateAggregator.getInstance()).aliases.resolveUsername('myTestAlias');
296
319
  * expect(username).to.equal('user@company.com');
297
320
  * });
298
321
  * });
299
322
  * ```
300
323
  */
301
- export declare const testSetup: (sinon?: any) => TestContext;
324
+ export declare const testSetup: (sinon?: SinonStatic) => TestContext;
302
325
  /**
303
326
  * A pre-canned error for try/catch testing.
304
327
  *
package/lib/testSetup.js CHANGED
@@ -11,7 +11,7 @@
11
11
  /* eslint-disable @typescript-eslint/no-unsafe-member-access */
12
12
  /* eslint-disable @typescript-eslint/no-unsafe-call */
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.MockTestSandboxData = exports.MockTestOrgData = exports.StreamingMockCometClient = exports.StreamingMockCometSubscription = exports.StreamingMockSubscriptionCall = exports.shouldThrowSync = exports.shouldThrow = exports.unexpectedResult = exports.testSetup = exports.restoreContext = exports.stubContext = exports.instantiateContext = exports.uniqid = void 0;
14
+ exports.MockTestSandboxData = exports.MockTestOrgData = exports.StreamingMockCometClient = exports.StreamingMockCometSubscription = exports.StreamingMockSubscriptionCall = exports.shouldThrowSync = exports.shouldThrow = exports.unexpectedResult = exports.testSetup = exports.restoreContext = exports.stubContext = exports.instantiateContext = exports.uniqid = exports.TestContext = void 0;
15
15
  const crypto_1 = require("crypto");
16
16
  const events_1 = require("events");
17
17
  const os_1 = require("os");
@@ -34,6 +34,234 @@ const org_1 = require("./org");
34
34
  const sandboxAccessor_1 = require("./stateAggregator/accessors/sandboxAccessor");
35
35
  const aliasesConfig_1 = require("./config/aliasesConfig");
36
36
  const global_1 = require("./global");
37
+ /**
38
+ * Instantiate a @salesforce/core test context.
39
+ */
40
+ class TestContext {
41
+ constructor(options = {}) {
42
+ /**
43
+ * id A unique id for the test run.
44
+ */
45
+ this.id = uniqid();
46
+ /**
47
+ * An object used in tests that interact with config files.
48
+ */
49
+ this.configStubs = {};
50
+ /**
51
+ * A record of stubs created during instantiation.
52
+ */
53
+ this.stubs = {};
54
+ const opts = { setup: true, ...options };
55
+ const sinon = this.requireSinon(opts.sinon);
56
+ // Import all the messages files in the sfdx-core messages dir.
57
+ messages_1.Messages.importMessagesDirectory((0, path_1.join)(__dirname));
58
+ // Create a global sinon sandbox and a test logger instance for use within tests.
59
+ this.SANDBOX = opts.sandbox ?? sinon.createSandbox();
60
+ this.SANDBOXES = {
61
+ DEFAULT: this.SANDBOX,
62
+ CONFIG: sinon.createSandbox(),
63
+ PROJECT: sinon.createSandbox(),
64
+ CRYPTO: sinon.createSandbox(),
65
+ CONNECTION: sinon.createSandbox(),
66
+ FS: sinon.createSandbox(),
67
+ ORGS: sinon.createSandbox(),
68
+ };
69
+ this.TEST_LOGGER = new logger_1.Logger({ name: 'SFDX_Core_Test_Logger' }).useMemoryLogging();
70
+ if (opts.setup) {
71
+ this.setup();
72
+ }
73
+ }
74
+ /**
75
+ * Generate unique string.
76
+ */
77
+ uniqid() {
78
+ return uniqid();
79
+ }
80
+ /**
81
+ * A function used when resolving the local path. Calls localPathResolverSync by default.
82
+ *
83
+ * @param uid Unique id.
84
+ */
85
+ async localPathRetriever(uid) {
86
+ return Promise.resolve(getTestLocalPath(uid));
87
+ }
88
+ /**
89
+ * A function used when resolving the local path.
90
+ *
91
+ * @param uid Unique id.
92
+ */
93
+ localPathRetrieverSync(uid) {
94
+ return getTestLocalPath(uid);
95
+ }
96
+ /**
97
+ * A function used when resolving the global path. Calls globalPathResolverSync by default.
98
+ *
99
+ * @param uid Unique id.
100
+ */
101
+ async globalPathRetriever(uid) {
102
+ return Promise.resolve(getTestGlobalPath(uid));
103
+ }
104
+ /**
105
+ * A function used when resolving the global path.
106
+ *
107
+ * @param uid Unique id.
108
+ */
109
+ globalPathRetrieverSync(uid) {
110
+ return getTestGlobalPath(uid);
111
+ }
112
+ /**
113
+ * A function used for resolving paths. Calls localPathRetriever and globalPathRetriever.
114
+ *
115
+ * @param isGlobal `true` if the config is global.
116
+ * @param uid user id.
117
+ */
118
+ async rootPathRetriever(isGlobal, uid) {
119
+ return retrieveRootPath(isGlobal, uid);
120
+ }
121
+ /**
122
+ * A function used for resolving paths. Calls localPathRetrieverSync and globalPathRetrieverSync.
123
+ *
124
+ * @param isGlobal `true` if the config is global.
125
+ * @param uid user id.
126
+ */
127
+ rootPathRetrieverSync(isGlobal, uid) {
128
+ return retrieveRootPathSync(isGlobal, uid);
129
+ }
130
+ /**
131
+ * Used to mock http request to Salesforce.
132
+ *
133
+ * @param request An HttpRequest.
134
+ * @param options Additional options.
135
+ *
136
+ * **See** {@link Connection.request}
137
+ */
138
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
139
+ async fakeConnectionRequest(request, options) {
140
+ return defaultFakeConnectionRequest();
141
+ }
142
+ /**
143
+ * Gets a config stub contents by name.
144
+ *
145
+ * @param name The name of the config.
146
+ * @param group If the config supports groups.
147
+ */
148
+ getConfigStubContents(name, group) {
149
+ const stub = this.configStubs[name];
150
+ if (stub?.contents) {
151
+ if (group && stub.contents[group]) {
152
+ return (0, ts_types_1.ensureJsonMap)(stub.contents[group]);
153
+ }
154
+ else {
155
+ return stub.contents;
156
+ }
157
+ }
158
+ return {};
159
+ }
160
+ /**
161
+ * Sets a config stub contents by name
162
+ *
163
+ * @param name The name of the config stub.
164
+ * @param value The actual stub contents. The Mock data.
165
+ */
166
+ setConfigStubContents(name, value) {
167
+ if ((0, ts_types_1.ensureString)(name) && (0, ts_types_1.isJsonMap)(value)) {
168
+ this.configStubs[name] = value;
169
+ }
170
+ }
171
+ /**
172
+ * Set stubs for working in the context of a SfProject
173
+ */
174
+ inProject(inProject = true) {
175
+ this.SANDBOXES.PROJECT.restore();
176
+ if (inProject) {
177
+ this.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPath').callsFake(() => this.localPathRetriever(this.id));
178
+ this.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPathSync').callsFake(() => this.localPathRetrieverSync(this.id));
179
+ }
180
+ else {
181
+ this.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPath').rejects(new sfError_1.SfError('', 'InvalidProjectWorkspaceError'));
182
+ this.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPathSync').throws(new sfError_1.SfError('', 'InvalidProjectWorkspaceError'));
183
+ }
184
+ }
185
+ /**
186
+ * Stub salesforce org authorizations.
187
+ */
188
+ async stubAuths(...orgs) {
189
+ const entries = await Promise.all(orgs.map(async (org) => [org.username, await org.getConfig()]));
190
+ const orgMap = new Map(entries);
191
+ (0, ts_sinon_1.stubMethod)(this.SANDBOX, stateAggregator_1.OrgAccessor.prototype, 'getAllFiles').resolves([...orgMap.keys()].map((o) => `${o}.json`));
192
+ (0, ts_sinon_1.stubMethod)(this.SANDBOX, stateAggregator_1.OrgAccessor.prototype, 'hasFile').callsFake((username) => orgMap.has(username));
193
+ const retrieveContents = async function () {
194
+ const username = (0, path_1.basename)(this.path.replace('.json', ''));
195
+ return Promise.resolve(orgMap.get(username) ?? {});
196
+ };
197
+ this.configStubs.AuthInfoConfig = { retrieveContents };
198
+ }
199
+ /**
200
+ * Stub salesforce sandbox authorizations.
201
+ */
202
+ async stubSandboxes(...sandboxes) {
203
+ const entries = (await Promise.all(sandboxes.map(async (sandbox) => [sandbox.username, await sandbox.getConfig()])));
204
+ const sandboxMap = new Map(entries);
205
+ (0, ts_sinon_1.stubMethod)(this.SANDBOX, sandboxAccessor_1.SandboxAccessor.prototype, 'getAllFiles').resolves([...sandboxMap.keys()].map((o) => `${o}.sandbox.json`));
206
+ const retrieveContents = async function () {
207
+ const username = (0, path_1.basename)(this.path.replace('.sandbox.json', ''));
208
+ return Promise.resolve(sandboxMap.get(username) ?? {});
209
+ };
210
+ this.configStubs.SandboxOrgConfig = { retrieveContents };
211
+ }
212
+ /**
213
+ * Stub the aliases in the global aliases config file.
214
+ */
215
+ stubAliases(aliases, group = aliasesConfig_1.AliasGroup.ORGS) {
216
+ this.configStubs.AliasesConfig = { contents: { [group]: aliases } };
217
+ }
218
+ /**
219
+ * Stub contents in the config file.
220
+ */
221
+ async stubConfig(config) {
222
+ this.configStubs.Config = { contents: config };
223
+ // configAggregator may have already loaded an instance. We're not sure why this happens.
224
+ // This seems to solve the problem by forcing a load of the new stubbed config.
225
+ await configAggregator_1.ConfigAggregator.create();
226
+ }
227
+ /**
228
+ * Stub the tokens in the global token config file.
229
+ */
230
+ stubTokens(tokens) {
231
+ this.configStubs.TokensConfig = { contents: tokens };
232
+ }
233
+ restore() {
234
+ (0, exports.restoreContext)(this);
235
+ }
236
+ init() {
237
+ this.stubs = (0, exports.stubContext)(this);
238
+ }
239
+ /**
240
+ * Add beforeEach and afterEach hooks to init the stubs and restore them.
241
+ * This is called automatically when the class is instantiated unless the setup option is set to false.
242
+ */
243
+ setup() {
244
+ beforeEach(() => {
245
+ this.init();
246
+ });
247
+ afterEach(() => {
248
+ this.restore();
249
+ });
250
+ }
251
+ requireSinon(sinon) {
252
+ if (sinon)
253
+ return sinon;
254
+ try {
255
+ sinon = require('sinon');
256
+ }
257
+ catch (e) {
258
+ throw new Error('The package sinon was not found. Add it to your package.json and pass it in to new TestContext({sinon})');
259
+ }
260
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
261
+ return sinon;
262
+ }
263
+ }
264
+ exports.TestContext = TestContext;
37
265
  /**
38
266
  * A function to generate a unique id and return it in the context of a template, if supplied.
39
267
  *
@@ -84,121 +312,16 @@ function defaultFakeConnectionRequest() {
84
312
  * const $$ = instantiateContext();
85
313
  *
86
314
  * beforeEach(() => {
87
- * stubContext($$);
315
+ * $$.init()
88
316
  * });
89
317
  *
90
318
  * afterEach(() => {
91
- * restoreContext($$);
319
+ * $$.restore();
92
320
  * });
93
321
  * ```
94
322
  * @param sinon
95
323
  */
96
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
97
- const instantiateContext = (sinon) => {
98
- if (!sinon) {
99
- try {
100
- sinon = require('sinon');
101
- }
102
- catch (e) {
103
- throw new Error('The package sinon was not found. Add it to your package.json and pass it in to testSetup(sinon.sandbox)');
104
- }
105
- }
106
- // Import all the messages files in the sfdx-core messages dir.
107
- // Messages.importMessagesDirectory(pathJoin(__dirname, '..', '..'));
108
- messages_1.Messages.importMessagesDirectory((0, path_1.join)(__dirname));
109
- // Create a global sinon sandbox and a test logger instance for use within tests.
110
- const defaultSandbox = sinon.createSandbox();
111
- const testContext = {
112
- SANDBOX: defaultSandbox,
113
- SANDBOXES: {
114
- DEFAULT: defaultSandbox,
115
- CONFIG: sinon.createSandbox(),
116
- PROJECT: sinon.createSandbox(),
117
- CRYPTO: sinon.createSandbox(),
118
- CONNECTION: sinon.createSandbox(),
119
- FS: sinon.createSandbox(),
120
- ORGS: sinon.createSandbox(),
121
- },
122
- TEST_LOGGER: new logger_1.Logger({
123
- name: 'SFDX_Core_Test_Logger',
124
- }).useMemoryLogging(),
125
- id: uniqid(),
126
- uniqid,
127
- configStubs: {},
128
- stubs: {},
129
- // eslint-disable-next-line @typescript-eslint/require-await
130
- localPathRetriever: async (uid) => getTestLocalPath(uid),
131
- localPathRetrieverSync: getTestLocalPath,
132
- // eslint-disable-next-line @typescript-eslint/require-await
133
- globalPathRetriever: async (uid) => getTestGlobalPath(uid),
134
- globalPathRetrieverSync: getTestGlobalPath,
135
- rootPathRetriever: retrieveRootPath,
136
- rootPathRetrieverSync: retrieveRootPathSync,
137
- fakeConnectionRequest: defaultFakeConnectionRequest,
138
- getConfigStubContents(name, group) {
139
- const stub = this.configStubs[name];
140
- if (stub?.contents) {
141
- if (group && stub.contents[group]) {
142
- return (0, ts_types_1.ensureJsonMap)(stub.contents[group]);
143
- }
144
- else {
145
- return stub.contents;
146
- }
147
- }
148
- return {};
149
- },
150
- setConfigStubContents(name, value) {
151
- if ((0, ts_types_1.ensureString)(name) && (0, ts_types_1.isJsonMap)(value)) {
152
- this.configStubs[name] = value;
153
- }
154
- },
155
- inProject(inProject = true) {
156
- testContext.SANDBOXES.PROJECT.restore();
157
- if (inProject) {
158
- testContext.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPath').callsFake(() => testContext.localPathRetriever(testContext.id));
159
- testContext.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPathSync').callsFake(() => testContext.localPathRetrieverSync(testContext.id));
160
- }
161
- else {
162
- testContext.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPath').rejects(new sfError_1.SfError('', 'InvalidProjectWorkspaceError'));
163
- testContext.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPathSync').throws(new sfError_1.SfError('', 'InvalidProjectWorkspaceError'));
164
- }
165
- },
166
- async stubAuths(...orgs) {
167
- const entries = await Promise.all(orgs.map(async (org) => [org.username, await org.getConfig()]));
168
- const orgMap = new Map(entries);
169
- (0, ts_sinon_1.stubMethod)(testContext.SANDBOX, stateAggregator_1.OrgAccessor.prototype, 'getAllFiles').resolves([...orgMap.keys()].map((o) => `${o}.json`));
170
- (0, ts_sinon_1.stubMethod)(testContext.SANDBOX, stateAggregator_1.OrgAccessor.prototype, 'hasFile').callsFake((username) => orgMap.has(username));
171
- const retrieveContents = async function () {
172
- const username = (0, path_1.basename)(this.path.replace('.json', ''));
173
- return Promise.resolve(orgMap.get(username) ?? {});
174
- };
175
- this.configStubs.AuthInfoConfig = { retrieveContents };
176
- },
177
- async stubSandboxes(...sandboxes) {
178
- const entries = (await Promise.all(sandboxes.map(async (sanbox) => [sanbox.username, await sanbox.getConfig()])));
179
- const sandboxMap = new Map(entries);
180
- (0, ts_sinon_1.stubMethod)(testContext.SANDBOX, sandboxAccessor_1.SandboxAccessor.prototype, 'getAllFiles').resolves([...sandboxMap.keys()].map((o) => `${o}.sandbox.json`));
181
- const retrieveContents = async function () {
182
- const username = (0, path_1.basename)(this.path.replace('.sandbox.json', ''));
183
- return Promise.resolve(sandboxMap.get(username) ?? {});
184
- };
185
- this.configStubs.SandboxOrgConfig = { retrieveContents };
186
- },
187
- stubAliases(aliases, group = aliasesConfig_1.AliasGroup.ORGS) {
188
- this.configStubs.AliasesConfig = { contents: { [group]: aliases } };
189
- },
190
- async stubConfig(config) {
191
- this.configStubs.Config = { contents: config };
192
- // configAggregator may have already loaded an instance. We're not sure why this happens.
193
- // This seems to solve the problem by forcing a load of the new stubbed config.
194
- await configAggregator_1.ConfigAggregator.create();
195
- },
196
- stubTokens(tokens) {
197
- this.configStubs.TokensConfig = { contents: tokens };
198
- },
199
- };
200
- return testContext;
201
- };
324
+ const instantiateContext = (sinon) => new TestContext({ sinon, setup: false });
202
325
  exports.instantiateContext = instantiateContext;
203
326
  /**
204
327
  * Stub a @salesforce/core test context. This will mock out logging to a file, config file reading and writing,
@@ -215,11 +338,11 @@ exports.instantiateContext = instantiateContext;
215
338
  * const $$ = instantiateContext();
216
339
  *
217
340
  * beforeEach(() => {
218
- * stubContext($$);
341
+ * $$.init()
219
342
  * });
220
343
  *
221
344
  * afterEach(() => {
222
- * restoreContext($$);
345
+ * $$.restore();
223
346
  * });
224
347
  * ```
225
348
  * @param testContext
@@ -322,6 +445,7 @@ const stubContext = (testContext) => {
322
445
  });
323
446
  // Always start with the default and tests beforeEach or it methods can override it.
324
447
  testContext.fakeConnectionRequest = defaultFakeConnectionRequest;
448
+ testContext.stubs = stubs;
325
449
  return stubs;
326
450
  };
327
451
  exports.stubContext = stubContext;
@@ -335,11 +459,11 @@ exports.stubContext = stubContext;
335
459
  * const $$ = instantiateContext();
336
460
  *
337
461
  * beforeEach(() => {
338
- * stubContext($$);
462
+ * $$.init()
339
463
  * });
340
464
  *
341
465
  * afterEach(() => {
342
- * restoreContext($$);
466
+ * $$.restore();
343
467
  * });
344
468
  * ```
345
469
  * @param testContext
@@ -351,9 +475,12 @@ const restoreContext = (testContext) => {
351
475
  testContext.configStubs = {};
352
476
  // Give each test run a clean StateAggregator
353
477
  stateAggregator_1.StateAggregator.clearInstance();
478
+ // Allow each test to have their own config aggregator
479
+ // @ts-ignore clear for testing.
480
+ delete configAggregator_1.ConfigAggregator.instance;
354
481
  };
355
482
  exports.restoreContext = restoreContext;
356
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, no-underscore-dangle
483
+ // eslint-disable-next-line no-underscore-dangle
357
484
  const _testSetup = (sinon) => {
358
485
  const testContext = (0, exports.instantiateContext)(sinon);
359
486
  beforeEach(() => {
@@ -368,12 +495,29 @@ const _testSetup = (sinon) => {
368
495
  return testContext;
369
496
  };
370
497
  /**
498
+ * @deprecated Use TestContext instead.
499
+ * Using testSetup will create globals stubs that could lead to erratic test behavior.
500
+ *
501
+ * This example shows you how to use TestContext:
502
+ * @example
503
+ * ```
504
+ * const $$ = new TestContext();
505
+ *
506
+ * beforeEach(() => {
507
+ * $$.init();
508
+ * });
509
+ *
510
+ * afterEach(() => {
511
+ * $$.restore();
512
+ * });
513
+ * ```
514
+ *
371
515
  * Use to mock out different pieces of sfdx-core to make testing easier. This will mock out
372
516
  * logging to a file, config file reading and writing, local and global path resolution, and
373
517
  * *http request using connection (soon)*.
374
518
  *
375
519
  * **Note:** The testSetup should be outside of the describe. If you need to stub per test, use
376
- * `instantiateContext`, `stubContext`, and `restoreContext`.
520
+ * `TestContext`.
377
521
  * ```
378
522
  * // In a mocha tests
379
523
  * import testSetup from '@salesforce/core/lib/testSetup';
@@ -389,7 +533,7 @@ const _testSetup = (sinon) => {
389
533
  * $$.stubAliases({ 'myTestAlias': 'user@company.com' });
390
534
  *
391
535
  * // Will use the contents set above.
392
- * const username = (await StateAggregator.getInstance()).aliases.resolveUseranme('myTestAlias');
536
+ * const username = (await StateAggregator.getInstance()).aliases.resolveUsername('myTestAlias');
393
537
  * expect(username).to.equal('user@company.com');
394
538
  * });
395
539
  * });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/core",
3
- "version": "3.30.13",
3
+ "version": "3.31.04",
4
4
  "description": "Core libraries to interact with SFDX projects, orgs, and APIs.",
5
5
  "main": "lib/exported",
6
6
  "types": "lib/exported.d.ts",