@salesforce/core 3.31.4 → 3.31.7
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/LICENSE.txt +11 -11
- package/README.md +222 -222
- package/lib/config/aliasesConfig.d.ts +12 -12
- package/lib/config/aliasesConfig.js +27 -27
- package/lib/config/authInfoConfig.d.ts +19 -19
- package/lib/config/authInfoConfig.js +34 -34
- package/lib/config/config.d.ts +311 -311
- package/lib/config/config.js +574 -574
- package/lib/config/configAggregator.d.ts +232 -232
- package/lib/config/configAggregator.js +379 -379
- package/lib/config/configFile.d.ts +199 -199
- package/lib/config/configFile.js +340 -340
- package/lib/config/configGroup.d.ts +141 -141
- package/lib/config/configGroup.js +224 -224
- package/lib/config/configStore.d.ts +241 -241
- package/lib/config/configStore.js +352 -352
- package/lib/config/envVars.d.ts +101 -101
- package/lib/config/envVars.js +456 -456
- package/lib/config/orgUsersConfig.d.ts +31 -31
- package/lib/config/orgUsersConfig.js +41 -41
- package/lib/config/sandboxOrgConfig.d.ts +37 -37
- package/lib/config/sandboxOrgConfig.js +50 -50
- package/lib/config/sandboxProcessCache.d.ts +16 -16
- package/lib/config/sandboxProcessCache.js +37 -37
- package/lib/config/tokensConfig.d.ts +10 -10
- package/lib/config/tokensConfig.js +28 -28
- package/lib/config/ttlConfig.d.ts +34 -34
- package/lib/config/ttlConfig.js +54 -54
- package/lib/crypto/crypto.d.ts +54 -54
- package/lib/crypto/crypto.js +220 -220
- package/lib/crypto/keyChain.d.ts +8 -8
- package/lib/crypto/keyChain.js +61 -61
- package/lib/crypto/keyChainImpl.d.ts +116 -116
- package/lib/crypto/keyChainImpl.js +486 -486
- package/lib/crypto/secureBuffer.d.ts +46 -46
- package/lib/crypto/secureBuffer.js +82 -82
- package/lib/deviceOauthService.d.ts +71 -71
- package/lib/deviceOauthService.js +191 -191
- package/lib/exported.d.ts +38 -38
- package/lib/exported.js +118 -118
- package/lib/global.d.ts +70 -70
- package/lib/global.js +109 -109
- package/lib/lifecycleEvents.d.ts +93 -93
- package/lib/lifecycleEvents.js +188 -188
- package/lib/logger.d.ts +381 -381
- package/lib/logger.js +734 -734
- package/lib/messages.d.ts +291 -291
- package/lib/messages.js +543 -543
- package/lib/org/authInfo.d.ts +344 -344
- package/lib/org/authInfo.js +892 -892
- package/lib/org/authRemover.d.ts +88 -88
- package/lib/org/authRemover.js +182 -182
- package/lib/org/connection.d.ts +197 -197
- package/lib/org/connection.js +395 -395
- package/lib/org/index.d.ts +6 -6
- package/lib/org/index.js +28 -28
- package/lib/org/org.d.ts +558 -558
- package/lib/org/org.js +1267 -1267
- package/lib/org/orgConfigProperties.d.ts +69 -69
- package/lib/org/orgConfigProperties.js +136 -136
- package/lib/org/permissionSetAssignment.d.ts +35 -35
- package/lib/org/permissionSetAssignment.js +125 -125
- package/lib/org/scratchOrgCache.d.ts +20 -20
- package/lib/org/scratchOrgCache.js +32 -32
- package/lib/org/scratchOrgCreate.d.ts +54 -54
- package/lib/org/scratchOrgCreate.js +216 -216
- package/lib/org/scratchOrgErrorCodes.d.ts +10 -10
- package/lib/org/scratchOrgErrorCodes.js +88 -88
- package/lib/org/scratchOrgFeatureDeprecation.d.ts +26 -26
- package/lib/org/scratchOrgFeatureDeprecation.js +109 -109
- package/lib/org/scratchOrgInfoApi.d.ts +68 -68
- package/lib/org/scratchOrgInfoApi.js +413 -413
- package/lib/org/scratchOrgInfoGenerator.d.ts +64 -64
- package/lib/org/scratchOrgInfoGenerator.js +241 -241
- package/lib/org/scratchOrgLifecycleEvents.d.ts +10 -10
- package/lib/org/scratchOrgLifecycleEvents.js +40 -40
- package/lib/org/scratchOrgSettingsGenerator.d.ts +78 -78
- package/lib/org/scratchOrgSettingsGenerator.js +276 -276
- package/lib/org/scratchOrgTypes.d.ts +43 -43
- package/lib/org/scratchOrgTypes.js +8 -8
- package/lib/org/user.d.ts +187 -187
- package/lib/org/user.js +448 -448
- package/lib/schema/printer.d.ts +79 -79
- package/lib/schema/printer.js +260 -260
- package/lib/schema/validator.d.ts +70 -70
- package/lib/schema/validator.js +169 -169
- package/lib/sfError.d.ts +73 -73
- package/lib/sfError.js +136 -136
- package/lib/sfProject.d.ts +357 -357
- package/lib/sfProject.js +671 -671
- package/lib/stateAggregator/accessors/aliasAccessor.d.ts +98 -98
- package/lib/stateAggregator/accessors/aliasAccessor.js +145 -145
- package/lib/stateAggregator/accessors/orgAccessor.d.ts +101 -101
- package/lib/stateAggregator/accessors/orgAccessor.js +240 -240
- package/lib/stateAggregator/accessors/sandboxAccessor.d.ts +8 -8
- package/lib/stateAggregator/accessors/sandboxAccessor.js +27 -27
- package/lib/stateAggregator/accessors/tokenAccessor.d.ts +63 -63
- package/lib/stateAggregator/accessors/tokenAccessor.js +79 -79
- package/lib/stateAggregator/index.d.ts +4 -4
- package/lib/stateAggregator/index.js +26 -26
- package/lib/stateAggregator/stateAggregator.d.ts +25 -25
- package/lib/stateAggregator/stateAggregator.js +45 -45
- package/lib/status/myDomainResolver.d.ts +66 -66
- package/lib/status/myDomainResolver.js +124 -124
- package/lib/status/pollingClient.d.ts +85 -85
- package/lib/status/pollingClient.js +115 -115
- package/lib/status/streamingClient.d.ts +244 -244
- package/lib/status/streamingClient.js +436 -436
- package/lib/status/types.d.ts +89 -89
- package/lib/status/types.js +17 -17
- package/lib/testSetup.d.ts +553 -553
- package/lib/testSetup.js +871 -871
- package/lib/util/cache.d.ts +11 -11
- package/lib/util/cache.js +69 -69
- package/lib/util/checkLightningDomain.d.ts +1 -1
- package/lib/util/checkLightningDomain.js +28 -28
- package/lib/util/directoryWriter.d.ts +12 -12
- package/lib/util/directoryWriter.js +53 -53
- package/lib/util/getJwtAudienceUrl.d.ts +4 -4
- package/lib/util/getJwtAudienceUrl.js +18 -18
- package/lib/util/internal.d.ts +58 -58
- package/lib/util/internal.js +118 -118
- package/lib/util/jsonXmlTools.d.ts +14 -14
- package/lib/util/jsonXmlTools.js +38 -38
- package/lib/util/mapKeys.d.ts +14 -14
- package/lib/util/mapKeys.js +51 -51
- package/lib/util/sfdc.d.ts +52 -52
- package/lib/util/sfdc.js +85 -85
- package/lib/util/sfdcUrl.d.ts +72 -72
- package/lib/util/sfdcUrl.js +215 -215
- package/lib/util/structuredWriter.d.ts +9 -9
- package/lib/util/structuredWriter.js +2 -2
- package/lib/util/zipWriter.d.ts +16 -16
- package/lib/util/zipWriter.js +67 -67
- package/lib/webOAuthServer.d.ts +156 -156
- package/lib/webOAuthServer.js +388 -388
- package/messages/auth.md +37 -37
- package/messages/config.md +156 -156
- package/messages/connection.md +30 -30
- package/messages/core.json +20 -20
- package/messages/core.md +67 -67
- package/messages/encryption.md +85 -85
- package/messages/envVars.md +303 -303
- package/messages/org.md +63 -63
- package/messages/permissionSetAssignment.md +31 -31
- package/messages/scratchOrgCreate.md +23 -23
- package/messages/scratchOrgErrorCodes.md +115 -115
- package/messages/scratchOrgFeatureDeprecation.md +11 -11
- package/messages/scratchOrgInfoApi.md +15 -15
- package/messages/scratchOrgInfoGenerator.md +23 -23
- package/messages/streaming.md +23 -23
- package/messages/user.md +35 -35
- package/package.json +97 -97
package/lib/testSetup.js
CHANGED
|
@@ -1,872 +1,872 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2020, salesforce.com, inc.
|
|
4
|
-
* All rights reserved.
|
|
5
|
-
* Licensed under the BSD 3-Clause license.
|
|
6
|
-
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
-
*/
|
|
8
|
-
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
9
|
-
/* eslint-disable class-methods-use-this */
|
|
10
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
11
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
12
|
-
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
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 = exports.TestContext = void 0;
|
|
15
|
-
const crypto_1 = require("crypto");
|
|
16
|
-
const events_1 = require("events");
|
|
17
|
-
const os_1 = require("os");
|
|
18
|
-
const path_1 = require("path");
|
|
19
|
-
const util = require("util");
|
|
20
|
-
const kit_1 = require("@salesforce/kit");
|
|
21
|
-
const ts_sinon_1 = require("@salesforce/ts-sinon");
|
|
22
|
-
const ts_types_1 = require("@salesforce/ts-types");
|
|
23
|
-
const configAggregator_1 = require("./config/configAggregator");
|
|
24
|
-
const configFile_1 = require("./config/configFile");
|
|
25
|
-
const connection_1 = require("./org/connection");
|
|
26
|
-
const crypto_2 = require("./crypto/crypto");
|
|
27
|
-
const logger_1 = require("./logger");
|
|
28
|
-
const messages_1 = require("./messages");
|
|
29
|
-
const sfError_1 = require("./sfError");
|
|
30
|
-
const sfProject_1 = require("./sfProject");
|
|
31
|
-
const streamingClient_1 = require("./status/streamingClient");
|
|
32
|
-
const stateAggregator_1 = require("./stateAggregator");
|
|
33
|
-
const org_1 = require("./org");
|
|
34
|
-
const sandboxAccessor_1 = require("./stateAggregator/accessors/sandboxAccessor");
|
|
35
|
-
const aliasesConfig_1 = require("./config/aliasesConfig");
|
|
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;
|
|
265
|
-
/**
|
|
266
|
-
* A function to generate a unique id and return it in the context of a template, if supplied.
|
|
267
|
-
*
|
|
268
|
-
* A template is a string that can contain `${%s}` to be replaced with a unique id.
|
|
269
|
-
* If the template contains the "%s" placeholder, it will be replaced with the unique id otherwise the id will be appended to the template.
|
|
270
|
-
*
|
|
271
|
-
* @param options an object with the following properties:
|
|
272
|
-
* - template: a template string.
|
|
273
|
-
* - length: the length of the unique id as presented in hexadecimal.
|
|
274
|
-
*/
|
|
275
|
-
function uniqid(options) {
|
|
276
|
-
const uniqueString = (0, crypto_1.randomBytes)(Math.ceil((options?.length ?? 32) / 2.0))
|
|
277
|
-
.toString('hex')
|
|
278
|
-
.slice(0, options?.length ?? 32);
|
|
279
|
-
if (!options?.template) {
|
|
280
|
-
return uniqueString;
|
|
281
|
-
}
|
|
282
|
-
return options.template.includes('%s')
|
|
283
|
-
? util.format(options.template, uniqueString)
|
|
284
|
-
: `${options.template}${uniqueString}`;
|
|
285
|
-
}
|
|
286
|
-
exports.uniqid = uniqid;
|
|
287
|
-
function getTestLocalPath(uid) {
|
|
288
|
-
return (0, path_1.join)((0, os_1.tmpdir)(), uid, 'sfdx_core', 'local');
|
|
289
|
-
}
|
|
290
|
-
function getTestGlobalPath(uid) {
|
|
291
|
-
return (0, path_1.join)((0, os_1.tmpdir)(), uid, 'sfdx_core', 'global');
|
|
292
|
-
}
|
|
293
|
-
function retrieveRootPathSync(isGlobal, uid = uniqid()) {
|
|
294
|
-
return isGlobal ? getTestGlobalPath(uid) : getTestLocalPath(uid);
|
|
295
|
-
}
|
|
296
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
297
|
-
async function retrieveRootPath(isGlobal, uid = uniqid()) {
|
|
298
|
-
return retrieveRootPathSync(isGlobal, uid);
|
|
299
|
-
}
|
|
300
|
-
function defaultFakeConnectionRequest() {
|
|
301
|
-
return Promise.resolve((0, ts_types_1.ensureAnyJson)({ records: [] }));
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Instantiate a @salesforce/core test context. This is automatically created by `const $$ = testSetup()`
|
|
305
|
-
* but is useful if you don't want to have a global stub of @salesforce/core and you want to isolate it to
|
|
306
|
-
* a single describe.
|
|
307
|
-
*
|
|
308
|
-
* **Note:** Call `stubContext` in your beforeEach to have clean stubs of @salesforce/core every test run.
|
|
309
|
-
*
|
|
310
|
-
* @example
|
|
311
|
-
* ```
|
|
312
|
-
* const $$ = instantiateContext();
|
|
313
|
-
*
|
|
314
|
-
* beforeEach(() => {
|
|
315
|
-
* $$.init()
|
|
316
|
-
* });
|
|
317
|
-
*
|
|
318
|
-
* afterEach(() => {
|
|
319
|
-
* $$.restore();
|
|
320
|
-
* });
|
|
321
|
-
* ```
|
|
322
|
-
* @param sinon
|
|
323
|
-
*/
|
|
324
|
-
const instantiateContext = (sinon) => new TestContext({ sinon, setup: false });
|
|
325
|
-
exports.instantiateContext = instantiateContext;
|
|
326
|
-
/**
|
|
327
|
-
* Stub a @salesforce/core test context. This will mock out logging to a file, config file reading and writing,
|
|
328
|
-
* local and global path resolution, and http request using connection (soon)*.
|
|
329
|
-
*
|
|
330
|
-
* This is automatically stubbed in the global beforeEach created by
|
|
331
|
-
* `const $$ = testSetup()` but is useful if you don't want to have a global stub of @salesforce/core and you
|
|
332
|
-
* want to isolate it to a single describe.
|
|
333
|
-
*
|
|
334
|
-
* **Note:** Always call `restoreContext` in your afterEach.
|
|
335
|
-
*
|
|
336
|
-
* @example
|
|
337
|
-
* ```
|
|
338
|
-
* const $$ = instantiateContext();
|
|
339
|
-
*
|
|
340
|
-
* beforeEach(() => {
|
|
341
|
-
* $$.init()
|
|
342
|
-
* });
|
|
343
|
-
*
|
|
344
|
-
* afterEach(() => {
|
|
345
|
-
* $$.restore();
|
|
346
|
-
* });
|
|
347
|
-
* ```
|
|
348
|
-
* @param testContext
|
|
349
|
-
*/
|
|
350
|
-
const stubContext = (testContext) => {
|
|
351
|
-
// Turn off the interoperability feature so that we don't have to mock
|
|
352
|
-
// the old .sfdx config files
|
|
353
|
-
global_1.Global.SFDX_INTEROPERABILITY = false;
|
|
354
|
-
const stubs = {};
|
|
355
|
-
// Most core files create a child logger so stub this to return our test logger.
|
|
356
|
-
(0, ts_sinon_1.stubMethod)(testContext.SANDBOX, logger_1.Logger, 'child').resolves(testContext.TEST_LOGGER);
|
|
357
|
-
(0, ts_sinon_1.stubMethod)(testContext.SANDBOX, logger_1.Logger, 'childFromRoot').returns(testContext.TEST_LOGGER);
|
|
358
|
-
testContext.inProject(true);
|
|
359
|
-
testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile, 'resolveRootFolder').callsFake((isGlobal) => testContext.rootPathRetriever(isGlobal, testContext.id));
|
|
360
|
-
testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile, 'resolveRootFolderSync').callsFake((isGlobal) => testContext.rootPathRetrieverSync(isGlobal, testContext.id));
|
|
361
|
-
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.PROJECT, sfProject_1.SfProjectJson.prototype, 'doesPackageExist').callsFake(() => true);
|
|
362
|
-
const initStubForRead = (configFile) => {
|
|
363
|
-
const stub = testContext.configStubs[configFile.constructor.name] ?? {};
|
|
364
|
-
// init calls read calls getPath which sets the path on the config file the first time.
|
|
365
|
-
// Since read is now stubbed, make sure to call getPath to initialize it.
|
|
366
|
-
configFile.getPath();
|
|
367
|
-
// @ts-ignore set this to true to avoid an infinite loop in tests when reading config files.
|
|
368
|
-
configFile.hasRead = true;
|
|
369
|
-
return stub;
|
|
370
|
-
};
|
|
371
|
-
const readSync = function (newContents) {
|
|
372
|
-
const stub = initStubForRead(this);
|
|
373
|
-
this.setContentsFromObject(newContents ?? stub.contents ?? {});
|
|
374
|
-
return this.getContents();
|
|
375
|
-
};
|
|
376
|
-
const read = async function () {
|
|
377
|
-
const stub = initStubForRead(this);
|
|
378
|
-
if (stub.readFn) {
|
|
379
|
-
return stub.readFn.call(this);
|
|
380
|
-
}
|
|
381
|
-
if (stub.retrieveContents) {
|
|
382
|
-
return readSync.call(this, await stub.retrieveContents.call(this));
|
|
383
|
-
}
|
|
384
|
-
else {
|
|
385
|
-
return readSync.call(this);
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
// Mock out all config file IO for all tests. They can restore individually if they need original functionality.
|
|
389
|
-
// @ts-ignore
|
|
390
|
-
stubs.configRead = testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile.prototype, 'readSync').callsFake(readSync);
|
|
391
|
-
stubs.configReadSync = testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile.prototype, 'read').callsFake(read);
|
|
392
|
-
const writeSync = function (newContents) {
|
|
393
|
-
if (!testContext.configStubs[this.constructor.name]) {
|
|
394
|
-
testContext.configStubs[this.constructor.name] = {};
|
|
395
|
-
}
|
|
396
|
-
const stub = testContext.configStubs[this.constructor.name];
|
|
397
|
-
if (!stub)
|
|
398
|
-
return;
|
|
399
|
-
this.setContents(newContents ?? this.getContents());
|
|
400
|
-
stub.contents = this.toObject();
|
|
401
|
-
};
|
|
402
|
-
const write = async function (newContents) {
|
|
403
|
-
if (!testContext.configStubs[this.constructor.name]) {
|
|
404
|
-
testContext.configStubs[this.constructor.name] = {};
|
|
405
|
-
}
|
|
406
|
-
const stub = testContext.configStubs[this.constructor.name];
|
|
407
|
-
if (!stub)
|
|
408
|
-
return;
|
|
409
|
-
if (stub.writeFn) {
|
|
410
|
-
return stub.writeFn.call(this, newContents);
|
|
411
|
-
}
|
|
412
|
-
if (stub.updateContents) {
|
|
413
|
-
writeSync.call(this, await stub.updateContents.call(this));
|
|
414
|
-
}
|
|
415
|
-
else {
|
|
416
|
-
writeSync.call(this);
|
|
417
|
-
}
|
|
418
|
-
};
|
|
419
|
-
stubs.configWriteSync = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONFIG, configFile_1.ConfigFile.prototype, 'writeSync').callsFake(writeSync);
|
|
420
|
-
stubs.configWrite = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONFIG, configFile_1.ConfigFile.prototype, 'write').callsFake(write);
|
|
421
|
-
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CRYPTO, crypto_2.Crypto.prototype, 'getKeyChain').callsFake(() => Promise.resolve({
|
|
422
|
-
setPassword: () => Promise.resolve(),
|
|
423
|
-
getPassword: (data, cb) => cb(undefined, '12345678901234567890123456789012'),
|
|
424
|
-
}));
|
|
425
|
-
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONNECTION, connection_1.Connection.prototype, 'isResolvable').resolves(true);
|
|
426
|
-
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONNECTION, connection_1.Connection.prototype, 'request').callsFake(function (request, options) {
|
|
427
|
-
if (request === `${this.instanceUrl}/services/data`) {
|
|
428
|
-
return Promise.resolve([{ version: '42.0' }]);
|
|
429
|
-
}
|
|
430
|
-
return testContext.fakeConnectionRequest.call(this, request, options);
|
|
431
|
-
});
|
|
432
|
-
stubs.configExists = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.ORGS, stateAggregator_1.OrgAccessor.prototype, 'exists').callsFake(async function (username) {
|
|
433
|
-
// @ts-expect-error because private member
|
|
434
|
-
if ([...this.contents.keys()].includes(username))
|
|
435
|
-
return Promise.resolve(true);
|
|
436
|
-
else
|
|
437
|
-
return Promise.resolve(false);
|
|
438
|
-
});
|
|
439
|
-
stubs.configRemove = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.ORGS, stateAggregator_1.OrgAccessor.prototype, 'remove').callsFake(async function (username) {
|
|
440
|
-
// @ts-expect-error because private member
|
|
441
|
-
if ([...this.contents.keys()].includes(username))
|
|
442
|
-
return Promise.resolve(true);
|
|
443
|
-
else
|
|
444
|
-
return Promise.resolve(false);
|
|
445
|
-
});
|
|
446
|
-
// Always start with the default and tests beforeEach or it methods can override it.
|
|
447
|
-
testContext.fakeConnectionRequest = defaultFakeConnectionRequest;
|
|
448
|
-
testContext.stubs = stubs;
|
|
449
|
-
return stubs;
|
|
450
|
-
};
|
|
451
|
-
exports.stubContext = stubContext;
|
|
452
|
-
/**
|
|
453
|
-
* Restore a @salesforce/core test context. This is automatically stubbed in the global beforeEach created by
|
|
454
|
-
* `const $$ = testSetup()` but is useful if you don't want to have a global stub of @salesforce/core and you
|
|
455
|
-
* want to isolate it to a single describe.
|
|
456
|
-
*
|
|
457
|
-
* @example
|
|
458
|
-
* ```
|
|
459
|
-
* const $$ = instantiateContext();
|
|
460
|
-
*
|
|
461
|
-
* beforeEach(() => {
|
|
462
|
-
* $$.init()
|
|
463
|
-
* });
|
|
464
|
-
*
|
|
465
|
-
* afterEach(() => {
|
|
466
|
-
* $$.restore();
|
|
467
|
-
* });
|
|
468
|
-
* ```
|
|
469
|
-
* @param testContext
|
|
470
|
-
*/
|
|
471
|
-
const restoreContext = (testContext) => {
|
|
472
|
-
testContext.SANDBOX.restore();
|
|
473
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
474
|
-
Object.values(testContext.SANDBOXES).forEach((theSandbox) => theSandbox.restore());
|
|
475
|
-
testContext.configStubs = {};
|
|
476
|
-
// Give each test run a clean StateAggregator
|
|
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;
|
|
481
|
-
};
|
|
482
|
-
exports.restoreContext = restoreContext;
|
|
483
|
-
// eslint-disable-next-line no-underscore-dangle
|
|
484
|
-
const _testSetup = (sinon) => {
|
|
485
|
-
const testContext = (0, exports.instantiateContext)(sinon);
|
|
486
|
-
beforeEach(() => {
|
|
487
|
-
// Allow each test to have their own config aggregator
|
|
488
|
-
// @ts-ignore clear for testing.
|
|
489
|
-
delete configAggregator_1.ConfigAggregator.instance;
|
|
490
|
-
testContext.stubs = (0, exports.stubContext)(testContext);
|
|
491
|
-
});
|
|
492
|
-
afterEach(() => {
|
|
493
|
-
(0, exports.restoreContext)(testContext);
|
|
494
|
-
});
|
|
495
|
-
return testContext;
|
|
496
|
-
};
|
|
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
|
-
*
|
|
515
|
-
* Use to mock out different pieces of sfdx-core to make testing easier. This will mock out
|
|
516
|
-
* logging to a file, config file reading and writing, local and global path resolution, and
|
|
517
|
-
* *http request using connection (soon)*.
|
|
518
|
-
*
|
|
519
|
-
* **Note:** The testSetup should be outside of the describe. If you need to stub per test, use
|
|
520
|
-
* `TestContext`.
|
|
521
|
-
* ```
|
|
522
|
-
* // In a mocha tests
|
|
523
|
-
* import testSetup from '@salesforce/core/lib/testSetup';
|
|
524
|
-
*
|
|
525
|
-
* const $$ = testSetup();
|
|
526
|
-
*
|
|
527
|
-
* describe(() => {
|
|
528
|
-
* it('test', () => {
|
|
529
|
-
* // Stub out your own method
|
|
530
|
-
* $$.SANDBOX.stub(MyClass.prototype, 'myMethod').returnsFake(() => {});
|
|
531
|
-
*
|
|
532
|
-
* // Set the contents that is used when aliases are read. Same for all config files.
|
|
533
|
-
* $$.stubAliases({ 'myTestAlias': 'user@company.com' });
|
|
534
|
-
*
|
|
535
|
-
* // Will use the contents set above.
|
|
536
|
-
* const username = (await StateAggregator.getInstance()).aliases.resolveUsername('myTestAlias');
|
|
537
|
-
* expect(username).to.equal('user@company.com');
|
|
538
|
-
* });
|
|
539
|
-
* });
|
|
540
|
-
* ```
|
|
541
|
-
*/
|
|
542
|
-
exports.testSetup = (0, kit_1.once)(_testSetup);
|
|
543
|
-
/**
|
|
544
|
-
* A pre-canned error for try/catch testing.
|
|
545
|
-
*
|
|
546
|
-
* **See** {@link shouldThrow}
|
|
547
|
-
*/
|
|
548
|
-
exports.unexpectedResult = new sfError_1.SfError('This code was expected to fail', 'UnexpectedResult');
|
|
549
|
-
/**
|
|
550
|
-
* Use for this testing pattern:
|
|
551
|
-
* ```
|
|
552
|
-
* try {
|
|
553
|
-
* await call()
|
|
554
|
-
* assert.fail('this should never happen');
|
|
555
|
-
* } catch (e) {
|
|
556
|
-
* ...
|
|
557
|
-
* }
|
|
558
|
-
*
|
|
559
|
-
* Just do this
|
|
560
|
-
*
|
|
561
|
-
* try {
|
|
562
|
-
* await shouldThrow(call()); // If this succeeds unexpectedResultError is thrown.
|
|
563
|
-
* } catch(e) {
|
|
564
|
-
* ...
|
|
565
|
-
* }
|
|
566
|
-
* ```
|
|
567
|
-
*
|
|
568
|
-
* @param f The async function that is expected to throw.
|
|
569
|
-
*/
|
|
570
|
-
async function shouldThrow(f, message) {
|
|
571
|
-
await f;
|
|
572
|
-
if (message) {
|
|
573
|
-
throw new sfError_1.SfError(message, 'UnexpectedResult');
|
|
574
|
-
}
|
|
575
|
-
else {
|
|
576
|
-
throw exports.unexpectedResult;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
exports.shouldThrow = shouldThrow;
|
|
580
|
-
/**
|
|
581
|
-
* Use for this testing pattern:
|
|
582
|
-
* ```
|
|
583
|
-
* try {
|
|
584
|
-
* call()
|
|
585
|
-
* assert.fail('this should never happen');
|
|
586
|
-
* } catch (e) {
|
|
587
|
-
* ...
|
|
588
|
-
* }
|
|
589
|
-
*
|
|
590
|
-
* Just do this
|
|
591
|
-
*
|
|
592
|
-
* try {
|
|
593
|
-
* shouldThrowSync(call); // If this succeeds unexpectedResultError is thrown.
|
|
594
|
-
* } catch(e) {
|
|
595
|
-
* ...
|
|
596
|
-
* }
|
|
597
|
-
* ```
|
|
598
|
-
*
|
|
599
|
-
* @param f The function that is expected to throw.
|
|
600
|
-
*/
|
|
601
|
-
function shouldThrowSync(f, message) {
|
|
602
|
-
f();
|
|
603
|
-
if (message) {
|
|
604
|
-
throw new sfError_1.SfError(message, 'UnexpectedResult');
|
|
605
|
-
}
|
|
606
|
-
else {
|
|
607
|
-
throw exports.unexpectedResult;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
exports.shouldThrowSync = shouldThrowSync;
|
|
611
|
-
/**
|
|
612
|
-
* A helper to determine if a subscription will use callback or errorback.
|
|
613
|
-
* Enable errback to simulate a subscription failure.
|
|
614
|
-
*/
|
|
615
|
-
var StreamingMockSubscriptionCall;
|
|
616
|
-
(function (StreamingMockSubscriptionCall) {
|
|
617
|
-
StreamingMockSubscriptionCall[StreamingMockSubscriptionCall["CALLBACK"] = 0] = "CALLBACK";
|
|
618
|
-
StreamingMockSubscriptionCall[StreamingMockSubscriptionCall["ERRORBACK"] = 1] = "ERRORBACK";
|
|
619
|
-
})(StreamingMockSubscriptionCall = exports.StreamingMockSubscriptionCall || (exports.StreamingMockSubscriptionCall = {}));
|
|
620
|
-
/**
|
|
621
|
-
* Simulates a comet subscription to a streaming channel.
|
|
622
|
-
*/
|
|
623
|
-
class StreamingMockCometSubscription extends events_1.EventEmitter {
|
|
624
|
-
constructor(options) {
|
|
625
|
-
super();
|
|
626
|
-
this.options = options;
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Sets up a streaming subscription callback to occur after the setTimeout event loop phase.
|
|
630
|
-
*
|
|
631
|
-
* @param callback The function to invoke.
|
|
632
|
-
*/
|
|
633
|
-
callback(callback) {
|
|
634
|
-
if (this.options.subscriptionCall === StreamingMockSubscriptionCall.CALLBACK) {
|
|
635
|
-
setTimeout(() => {
|
|
636
|
-
callback();
|
|
637
|
-
super.emit(StreamingMockCometSubscription.SUBSCRIPTION_COMPLETE);
|
|
638
|
-
}, 0);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
/**
|
|
642
|
-
* Sets up a streaming subscription errback to occur after the setTimeout event loop phase.
|
|
643
|
-
*
|
|
644
|
-
* @param callback The function to invoke.
|
|
645
|
-
*/
|
|
646
|
-
errback(callback) {
|
|
647
|
-
if (this.options.subscriptionCall === StreamingMockSubscriptionCall.ERRORBACK) {
|
|
648
|
-
const error = this.options.subscriptionErrbackError;
|
|
649
|
-
if (!error)
|
|
650
|
-
return;
|
|
651
|
-
setTimeout(() => {
|
|
652
|
-
callback(error);
|
|
653
|
-
super.emit(StreamingMockCometSubscription.SUBSCRIPTION_FAILED);
|
|
654
|
-
}, 0);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
exports.StreamingMockCometSubscription = StreamingMockCometSubscription;
|
|
659
|
-
StreamingMockCometSubscription.SUBSCRIPTION_COMPLETE = 'subscriptionComplete';
|
|
660
|
-
StreamingMockCometSubscription.SUBSCRIPTION_FAILED = 'subscriptionFailed';
|
|
661
|
-
/**
|
|
662
|
-
* Simulates a comet client. To the core streaming client this mocks the internal comet impl.
|
|
663
|
-
* The uses setTimeout(0ms) event loop phase just so the client can simulate actual streaming without the response
|
|
664
|
-
* latency.
|
|
665
|
-
*/
|
|
666
|
-
class StreamingMockCometClient extends streamingClient_1.CometClient {
|
|
667
|
-
/**
|
|
668
|
-
* Constructor
|
|
669
|
-
*
|
|
670
|
-
* @param {StreamingMockCometSubscriptionOptions} options Extends the StreamingClient options.
|
|
671
|
-
*/
|
|
672
|
-
constructor(options) {
|
|
673
|
-
super();
|
|
674
|
-
this.options = options;
|
|
675
|
-
if (!this.options.messagePlaylist) {
|
|
676
|
-
this.options.messagePlaylist = [{ id: this.options.id }];
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Fake addExtension. Does nothing.
|
|
681
|
-
*/
|
|
682
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
|
683
|
-
addExtension(extension) { }
|
|
684
|
-
/**
|
|
685
|
-
* Fake disable. Does nothing.
|
|
686
|
-
*/
|
|
687
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
|
688
|
-
disable(label) { }
|
|
689
|
-
/**
|
|
690
|
-
* Fake handshake that invoke callback after the setTimeout event phase.
|
|
691
|
-
*
|
|
692
|
-
* @param callback The function to invoke.
|
|
693
|
-
*/
|
|
694
|
-
handshake(callback) {
|
|
695
|
-
setTimeout(() => {
|
|
696
|
-
callback();
|
|
697
|
-
}, 0);
|
|
698
|
-
}
|
|
699
|
-
/**
|
|
700
|
-
* Fake setHeader. Does nothing,
|
|
701
|
-
*/
|
|
702
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
|
703
|
-
setHeader(name, value) { }
|
|
704
|
-
/**
|
|
705
|
-
* Fake subscription that completed after the setTimout event phase.
|
|
706
|
-
*
|
|
707
|
-
* @param channel The streaming channel.
|
|
708
|
-
* @param callback The function to invoke after the subscription completes.
|
|
709
|
-
*/
|
|
710
|
-
subscribe(channel, callback) {
|
|
711
|
-
const subscription = new StreamingMockCometSubscription(this.options);
|
|
712
|
-
subscription.on('subscriptionComplete', () => {
|
|
713
|
-
if (!this.options.messagePlaylist)
|
|
714
|
-
return;
|
|
715
|
-
Object.values(this.options.messagePlaylist).forEach((message) => {
|
|
716
|
-
setTimeout(() => {
|
|
717
|
-
callback(message);
|
|
718
|
-
}, 0);
|
|
719
|
-
});
|
|
720
|
-
});
|
|
721
|
-
return subscription;
|
|
722
|
-
}
|
|
723
|
-
/**
|
|
724
|
-
* Fake disconnect. Does Nothing.
|
|
725
|
-
*/
|
|
726
|
-
disconnect() {
|
|
727
|
-
return Promise.resolve();
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
exports.StreamingMockCometClient = StreamingMockCometClient;
|
|
731
|
-
/**
|
|
732
|
-
* Mock class for Salesforce Orgs.
|
|
733
|
-
*
|
|
734
|
-
* @example
|
|
735
|
-
* ```
|
|
736
|
-
* const testOrg = new MockTestOrgData();
|
|
737
|
-
* await $$.stubAuths(testOrg)
|
|
738
|
-
* ```
|
|
739
|
-
*/
|
|
740
|
-
class MockTestOrgData {
|
|
741
|
-
constructor(id = uniqid(), options) {
|
|
742
|
-
this.testId = id;
|
|
743
|
-
this.userId = `user_id_${this.testId}`;
|
|
744
|
-
this.orgId = `${this.testId}`;
|
|
745
|
-
this.username = options?.username ?? `admin_${this.testId}@gb.org`;
|
|
746
|
-
this.loginUrl = `https://login.${this.testId}.salesforce.com`;
|
|
747
|
-
this.instanceUrl = `https://instance.${this.testId}.salesforce.com`;
|
|
748
|
-
this.clientId = `${this.testId}/client_id`;
|
|
749
|
-
this.clientSecret = `${this.testId}/client_secret`;
|
|
750
|
-
this.authcode = `${this.testId}/authcode`;
|
|
751
|
-
this.accessToken = `${this.testId}/accessToken`;
|
|
752
|
-
this.refreshToken = `${this.testId}/refreshToken`;
|
|
753
|
-
this.redirectUri = 'http://localhost:1717/OauthRedirect';
|
|
754
|
-
}
|
|
755
|
-
/**
|
|
756
|
-
* Add devhub username to properties.
|
|
757
|
-
*/
|
|
758
|
-
createDevHubUsername(username) {
|
|
759
|
-
this.devHubUsername = username;
|
|
760
|
-
}
|
|
761
|
-
/**
|
|
762
|
-
* Mark this org as a devhub.
|
|
763
|
-
*/
|
|
764
|
-
makeDevHub() {
|
|
765
|
-
this.isDevHub = true;
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* Returns a MockTestOrgData that represents a user created in the org.
|
|
769
|
-
*/
|
|
770
|
-
createUser(user) {
|
|
771
|
-
const userMock = new MockTestOrgData();
|
|
772
|
-
userMock.username = user;
|
|
773
|
-
userMock.aliases = this.aliases;
|
|
774
|
-
userMock.configs = this.configs;
|
|
775
|
-
userMock.devHubUsername = this.devHubUsername;
|
|
776
|
-
userMock.orgId = this.orgId;
|
|
777
|
-
userMock.loginUrl = this.loginUrl;
|
|
778
|
-
userMock.instanceUrl = this.instanceUrl;
|
|
779
|
-
userMock.clientId = this.clientId;
|
|
780
|
-
userMock.clientSecret = this.clientSecret;
|
|
781
|
-
userMock.redirectUri = this.redirectUri;
|
|
782
|
-
userMock.isDevHub = this.isDevHub;
|
|
783
|
-
userMock.isScratchOrg = this.isScratchOrg;
|
|
784
|
-
userMock.isExpired = this.isExpired;
|
|
785
|
-
return userMock;
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* Return mock user information based on this org.
|
|
789
|
-
*/
|
|
790
|
-
getMockUserInfo() {
|
|
791
|
-
return {
|
|
792
|
-
Id: this.userId,
|
|
793
|
-
Username: this.username,
|
|
794
|
-
LastName: `user_lastname_${this.testId}`,
|
|
795
|
-
Alias: this.aliases ? this.aliases[0] : 'user_alias_blah',
|
|
796
|
-
Configs: this.configs,
|
|
797
|
-
TimeZoneSidKey: `user_timezonesidkey_${this.testId}`,
|
|
798
|
-
LocaleSidKey: `user_localesidkey_${this.testId}`,
|
|
799
|
-
EmailEncodingKey: `user_emailencodingkey_${this.testId}`,
|
|
800
|
-
ProfileId: `user_profileid_${this.testId}`,
|
|
801
|
-
LanguageLocaleKey: `user_languagelocalekey_${this.testId}`,
|
|
802
|
-
Email: `user_email@${this.testId}.com`,
|
|
803
|
-
};
|
|
804
|
-
}
|
|
805
|
-
/**
|
|
806
|
-
* Return the auth config file contents.
|
|
807
|
-
*/
|
|
808
|
-
async getConfig() {
|
|
809
|
-
const crypto = await crypto_2.Crypto.create();
|
|
810
|
-
const config = {};
|
|
811
|
-
config.orgId = this.orgId;
|
|
812
|
-
const accessToken = crypto.encrypt(this.accessToken);
|
|
813
|
-
if (accessToken) {
|
|
814
|
-
config.accessToken = accessToken;
|
|
815
|
-
}
|
|
816
|
-
const refreshToken = crypto.encrypt(this.refreshToken);
|
|
817
|
-
if (refreshToken) {
|
|
818
|
-
config.refreshToken = refreshToken;
|
|
819
|
-
}
|
|
820
|
-
config.instanceUrl = this.instanceUrl;
|
|
821
|
-
config.loginUrl = this.loginUrl;
|
|
822
|
-
config.username = this.username;
|
|
823
|
-
config.createdOrgInstance = 'CS1';
|
|
824
|
-
config.created = '1519163543003';
|
|
825
|
-
config.userId = this.userId;
|
|
826
|
-
config.tracksSource = this.tracksSource;
|
|
827
|
-
if (this.devHubUsername) {
|
|
828
|
-
config.devHubUsername = this.devHubUsername;
|
|
829
|
-
}
|
|
830
|
-
config.isDevHub = this.isDevHub;
|
|
831
|
-
return config;
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Return the Connection for the org.
|
|
835
|
-
*/
|
|
836
|
-
async getConnection() {
|
|
837
|
-
return (await org_1.Org.create({ aliasOrUsername: this.username })).getConnection();
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
exports.MockTestOrgData = MockTestOrgData;
|
|
841
|
-
/**
|
|
842
|
-
* Mock class for Salesforce Sandboxes.
|
|
843
|
-
*
|
|
844
|
-
* @example
|
|
845
|
-
* ```
|
|
846
|
-
* const testOrg = new MockTestSandboxData();
|
|
847
|
-
* await $$.stubSandboxes(testOrg)
|
|
848
|
-
* ```
|
|
849
|
-
*/
|
|
850
|
-
class MockTestSandboxData {
|
|
851
|
-
constructor(id = uniqid(), options) {
|
|
852
|
-
this.id = id;
|
|
853
|
-
this.sandboxOrgId = id;
|
|
854
|
-
this.prodOrgUsername = options?.prodOrgUsername ?? `admin_${id}@gb.org`;
|
|
855
|
-
this.sandboxName = options?.name ?? `sandbox_${id}`;
|
|
856
|
-
this.username = options?.username ?? `${this.prodOrgUsername}.sandbox`;
|
|
857
|
-
}
|
|
858
|
-
/**
|
|
859
|
-
* Return the auth config file contents.
|
|
860
|
-
*/
|
|
861
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
862
|
-
async getConfig() {
|
|
863
|
-
return {
|
|
864
|
-
sandboxOrgId: this.sandboxOrgId,
|
|
865
|
-
prodOrgUsername: this.prodOrgUsername,
|
|
866
|
-
sandboxName: this.sandboxName,
|
|
867
|
-
sandboxUsername: this.username,
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
exports.MockTestSandboxData = MockTestSandboxData;
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2020, salesforce.com, inc.
|
|
4
|
+
* All rights reserved.
|
|
5
|
+
* Licensed under the BSD 3-Clause license.
|
|
6
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
7
|
+
*/
|
|
8
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
9
|
+
/* eslint-disable class-methods-use-this */
|
|
10
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
11
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
12
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
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 = exports.TestContext = void 0;
|
|
15
|
+
const crypto_1 = require("crypto");
|
|
16
|
+
const events_1 = require("events");
|
|
17
|
+
const os_1 = require("os");
|
|
18
|
+
const path_1 = require("path");
|
|
19
|
+
const util = require("util");
|
|
20
|
+
const kit_1 = require("@salesforce/kit");
|
|
21
|
+
const ts_sinon_1 = require("@salesforce/ts-sinon");
|
|
22
|
+
const ts_types_1 = require("@salesforce/ts-types");
|
|
23
|
+
const configAggregator_1 = require("./config/configAggregator");
|
|
24
|
+
const configFile_1 = require("./config/configFile");
|
|
25
|
+
const connection_1 = require("./org/connection");
|
|
26
|
+
const crypto_2 = require("./crypto/crypto");
|
|
27
|
+
const logger_1 = require("./logger");
|
|
28
|
+
const messages_1 = require("./messages");
|
|
29
|
+
const sfError_1 = require("./sfError");
|
|
30
|
+
const sfProject_1 = require("./sfProject");
|
|
31
|
+
const streamingClient_1 = require("./status/streamingClient");
|
|
32
|
+
const stateAggregator_1 = require("./stateAggregator");
|
|
33
|
+
const org_1 = require("./org");
|
|
34
|
+
const sandboxAccessor_1 = require("./stateAggregator/accessors/sandboxAccessor");
|
|
35
|
+
const aliasesConfig_1 = require("./config/aliasesConfig");
|
|
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;
|
|
265
|
+
/**
|
|
266
|
+
* A function to generate a unique id and return it in the context of a template, if supplied.
|
|
267
|
+
*
|
|
268
|
+
* A template is a string that can contain `${%s}` to be replaced with a unique id.
|
|
269
|
+
* If the template contains the "%s" placeholder, it will be replaced with the unique id otherwise the id will be appended to the template.
|
|
270
|
+
*
|
|
271
|
+
* @param options an object with the following properties:
|
|
272
|
+
* - template: a template string.
|
|
273
|
+
* - length: the length of the unique id as presented in hexadecimal.
|
|
274
|
+
*/
|
|
275
|
+
function uniqid(options) {
|
|
276
|
+
const uniqueString = (0, crypto_1.randomBytes)(Math.ceil((options?.length ?? 32) / 2.0))
|
|
277
|
+
.toString('hex')
|
|
278
|
+
.slice(0, options?.length ?? 32);
|
|
279
|
+
if (!options?.template) {
|
|
280
|
+
return uniqueString;
|
|
281
|
+
}
|
|
282
|
+
return options.template.includes('%s')
|
|
283
|
+
? util.format(options.template, uniqueString)
|
|
284
|
+
: `${options.template}${uniqueString}`;
|
|
285
|
+
}
|
|
286
|
+
exports.uniqid = uniqid;
|
|
287
|
+
function getTestLocalPath(uid) {
|
|
288
|
+
return (0, path_1.join)((0, os_1.tmpdir)(), uid, 'sfdx_core', 'local');
|
|
289
|
+
}
|
|
290
|
+
function getTestGlobalPath(uid) {
|
|
291
|
+
return (0, path_1.join)((0, os_1.tmpdir)(), uid, 'sfdx_core', 'global');
|
|
292
|
+
}
|
|
293
|
+
function retrieveRootPathSync(isGlobal, uid = uniqid()) {
|
|
294
|
+
return isGlobal ? getTestGlobalPath(uid) : getTestLocalPath(uid);
|
|
295
|
+
}
|
|
296
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
297
|
+
async function retrieveRootPath(isGlobal, uid = uniqid()) {
|
|
298
|
+
return retrieveRootPathSync(isGlobal, uid);
|
|
299
|
+
}
|
|
300
|
+
function defaultFakeConnectionRequest() {
|
|
301
|
+
return Promise.resolve((0, ts_types_1.ensureAnyJson)({ records: [] }));
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Instantiate a @salesforce/core test context. This is automatically created by `const $$ = testSetup()`
|
|
305
|
+
* but is useful if you don't want to have a global stub of @salesforce/core and you want to isolate it to
|
|
306
|
+
* a single describe.
|
|
307
|
+
*
|
|
308
|
+
* **Note:** Call `stubContext` in your beforeEach to have clean stubs of @salesforce/core every test run.
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```
|
|
312
|
+
* const $$ = instantiateContext();
|
|
313
|
+
*
|
|
314
|
+
* beforeEach(() => {
|
|
315
|
+
* $$.init()
|
|
316
|
+
* });
|
|
317
|
+
*
|
|
318
|
+
* afterEach(() => {
|
|
319
|
+
* $$.restore();
|
|
320
|
+
* });
|
|
321
|
+
* ```
|
|
322
|
+
* @param sinon
|
|
323
|
+
*/
|
|
324
|
+
const instantiateContext = (sinon) => new TestContext({ sinon, setup: false });
|
|
325
|
+
exports.instantiateContext = instantiateContext;
|
|
326
|
+
/**
|
|
327
|
+
* Stub a @salesforce/core test context. This will mock out logging to a file, config file reading and writing,
|
|
328
|
+
* local and global path resolution, and http request using connection (soon)*.
|
|
329
|
+
*
|
|
330
|
+
* This is automatically stubbed in the global beforeEach created by
|
|
331
|
+
* `const $$ = testSetup()` but is useful if you don't want to have a global stub of @salesforce/core and you
|
|
332
|
+
* want to isolate it to a single describe.
|
|
333
|
+
*
|
|
334
|
+
* **Note:** Always call `restoreContext` in your afterEach.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* ```
|
|
338
|
+
* const $$ = instantiateContext();
|
|
339
|
+
*
|
|
340
|
+
* beforeEach(() => {
|
|
341
|
+
* $$.init()
|
|
342
|
+
* });
|
|
343
|
+
*
|
|
344
|
+
* afterEach(() => {
|
|
345
|
+
* $$.restore();
|
|
346
|
+
* });
|
|
347
|
+
* ```
|
|
348
|
+
* @param testContext
|
|
349
|
+
*/
|
|
350
|
+
const stubContext = (testContext) => {
|
|
351
|
+
// Turn off the interoperability feature so that we don't have to mock
|
|
352
|
+
// the old .sfdx config files
|
|
353
|
+
global_1.Global.SFDX_INTEROPERABILITY = false;
|
|
354
|
+
const stubs = {};
|
|
355
|
+
// Most core files create a child logger so stub this to return our test logger.
|
|
356
|
+
(0, ts_sinon_1.stubMethod)(testContext.SANDBOX, logger_1.Logger, 'child').resolves(testContext.TEST_LOGGER);
|
|
357
|
+
(0, ts_sinon_1.stubMethod)(testContext.SANDBOX, logger_1.Logger, 'childFromRoot').returns(testContext.TEST_LOGGER);
|
|
358
|
+
testContext.inProject(true);
|
|
359
|
+
testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile, 'resolveRootFolder').callsFake((isGlobal) => testContext.rootPathRetriever(isGlobal, testContext.id));
|
|
360
|
+
testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile, 'resolveRootFolderSync').callsFake((isGlobal) => testContext.rootPathRetrieverSync(isGlobal, testContext.id));
|
|
361
|
+
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.PROJECT, sfProject_1.SfProjectJson.prototype, 'doesPackageExist').callsFake(() => true);
|
|
362
|
+
const initStubForRead = (configFile) => {
|
|
363
|
+
const stub = testContext.configStubs[configFile.constructor.name] ?? {};
|
|
364
|
+
// init calls read calls getPath which sets the path on the config file the first time.
|
|
365
|
+
// Since read is now stubbed, make sure to call getPath to initialize it.
|
|
366
|
+
configFile.getPath();
|
|
367
|
+
// @ts-ignore set this to true to avoid an infinite loop in tests when reading config files.
|
|
368
|
+
configFile.hasRead = true;
|
|
369
|
+
return stub;
|
|
370
|
+
};
|
|
371
|
+
const readSync = function (newContents) {
|
|
372
|
+
const stub = initStubForRead(this);
|
|
373
|
+
this.setContentsFromObject(newContents ?? stub.contents ?? {});
|
|
374
|
+
return this.getContents();
|
|
375
|
+
};
|
|
376
|
+
const read = async function () {
|
|
377
|
+
const stub = initStubForRead(this);
|
|
378
|
+
if (stub.readFn) {
|
|
379
|
+
return stub.readFn.call(this);
|
|
380
|
+
}
|
|
381
|
+
if (stub.retrieveContents) {
|
|
382
|
+
return readSync.call(this, await stub.retrieveContents.call(this));
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
return readSync.call(this);
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
// Mock out all config file IO for all tests. They can restore individually if they need original functionality.
|
|
389
|
+
// @ts-ignore
|
|
390
|
+
stubs.configRead = testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile.prototype, 'readSync').callsFake(readSync);
|
|
391
|
+
stubs.configReadSync = testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile.prototype, 'read').callsFake(read);
|
|
392
|
+
const writeSync = function (newContents) {
|
|
393
|
+
if (!testContext.configStubs[this.constructor.name]) {
|
|
394
|
+
testContext.configStubs[this.constructor.name] = {};
|
|
395
|
+
}
|
|
396
|
+
const stub = testContext.configStubs[this.constructor.name];
|
|
397
|
+
if (!stub)
|
|
398
|
+
return;
|
|
399
|
+
this.setContents(newContents ?? this.getContents());
|
|
400
|
+
stub.contents = this.toObject();
|
|
401
|
+
};
|
|
402
|
+
const write = async function (newContents) {
|
|
403
|
+
if (!testContext.configStubs[this.constructor.name]) {
|
|
404
|
+
testContext.configStubs[this.constructor.name] = {};
|
|
405
|
+
}
|
|
406
|
+
const stub = testContext.configStubs[this.constructor.name];
|
|
407
|
+
if (!stub)
|
|
408
|
+
return;
|
|
409
|
+
if (stub.writeFn) {
|
|
410
|
+
return stub.writeFn.call(this, newContents);
|
|
411
|
+
}
|
|
412
|
+
if (stub.updateContents) {
|
|
413
|
+
writeSync.call(this, await stub.updateContents.call(this));
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
writeSync.call(this);
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
stubs.configWriteSync = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONFIG, configFile_1.ConfigFile.prototype, 'writeSync').callsFake(writeSync);
|
|
420
|
+
stubs.configWrite = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONFIG, configFile_1.ConfigFile.prototype, 'write').callsFake(write);
|
|
421
|
+
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CRYPTO, crypto_2.Crypto.prototype, 'getKeyChain').callsFake(() => Promise.resolve({
|
|
422
|
+
setPassword: () => Promise.resolve(),
|
|
423
|
+
getPassword: (data, cb) => cb(undefined, '12345678901234567890123456789012'),
|
|
424
|
+
}));
|
|
425
|
+
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONNECTION, connection_1.Connection.prototype, 'isResolvable').resolves(true);
|
|
426
|
+
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONNECTION, connection_1.Connection.prototype, 'request').callsFake(function (request, options) {
|
|
427
|
+
if (request === `${this.instanceUrl}/services/data`) {
|
|
428
|
+
return Promise.resolve([{ version: '42.0' }]);
|
|
429
|
+
}
|
|
430
|
+
return testContext.fakeConnectionRequest.call(this, request, options);
|
|
431
|
+
});
|
|
432
|
+
stubs.configExists = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.ORGS, stateAggregator_1.OrgAccessor.prototype, 'exists').callsFake(async function (username) {
|
|
433
|
+
// @ts-expect-error because private member
|
|
434
|
+
if ([...this.contents.keys()].includes(username))
|
|
435
|
+
return Promise.resolve(true);
|
|
436
|
+
else
|
|
437
|
+
return Promise.resolve(false);
|
|
438
|
+
});
|
|
439
|
+
stubs.configRemove = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.ORGS, stateAggregator_1.OrgAccessor.prototype, 'remove').callsFake(async function (username) {
|
|
440
|
+
// @ts-expect-error because private member
|
|
441
|
+
if ([...this.contents.keys()].includes(username))
|
|
442
|
+
return Promise.resolve(true);
|
|
443
|
+
else
|
|
444
|
+
return Promise.resolve(false);
|
|
445
|
+
});
|
|
446
|
+
// Always start with the default and tests beforeEach or it methods can override it.
|
|
447
|
+
testContext.fakeConnectionRequest = defaultFakeConnectionRequest;
|
|
448
|
+
testContext.stubs = stubs;
|
|
449
|
+
return stubs;
|
|
450
|
+
};
|
|
451
|
+
exports.stubContext = stubContext;
|
|
452
|
+
/**
|
|
453
|
+
* Restore a @salesforce/core test context. This is automatically stubbed in the global beforeEach created by
|
|
454
|
+
* `const $$ = testSetup()` but is useful if you don't want to have a global stub of @salesforce/core and you
|
|
455
|
+
* want to isolate it to a single describe.
|
|
456
|
+
*
|
|
457
|
+
* @example
|
|
458
|
+
* ```
|
|
459
|
+
* const $$ = instantiateContext();
|
|
460
|
+
*
|
|
461
|
+
* beforeEach(() => {
|
|
462
|
+
* $$.init()
|
|
463
|
+
* });
|
|
464
|
+
*
|
|
465
|
+
* afterEach(() => {
|
|
466
|
+
* $$.restore();
|
|
467
|
+
* });
|
|
468
|
+
* ```
|
|
469
|
+
* @param testContext
|
|
470
|
+
*/
|
|
471
|
+
const restoreContext = (testContext) => {
|
|
472
|
+
testContext.SANDBOX.restore();
|
|
473
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
474
|
+
Object.values(testContext.SANDBOXES).forEach((theSandbox) => theSandbox.restore());
|
|
475
|
+
testContext.configStubs = {};
|
|
476
|
+
// Give each test run a clean StateAggregator
|
|
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;
|
|
481
|
+
};
|
|
482
|
+
exports.restoreContext = restoreContext;
|
|
483
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
484
|
+
const _testSetup = (sinon) => {
|
|
485
|
+
const testContext = (0, exports.instantiateContext)(sinon);
|
|
486
|
+
beforeEach(() => {
|
|
487
|
+
// Allow each test to have their own config aggregator
|
|
488
|
+
// @ts-ignore clear for testing.
|
|
489
|
+
delete configAggregator_1.ConfigAggregator.instance;
|
|
490
|
+
testContext.stubs = (0, exports.stubContext)(testContext);
|
|
491
|
+
});
|
|
492
|
+
afterEach(() => {
|
|
493
|
+
(0, exports.restoreContext)(testContext);
|
|
494
|
+
});
|
|
495
|
+
return testContext;
|
|
496
|
+
};
|
|
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
|
+
*
|
|
515
|
+
* Use to mock out different pieces of sfdx-core to make testing easier. This will mock out
|
|
516
|
+
* logging to a file, config file reading and writing, local and global path resolution, and
|
|
517
|
+
* *http request using connection (soon)*.
|
|
518
|
+
*
|
|
519
|
+
* **Note:** The testSetup should be outside of the describe. If you need to stub per test, use
|
|
520
|
+
* `TestContext`.
|
|
521
|
+
* ```
|
|
522
|
+
* // In a mocha tests
|
|
523
|
+
* import testSetup from '@salesforce/core/lib/testSetup';
|
|
524
|
+
*
|
|
525
|
+
* const $$ = testSetup();
|
|
526
|
+
*
|
|
527
|
+
* describe(() => {
|
|
528
|
+
* it('test', () => {
|
|
529
|
+
* // Stub out your own method
|
|
530
|
+
* $$.SANDBOX.stub(MyClass.prototype, 'myMethod').returnsFake(() => {});
|
|
531
|
+
*
|
|
532
|
+
* // Set the contents that is used when aliases are read. Same for all config files.
|
|
533
|
+
* $$.stubAliases({ 'myTestAlias': 'user@company.com' });
|
|
534
|
+
*
|
|
535
|
+
* // Will use the contents set above.
|
|
536
|
+
* const username = (await StateAggregator.getInstance()).aliases.resolveUsername('myTestAlias');
|
|
537
|
+
* expect(username).to.equal('user@company.com');
|
|
538
|
+
* });
|
|
539
|
+
* });
|
|
540
|
+
* ```
|
|
541
|
+
*/
|
|
542
|
+
exports.testSetup = (0, kit_1.once)(_testSetup);
|
|
543
|
+
/**
|
|
544
|
+
* A pre-canned error for try/catch testing.
|
|
545
|
+
*
|
|
546
|
+
* **See** {@link shouldThrow}
|
|
547
|
+
*/
|
|
548
|
+
exports.unexpectedResult = new sfError_1.SfError('This code was expected to fail', 'UnexpectedResult');
|
|
549
|
+
/**
|
|
550
|
+
* Use for this testing pattern:
|
|
551
|
+
* ```
|
|
552
|
+
* try {
|
|
553
|
+
* await call()
|
|
554
|
+
* assert.fail('this should never happen');
|
|
555
|
+
* } catch (e) {
|
|
556
|
+
* ...
|
|
557
|
+
* }
|
|
558
|
+
*
|
|
559
|
+
* Just do this
|
|
560
|
+
*
|
|
561
|
+
* try {
|
|
562
|
+
* await shouldThrow(call()); // If this succeeds unexpectedResultError is thrown.
|
|
563
|
+
* } catch(e) {
|
|
564
|
+
* ...
|
|
565
|
+
* }
|
|
566
|
+
* ```
|
|
567
|
+
*
|
|
568
|
+
* @param f The async function that is expected to throw.
|
|
569
|
+
*/
|
|
570
|
+
async function shouldThrow(f, message) {
|
|
571
|
+
await f;
|
|
572
|
+
if (message) {
|
|
573
|
+
throw new sfError_1.SfError(message, 'UnexpectedResult');
|
|
574
|
+
}
|
|
575
|
+
else {
|
|
576
|
+
throw exports.unexpectedResult;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
exports.shouldThrow = shouldThrow;
|
|
580
|
+
/**
|
|
581
|
+
* Use for this testing pattern:
|
|
582
|
+
* ```
|
|
583
|
+
* try {
|
|
584
|
+
* call()
|
|
585
|
+
* assert.fail('this should never happen');
|
|
586
|
+
* } catch (e) {
|
|
587
|
+
* ...
|
|
588
|
+
* }
|
|
589
|
+
*
|
|
590
|
+
* Just do this
|
|
591
|
+
*
|
|
592
|
+
* try {
|
|
593
|
+
* shouldThrowSync(call); // If this succeeds unexpectedResultError is thrown.
|
|
594
|
+
* } catch(e) {
|
|
595
|
+
* ...
|
|
596
|
+
* }
|
|
597
|
+
* ```
|
|
598
|
+
*
|
|
599
|
+
* @param f The function that is expected to throw.
|
|
600
|
+
*/
|
|
601
|
+
function shouldThrowSync(f, message) {
|
|
602
|
+
f();
|
|
603
|
+
if (message) {
|
|
604
|
+
throw new sfError_1.SfError(message, 'UnexpectedResult');
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
throw exports.unexpectedResult;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
exports.shouldThrowSync = shouldThrowSync;
|
|
611
|
+
/**
|
|
612
|
+
* A helper to determine if a subscription will use callback or errorback.
|
|
613
|
+
* Enable errback to simulate a subscription failure.
|
|
614
|
+
*/
|
|
615
|
+
var StreamingMockSubscriptionCall;
|
|
616
|
+
(function (StreamingMockSubscriptionCall) {
|
|
617
|
+
StreamingMockSubscriptionCall[StreamingMockSubscriptionCall["CALLBACK"] = 0] = "CALLBACK";
|
|
618
|
+
StreamingMockSubscriptionCall[StreamingMockSubscriptionCall["ERRORBACK"] = 1] = "ERRORBACK";
|
|
619
|
+
})(StreamingMockSubscriptionCall = exports.StreamingMockSubscriptionCall || (exports.StreamingMockSubscriptionCall = {}));
|
|
620
|
+
/**
|
|
621
|
+
* Simulates a comet subscription to a streaming channel.
|
|
622
|
+
*/
|
|
623
|
+
class StreamingMockCometSubscription extends events_1.EventEmitter {
|
|
624
|
+
constructor(options) {
|
|
625
|
+
super();
|
|
626
|
+
this.options = options;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Sets up a streaming subscription callback to occur after the setTimeout event loop phase.
|
|
630
|
+
*
|
|
631
|
+
* @param callback The function to invoke.
|
|
632
|
+
*/
|
|
633
|
+
callback(callback) {
|
|
634
|
+
if (this.options.subscriptionCall === StreamingMockSubscriptionCall.CALLBACK) {
|
|
635
|
+
setTimeout(() => {
|
|
636
|
+
callback();
|
|
637
|
+
super.emit(StreamingMockCometSubscription.SUBSCRIPTION_COMPLETE);
|
|
638
|
+
}, 0);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Sets up a streaming subscription errback to occur after the setTimeout event loop phase.
|
|
643
|
+
*
|
|
644
|
+
* @param callback The function to invoke.
|
|
645
|
+
*/
|
|
646
|
+
errback(callback) {
|
|
647
|
+
if (this.options.subscriptionCall === StreamingMockSubscriptionCall.ERRORBACK) {
|
|
648
|
+
const error = this.options.subscriptionErrbackError;
|
|
649
|
+
if (!error)
|
|
650
|
+
return;
|
|
651
|
+
setTimeout(() => {
|
|
652
|
+
callback(error);
|
|
653
|
+
super.emit(StreamingMockCometSubscription.SUBSCRIPTION_FAILED);
|
|
654
|
+
}, 0);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
exports.StreamingMockCometSubscription = StreamingMockCometSubscription;
|
|
659
|
+
StreamingMockCometSubscription.SUBSCRIPTION_COMPLETE = 'subscriptionComplete';
|
|
660
|
+
StreamingMockCometSubscription.SUBSCRIPTION_FAILED = 'subscriptionFailed';
|
|
661
|
+
/**
|
|
662
|
+
* Simulates a comet client. To the core streaming client this mocks the internal comet impl.
|
|
663
|
+
* The uses setTimeout(0ms) event loop phase just so the client can simulate actual streaming without the response
|
|
664
|
+
* latency.
|
|
665
|
+
*/
|
|
666
|
+
class StreamingMockCometClient extends streamingClient_1.CometClient {
|
|
667
|
+
/**
|
|
668
|
+
* Constructor
|
|
669
|
+
*
|
|
670
|
+
* @param {StreamingMockCometSubscriptionOptions} options Extends the StreamingClient options.
|
|
671
|
+
*/
|
|
672
|
+
constructor(options) {
|
|
673
|
+
super();
|
|
674
|
+
this.options = options;
|
|
675
|
+
if (!this.options.messagePlaylist) {
|
|
676
|
+
this.options.messagePlaylist = [{ id: this.options.id }];
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Fake addExtension. Does nothing.
|
|
681
|
+
*/
|
|
682
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
|
683
|
+
addExtension(extension) { }
|
|
684
|
+
/**
|
|
685
|
+
* Fake disable. Does nothing.
|
|
686
|
+
*/
|
|
687
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
|
688
|
+
disable(label) { }
|
|
689
|
+
/**
|
|
690
|
+
* Fake handshake that invoke callback after the setTimeout event phase.
|
|
691
|
+
*
|
|
692
|
+
* @param callback The function to invoke.
|
|
693
|
+
*/
|
|
694
|
+
handshake(callback) {
|
|
695
|
+
setTimeout(() => {
|
|
696
|
+
callback();
|
|
697
|
+
}, 0);
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Fake setHeader. Does nothing,
|
|
701
|
+
*/
|
|
702
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
|
|
703
|
+
setHeader(name, value) { }
|
|
704
|
+
/**
|
|
705
|
+
* Fake subscription that completed after the setTimout event phase.
|
|
706
|
+
*
|
|
707
|
+
* @param channel The streaming channel.
|
|
708
|
+
* @param callback The function to invoke after the subscription completes.
|
|
709
|
+
*/
|
|
710
|
+
subscribe(channel, callback) {
|
|
711
|
+
const subscription = new StreamingMockCometSubscription(this.options);
|
|
712
|
+
subscription.on('subscriptionComplete', () => {
|
|
713
|
+
if (!this.options.messagePlaylist)
|
|
714
|
+
return;
|
|
715
|
+
Object.values(this.options.messagePlaylist).forEach((message) => {
|
|
716
|
+
setTimeout(() => {
|
|
717
|
+
callback(message);
|
|
718
|
+
}, 0);
|
|
719
|
+
});
|
|
720
|
+
});
|
|
721
|
+
return subscription;
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Fake disconnect. Does Nothing.
|
|
725
|
+
*/
|
|
726
|
+
disconnect() {
|
|
727
|
+
return Promise.resolve();
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
exports.StreamingMockCometClient = StreamingMockCometClient;
|
|
731
|
+
/**
|
|
732
|
+
* Mock class for Salesforce Orgs.
|
|
733
|
+
*
|
|
734
|
+
* @example
|
|
735
|
+
* ```
|
|
736
|
+
* const testOrg = new MockTestOrgData();
|
|
737
|
+
* await $$.stubAuths(testOrg)
|
|
738
|
+
* ```
|
|
739
|
+
*/
|
|
740
|
+
class MockTestOrgData {
|
|
741
|
+
constructor(id = uniqid(), options) {
|
|
742
|
+
this.testId = id;
|
|
743
|
+
this.userId = `user_id_${this.testId}`;
|
|
744
|
+
this.orgId = `${this.testId}`;
|
|
745
|
+
this.username = options?.username ?? `admin_${this.testId}@gb.org`;
|
|
746
|
+
this.loginUrl = `https://login.${this.testId}.salesforce.com`;
|
|
747
|
+
this.instanceUrl = `https://instance.${this.testId}.salesforce.com`;
|
|
748
|
+
this.clientId = `${this.testId}/client_id`;
|
|
749
|
+
this.clientSecret = `${this.testId}/client_secret`;
|
|
750
|
+
this.authcode = `${this.testId}/authcode`;
|
|
751
|
+
this.accessToken = `${this.testId}/accessToken`;
|
|
752
|
+
this.refreshToken = `${this.testId}/refreshToken`;
|
|
753
|
+
this.redirectUri = 'http://localhost:1717/OauthRedirect';
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Add devhub username to properties.
|
|
757
|
+
*/
|
|
758
|
+
createDevHubUsername(username) {
|
|
759
|
+
this.devHubUsername = username;
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Mark this org as a devhub.
|
|
763
|
+
*/
|
|
764
|
+
makeDevHub() {
|
|
765
|
+
this.isDevHub = true;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Returns a MockTestOrgData that represents a user created in the org.
|
|
769
|
+
*/
|
|
770
|
+
createUser(user) {
|
|
771
|
+
const userMock = new MockTestOrgData();
|
|
772
|
+
userMock.username = user;
|
|
773
|
+
userMock.aliases = this.aliases;
|
|
774
|
+
userMock.configs = this.configs;
|
|
775
|
+
userMock.devHubUsername = this.devHubUsername;
|
|
776
|
+
userMock.orgId = this.orgId;
|
|
777
|
+
userMock.loginUrl = this.loginUrl;
|
|
778
|
+
userMock.instanceUrl = this.instanceUrl;
|
|
779
|
+
userMock.clientId = this.clientId;
|
|
780
|
+
userMock.clientSecret = this.clientSecret;
|
|
781
|
+
userMock.redirectUri = this.redirectUri;
|
|
782
|
+
userMock.isDevHub = this.isDevHub;
|
|
783
|
+
userMock.isScratchOrg = this.isScratchOrg;
|
|
784
|
+
userMock.isExpired = this.isExpired;
|
|
785
|
+
return userMock;
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Return mock user information based on this org.
|
|
789
|
+
*/
|
|
790
|
+
getMockUserInfo() {
|
|
791
|
+
return {
|
|
792
|
+
Id: this.userId,
|
|
793
|
+
Username: this.username,
|
|
794
|
+
LastName: `user_lastname_${this.testId}`,
|
|
795
|
+
Alias: this.aliases ? this.aliases[0] : 'user_alias_blah',
|
|
796
|
+
Configs: this.configs,
|
|
797
|
+
TimeZoneSidKey: `user_timezonesidkey_${this.testId}`,
|
|
798
|
+
LocaleSidKey: `user_localesidkey_${this.testId}`,
|
|
799
|
+
EmailEncodingKey: `user_emailencodingkey_${this.testId}`,
|
|
800
|
+
ProfileId: `user_profileid_${this.testId}`,
|
|
801
|
+
LanguageLocaleKey: `user_languagelocalekey_${this.testId}`,
|
|
802
|
+
Email: `user_email@${this.testId}.com`,
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Return the auth config file contents.
|
|
807
|
+
*/
|
|
808
|
+
async getConfig() {
|
|
809
|
+
const crypto = await crypto_2.Crypto.create();
|
|
810
|
+
const config = {};
|
|
811
|
+
config.orgId = this.orgId;
|
|
812
|
+
const accessToken = crypto.encrypt(this.accessToken);
|
|
813
|
+
if (accessToken) {
|
|
814
|
+
config.accessToken = accessToken;
|
|
815
|
+
}
|
|
816
|
+
const refreshToken = crypto.encrypt(this.refreshToken);
|
|
817
|
+
if (refreshToken) {
|
|
818
|
+
config.refreshToken = refreshToken;
|
|
819
|
+
}
|
|
820
|
+
config.instanceUrl = this.instanceUrl;
|
|
821
|
+
config.loginUrl = this.loginUrl;
|
|
822
|
+
config.username = this.username;
|
|
823
|
+
config.createdOrgInstance = 'CS1';
|
|
824
|
+
config.created = '1519163543003';
|
|
825
|
+
config.userId = this.userId;
|
|
826
|
+
config.tracksSource = this.tracksSource;
|
|
827
|
+
if (this.devHubUsername) {
|
|
828
|
+
config.devHubUsername = this.devHubUsername;
|
|
829
|
+
}
|
|
830
|
+
config.isDevHub = this.isDevHub;
|
|
831
|
+
return config;
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Return the Connection for the org.
|
|
835
|
+
*/
|
|
836
|
+
async getConnection() {
|
|
837
|
+
return (await org_1.Org.create({ aliasOrUsername: this.username })).getConnection();
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
exports.MockTestOrgData = MockTestOrgData;
|
|
841
|
+
/**
|
|
842
|
+
* Mock class for Salesforce Sandboxes.
|
|
843
|
+
*
|
|
844
|
+
* @example
|
|
845
|
+
* ```
|
|
846
|
+
* const testOrg = new MockTestSandboxData();
|
|
847
|
+
* await $$.stubSandboxes(testOrg)
|
|
848
|
+
* ```
|
|
849
|
+
*/
|
|
850
|
+
class MockTestSandboxData {
|
|
851
|
+
constructor(id = uniqid(), options) {
|
|
852
|
+
this.id = id;
|
|
853
|
+
this.sandboxOrgId = id;
|
|
854
|
+
this.prodOrgUsername = options?.prodOrgUsername ?? `admin_${id}@gb.org`;
|
|
855
|
+
this.sandboxName = options?.name ?? `sandbox_${id}`;
|
|
856
|
+
this.username = options?.username ?? `${this.prodOrgUsername}.sandbox`;
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* Return the auth config file contents.
|
|
860
|
+
*/
|
|
861
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
862
|
+
async getConfig() {
|
|
863
|
+
return {
|
|
864
|
+
sandboxOrgId: this.sandboxOrgId,
|
|
865
|
+
prodOrgUsername: this.prodOrgUsername,
|
|
866
|
+
sandboxName: this.sandboxName,
|
|
867
|
+
sandboxUsername: this.username,
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
exports.MockTestSandboxData = MockTestSandboxData;
|
|
872
872
|
//# sourceMappingURL=testSetup.js.map
|