@salesforce/core
Version:
Core libraries to interact with SFDX projects, orgs, and APIs.
905 lines • 34.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockTestSandboxData = exports.MockTestOrgData = exports.StreamingMockCometClient = exports.StreamingMockCometSubscription = exports.StreamingMockSubscriptionCall = exports.unexpectedResult = exports.restoreContext = exports.stubContext = exports.instantiateContext = exports.TestContext = exports.SecureBuffer = exports.uniqid = void 0;
exports.shouldThrow = shouldThrow;
exports.shouldThrowSync = shouldThrowSync;
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
/* eslint-disable no-param-reassign */ // mutate ALL the THINGS!
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable class-methods-use-this */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-call */
const fs = __importStar(require("node:fs"));
const node_events_1 = require("node:events");
const node_os_1 = require("node:os");
const node_path_1 = require("node:path");
const ts_types_1 = require("@salesforce/ts-types");
const configAggregator_1 = require("./config/configAggregator");
const configFile_1 = require("./config/configFile");
const connection_1 = require("./org/connection");
const crypto_1 = require("./crypto/crypto");
const logger_1 = require("./logger/logger");
const messages_1 = require("./messages");
const sfError_1 = require("./sfError");
const sfProject_1 = require("./sfProject");
const aliasAccessorEntireFile = __importStar(require("./stateAggregator/accessors/aliasAccessor"));
const streamingClient_1 = require("./status/streamingClient");
const stateAggregator_1 = require("./stateAggregator/stateAggregator");
const orgAccessor_1 = require("./stateAggregator/accessors/orgAccessor");
const org_1 = require("./org/org");
const user_1 = require("./org/user");
const sandboxAccessor_1 = require("./stateAggregator/accessors/sandboxAccessor");
const global_1 = require("./global");
const uniqid_1 = require("./util/uniqid");
Object.defineProperty(exports, "uniqid", { enumerable: true, get: function () { return uniqid_1.uniqid; } });
// stuff previously imported via /lib/foo and used in unit tests
var secureBuffer_1 = require("./crypto/secureBuffer");
Object.defineProperty(exports, "SecureBuffer", { enumerable: true, get: function () { return secureBuffer_1.SecureBuffer; } });
/**
* Instantiate a @salesforce/core test context.
*/
class TestContext {
/**
* The default sandbox is cleared out before each test run.
*
* **See** [sinon sandbox]{@link https://sinonjs.org/releases/v14/sandbox/}.
*/
SANDBOX;
/**
* An object of different sandboxes. Used when
* needing to restore parts of the system for customized testing.
*/
SANDBOXES;
/**
* The test logger that is used when {@link Logger.child} is used anywhere. It uses memory logging.
*/
TEST_LOGGER;
/**
* id A unique id for the test run.
*/
id = (0, uniqid_1.uniqid)();
/**
* An object used in tests that interact with config files.
*/
configStubs = {};
/**
* A record of stubs created during instantiation.
*/
stubs = {};
constructor(options = {}) {
const opts = { setup: true, ...options };
const sinon = requireSinon(opts.sinon);
;
// Create a global sinon sandbox and a test logger instance for use within tests.
this.SANDBOX = opts.sandbox ?? sinon.createSandbox();
this.SANDBOXES = {
DEFAULT: this.SANDBOX,
CONFIG: sinon.createSandbox(),
PROJECT: sinon.createSandbox(),
CRYPTO: sinon.createSandbox(),
CONNECTION: sinon.createSandbox(),
FS: sinon.createSandbox(),
ORGS: sinon.createSandbox(),
};
this.TEST_LOGGER = new logger_1.Logger({ name: 'SFDX_Core_Test_Logger', useMemoryLogger: true });
if (opts.setup) {
this.setup();
}
}
/**
* Generate unique string.
*/
uniqid() {
return (0, uniqid_1.uniqid)();
}
/**
* A function used when resolving the local path. Calls localPathResolverSync by default.
*
* @param uid Unique id.
*/
async localPathRetriever(uid) {
return Promise.resolve(getTestLocalPath(uid));
}
/**
* A function used when resolving the local path.
*
* @param uid Unique id.
*/
localPathRetrieverSync(uid) {
return getTestLocalPath(uid);
}
/**
* A function used when resolving the global path. Calls globalPathResolverSync by default.
*
* @param uid Unique id.
*/
async globalPathRetriever(uid) {
return Promise.resolve(getTestGlobalPath(uid));
}
/**
* A function used when resolving the global path.
*
* @param uid Unique id.
*/
globalPathRetrieverSync(uid) {
return getTestGlobalPath(uid);
}
/**
* A function used for resolving paths. Calls localPathRetriever and globalPathRetriever.
*
* @param isGlobal `true` if the config is global.
* @param uid user id.
*/
async rootPathRetriever(isGlobal, uid) {
return retrieveRootPath(isGlobal, uid);
}
/**
* A function used for resolving paths. Calls localPathRetrieverSync and globalPathRetrieverSync.
*
* @param isGlobal `true` if the config is global.
* @param uid user id.
*/
rootPathRetrieverSync(isGlobal, uid) {
return retrieveRootPathSync(isGlobal, uid);
}
/**
* Used to mock http request to Salesforce.
*
* @param request An HttpRequest.
* @param options Additional options.
*
* **See** {@link Connection.request}
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async fakeConnectionRequest(request, options) {
return defaultFakeConnectionRequest();
}
/**
* Gets a config stub contents by name.
*
* @param name The name of the config.
* @param group If the config supports groups.
*/
getConfigStubContents(name, group) {
const stub = this.configStubs[name];
if (stub?.contents) {
if (group && stub.contents[group]) {
return (0, ts_types_1.ensureJsonMap)(stub.contents[group]);
}
else {
return stub.contents;
}
}
return {};
}
/**
* Sets a config stub contents by name
*
* @param name The name of the config stub.
* @param value The actual stub contents. The Mock data.
*/
setConfigStubContents(name, value) {
if ((0, ts_types_1.ensureString)(name) && (0, ts_types_1.isJsonMap)(value)) {
this.configStubs[name] = value;
}
}
/**
* Set stubs for working in the context of a SfProject
*/
inProject(inProject = true) {
this.SANDBOXES.PROJECT.restore();
if (inProject) {
this.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPath').callsFake(() => this.localPathRetriever(this.id));
this.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPathSync').callsFake(() => this.localPathRetrieverSync(this.id));
}
else {
this.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPath').rejects(new sfError_1.SfError('', 'InvalidProjectWorkspaceError'));
this.SANDBOXES.PROJECT.stub(sfProject_1.SfProject, 'resolveProjectPathSync').throws(new sfError_1.SfError('', 'InvalidProjectWorkspaceError'));
}
}
/**
* Stub salesforce org authorizations.
*/
async stubAuths(...orgs) {
const entries = await Promise.all(orgs.map(async (org) => [org.username, await org.getConfig()]));
const orgMap = new Map(entries);
// @ts-expect-error because private method
this.SANDBOX.stub(orgAccessor_1.OrgAccessor.prototype, 'getAllFiles').resolves([...orgMap.keys()].map((o) => `${o}.json`));
this.SANDBOX.stub(orgAccessor_1.OrgAccessor.prototype, 'hasFile').callsFake((username) => Promise.resolve(orgMap.has(username)));
const retrieveContents = async function () {
const username = (0, node_path_1.basename)(this.path.replace('.json', ''));
return Promise.resolve(orgMap.get(username) ?? {});
};
this.configStubs.AuthInfoConfig = { retrieveContents };
}
/**
* Stub salesforce user authorizations.
*
* @param users The users to stub.
* The key is the username of the admin user and it must be included in the users array in order to obtain the orgId key for the remaining users.
* The admin user is excluded from the users array.
*
*/
stubUsers(users) {
const mockUsers = Object.values(users).flatMap((orgUsers) => orgUsers.map((user) => {
const userInfo = user.getMockUserInfo();
return {
alias: userInfo.Alias ?? '',
email: userInfo.Email ?? '',
emailEncodingKey: userInfo.EmailEncodingKey ?? '',
id: userInfo.Id ?? '',
languageLocaleKey: userInfo.LanguageLocaleKey ?? '',
lastName: userInfo.LastName ?? '',
localeSidKey: userInfo.LocaleSidKey ?? '',
profileId: userInfo.ProfileId ?? '',
timeZoneSidKey: userInfo.TimeZoneSidKey ?? '',
username: userInfo.Username ?? '',
};
}));
const userOrgsMap = new Map(Object.entries(users).map(([adminUsername, orgs]) => {
const adminOrg = orgs.find((org) => org.username === adminUsername);
return adminOrg
? [adminOrg.orgId, { usernames: orgs.filter((org) => org.username !== adminUsername) }]
: [undefined, undefined];
}));
this.SANDBOX.stub(user_1.User.prototype, 'retrieve').callsFake((username) => {
const user = mockUsers.find((org) => org.username === username);
if (!user)
throw new sfError_1.SfError('User not found', 'UserNotFoundError');
return Promise.resolve(user);
});
const retrieveContents = async function () {
const orgId = (0, node_path_1.basename)(this.path.replace('.json', ''));
return Promise.resolve(userOrgsMap.get(orgId) ?? {});
};
this.configStubs.OrgUsersConfig = { retrieveContents };
}
/**
* Stub salesforce sandbox authorizations.
*/
async stubSandboxes(...sandboxes) {
const entries = (await Promise.all(sandboxes.map(async (sandbox) => [sandbox.username, await sandbox.getConfig()])));
const sandboxMap = new Map(entries);
// @ts-expect-error because private method
this.SANDBOX.stub(sandboxAccessor_1.SandboxAccessor.prototype, 'getAllFiles').resolves([...sandboxMap.keys()].map((o) => `${o}.sandbox.json`));
const retrieveContents = async function () {
const username = (0, node_path_1.basename)(this.path.replace('.sandbox.json', ''));
return Promise.resolve(sandboxMap.get(username) ?? {});
};
this.configStubs.SandboxOrgConfig = { retrieveContents };
}
/**
* Stub the aliases in the global aliases config file.
*/
stubAliases(aliases, group = aliasAccessorEntireFile.DEFAULT_GROUP) {
// we don't really "stub" these since they don't use configFile.
// write the fileContents to location
fs.mkdirSync((0, node_path_1.dirname)(getAliasFileLocation()), { recursive: true });
fs.writeFileSync(getAliasFileLocation(), JSON.stringify({ [group]: aliases }));
}
/**
* Stub contents in the config file.
*/
async stubConfig(config) {
this.configStubs.Config = { contents: config };
// configAggregator may have already loaded an instance. We're not sure why this happens.
// This seems to solve the problem by forcing a load of the new stubbed config.
await configAggregator_1.ConfigAggregator.create();
}
restore() {
(0, exports.restoreContext)(this);
}
init() {
this.stubs = (0, exports.stubContext)(this);
}
/**
* Add beforeEach and afterEach hooks to init the stubs and restore them.
* This is called automatically when the class is instantiated unless the setup option is set to false.
*/
setup() {
beforeEach(() => {
this.init();
});
afterEach(() => {
this.restore();
});
}
}
exports.TestContext = TestContext;
const requireSinon = (sinon) => {
if (sinon)
return sinon;
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-extraneous-dependencies
const newSinon = require('sinon');
return newSinon;
}
catch (e) {
throw new Error('The package sinon was not found. Add it to your package.json and pass it in to new TestContext({sinon})');
}
};
function getTestLocalPath(uid) {
return (0, node_path_1.join)((0, node_os_1.tmpdir)(), uid, 'sfdx_core', 'local');
}
function getTestGlobalPath(uid) {
return (0, node_path_1.join)((0, node_os_1.tmpdir)(), uid, 'sfdx_core', 'global');
}
function retrieveRootPathSync(isGlobal, uid = (0, uniqid_1.uniqid)()) {
return isGlobal ? getTestGlobalPath(uid) : getTestLocalPath(uid);
}
// eslint-disable-next-line @typescript-eslint/require-await
async function retrieveRootPath(isGlobal, uid = (0, uniqid_1.uniqid)()) {
return retrieveRootPathSync(isGlobal, uid);
}
function defaultFakeConnectionRequest() {
return Promise.resolve((0, ts_types_1.ensureAnyJson)({ records: [] }));
}
/**
* Instantiate a @salesforce/core test context. This is automatically created by `const $$ = testSetup()`
* but is useful if you don't want to have a global stub of @salesforce/core and you want to isolate it to
* a single describe.
*
* **Note:** Call `stubContext` in your beforeEach to have clean stubs of @salesforce/core every test run.
*
* @example
* ```
* const $$ = instantiateContext();
*
* beforeEach(() => {
* $$.init()
* });
*
* afterEach(() => {
* $$.restore();
* });
* ```
* @param sinon
*/
const instantiateContext = (sinon) => new TestContext({ sinon, setup: false });
exports.instantiateContext = instantiateContext;
/**
* Stub a @salesforce/core test context. This will mock out logging to a file, config file reading and writing,
* local and global path resolution, and http request using connection (soon)*.
*
* This is automatically stubbed in the global beforeEach created by
* `const $$ = testSetup()` but is useful if you don't want to have a global stub of @salesforce/core and you
* want to isolate it to a single describe.
*
* **Note:** Always call `restoreContext` in your afterEach.
*
* @example
* ```
* const $$ = instantiateContext();
*
* beforeEach(() => {
* $$.init()
* });
*
* afterEach(() => {
* $$.restore();
* });
* ```
* @param testContext
*/
const stubContext = (testContext) => {
// Turn off the interoperability feature so that we don't have to mock
// the old .sfdx config files
global_1.Global.SFDX_INTEROPERABILITY = false;
const stubs = {};
// Most core files create a child logger so stub this to return our test logger.
testContext.SANDBOX.stub(logger_1.Logger, 'child').resolves(testContext.TEST_LOGGER);
testContext.SANDBOX.stub(logger_1.Logger, 'childFromRoot').returns(testContext.TEST_LOGGER);
testContext.inProject(true);
testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile, 'resolveRootFolder').callsFake((isGlobal) => testContext.rootPathRetriever(isGlobal, testContext.id));
testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile, 'resolveRootFolderSync').callsFake((isGlobal) => testContext.rootPathRetrieverSync(isGlobal, testContext.id));
// @ts-expect-error using private method
testContext.SANDBOXES.PROJECT.stub(sfProject_1.SfProjectJson.prototype, 'doesPackageExist').callsFake(() => true);
const initStubForRead = (configFile) => {
testContext.configStubs[configFile.constructor.name] ??= {};
const stub = testContext.configStubs[configFile.constructor.name] ?? {};
// init calls read calls getPath which sets the path on the config file the first time.
// Since read is now stubbed, make sure to call getPath to initialize it.
configFile.getPath();
// @ts-expect-error: set this to true to avoid an infinite loop in tests when reading config files.
configFile.hasRead = true;
return stub;
};
const readSync = function (newContents) {
const stub = initStubForRead(this);
this.setContentsFromFileContents(newContents ?? stub.contents ?? {});
return this.getContents();
};
const read = async function () {
const stub = initStubForRead(this);
if (stub.readFn) {
return stub.readFn.call(this);
}
if (stub.retrieveContents) {
return readSync.call(this, await stub.retrieveContents.call(this));
}
else {
return readSync.call(this);
}
};
// Mock out all config file IO for all tests. They can restore individually if they need original functionality.
stubs.configRead = testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile.prototype, 'read').callsFake(read);
// @ts-expect-error: muting exact type match for stub readSync
stubs.configReadSync = testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile.prototype, 'readSync').callsFake(readSync);
const writeSync = function () {
testContext.configStubs[this.constructor.name] ??= {};
const stub = testContext.configStubs[this.constructor.name] ?? {};
stub.contents = this.toObject();
};
const write = async function () {
testContext.configStubs[this.constructor.name] ??= {};
const stub = testContext.configStubs[this.constructor.name] ?? {};
if (stub.writeFn) {
return stub.writeFn.call(this);
}
writeSync.call(this);
};
stubs.configWriteSync = testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile.prototype, 'writeSync').callsFake(writeSync);
stubs.configWrite = testContext.SANDBOXES.CONFIG.stub(configFile_1.ConfigFile.prototype, 'write').callsFake(write);
// @ts-expect-error: getKeyChain is private
testContext.SANDBOXES.CRYPTO.stub(crypto_1.Crypto.prototype, 'getKeyChain').callsFake(() =>
// @ts-expect-error: not the full type
Promise.resolve({
setPassword: () => Promise.resolve(),
getPassword: (data, cb) => cb(undefined, '12345678901234567890123456789012'),
}));
testContext.SANDBOXES.CONNECTION.stub(connection_1.Connection.prototype, 'isResolvable').resolves(true);
// @ts-expect-error: just enough of an httpResponse for testing
testContext.SANDBOXES.CONNECTION.stub(connection_1.Connection.prototype, 'request').callsFake(function (request, options) {
if (request === `${this.instanceUrl}/services/data`) {
return Promise.resolve([{ version: '42.0' }]);
}
return testContext.fakeConnectionRequest.call(this, request, options);
});
testContext.SANDBOX.stub(aliasAccessorEntireFile, 'getFileLocation').returns(getAliasFileLocation());
stubs.configExists = testContext.SANDBOXES.ORGS.stub(orgAccessor_1.OrgAccessor.prototype, 'exists').callsFake(async function (username) {
// @ts-expect-error because private member
if ([...this.contents.keys()].includes(username))
return Promise.resolve(true);
else
return Promise.resolve(false);
});
stubs.configRemove = testContext.SANDBOXES.ORGS.stub(orgAccessor_1.OrgAccessor.prototype, 'remove').callsFake(async function (username) {
// @ts-expect-error because private member
if ([...this.contents.keys()].includes(username))
return Promise.resolve();
else
return Promise.resolve();
});
// Always start with the default and tests beforeEach or it methods can override it.
testContext.fakeConnectionRequest = defaultFakeConnectionRequest;
testContext.stubs = stubs;
return stubs;
};
exports.stubContext = stubContext;
const getAliasFileLocation = () => (0, node_path_1.join)((0, node_os_1.tmpdir)(), global_1.Global.SFDX_STATE_FOLDER, aliasAccessorEntireFile.FILENAME);
/**
* Restore a @salesforce/core test context. This is automatically stubbed in the global beforeEach created by
* `const $$ = testSetup()` but is useful if you don't want to have a global stub of @salesforce/core and you
* want to isolate it to a single describe.
*
* @example
* ```
* const $$ = instantiateContext();
*
* beforeEach(() => {
* $$.init()
* });
*
* afterEach(() => {
* $$.restore();
* });
* ```
* @param testContext
*/
const restoreContext = (testContext) => {
// Restore the default value for this setting on restore.
global_1.Global.SFDX_INTEROPERABILITY = true;
testContext.SANDBOX.restore();
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
Object.values(testContext.SANDBOXES).forEach((theSandbox) => theSandbox.restore());
testContext.configStubs = {};
// Give each test run a clean StateAggregator
stateAggregator_1.StateAggregator.clearInstance();
sfProject_1.SfProject.clearInstances();
// Allow each test to have their own config aggregator
// @ts-ignore clear for testing.
delete configAggregator_1.ConfigAggregator.instance;
};
exports.restoreContext = restoreContext;
/**
* A pre-canned error for try/catch testing.
*
* **See** {@link shouldThrow}
*/
exports.unexpectedResult = new sfError_1.SfError('This code was expected to fail', 'UnexpectedResult');
/**
* Use for this testing pattern:
* ```
* try {
* await call()
* assert.fail("this should never happen");
* } catch (e) {
* ...
* }
*
* Just do this
*
* try {
* await shouldThrow(call()); // If this succeeds unexpectedResultError is thrown.
* } catch(e) {
* ...
* }
* ```
*
* @param f The async function that is expected to throw.
*/
async function shouldThrow(f, message) {
await f;
if (message) {
throw new sfError_1.SfError(message, 'UnexpectedResult');
}
else {
throw exports.unexpectedResult;
}
}
/**
* Use for this testing pattern:
* ```
* try {
* call()
* assert.fail("this should never happen");
* } catch (e) {
* ...
* }
*
* Just do this
*
* try {
* shouldThrowSync(call); // If this succeeds unexpectedResultError is thrown.
* } catch(e) {
* ...
* }
* ```
*
* @param f The function that is expected to throw.
*/
function shouldThrowSync(f, message) {
f();
if (message) {
throw new sfError_1.SfError(message, 'UnexpectedResult');
}
else {
throw exports.unexpectedResult;
}
}
/**
* A helper to determine if a subscription will use callback or errorback.
* Enable errback to simulate a subscription failure.
*/
var StreamingMockSubscriptionCall;
(function (StreamingMockSubscriptionCall) {
StreamingMockSubscriptionCall[StreamingMockSubscriptionCall["CALLBACK"] = 0] = "CALLBACK";
StreamingMockSubscriptionCall[StreamingMockSubscriptionCall["ERRORBACK"] = 1] = "ERRORBACK";
})(StreamingMockSubscriptionCall || (exports.StreamingMockSubscriptionCall = StreamingMockSubscriptionCall = {}));
/**
* Simulates a comet subscription to a streaming channel.
*/
class StreamingMockCometSubscription extends node_events_1.EventEmitter {
static SUBSCRIPTION_COMPLETE = 'subscriptionComplete';
static SUBSCRIPTION_FAILED = 'subscriptionFailed';
options;
constructor(options) {
super();
this.options = options;
}
/**
* Sets up a streaming subscription callback to occur after the setTimeout event loop phase.
*
* @param callback The function to invoke.
*/
callback(callback) {
if (this.options.subscriptionCall === StreamingMockSubscriptionCall.CALLBACK) {
setTimeout(() => {
callback();
super.emit(StreamingMockCometSubscription.SUBSCRIPTION_COMPLETE);
}, 0);
}
}
/**
* Sets up a streaming subscription errback to occur after the setTimeout event loop phase.
*
* @param callback The function to invoke.
*/
errback(callback) {
if (this.options.subscriptionCall === StreamingMockSubscriptionCall.ERRORBACK) {
const error = this.options.subscriptionErrbackError;
if (!error)
return;
setTimeout(() => {
callback(error);
super.emit(StreamingMockCometSubscription.SUBSCRIPTION_FAILED);
}, 0);
}
}
}
exports.StreamingMockCometSubscription = StreamingMockCometSubscription;
/**
* Simulates a comet client. To the core streaming client this mocks the internal comet impl.
* The uses setTimeout(0ms) event loop phase just so the client can simulate actual streaming without the response
* latency.
*/
class StreamingMockCometClient extends streamingClient_1.CometClient {
options;
/**
* Constructor
*
* @param {StreamingMockCometSubscriptionOptions} options Extends the StreamingClient options.
*/
constructor(options) {
super();
this.options = options;
if (!this.options.messagePlaylist) {
this.options.messagePlaylist = [{ id: this.options.id }];
}
}
/**
* Fake addExtension. Does nothing.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
addExtension(extension) { }
/**
* Fake disable. Does nothing.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
disable(label) { }
/**
* Fake handshake that invoke callback after the setTimeout event phase.
*
* @param callback The function to invoke.
*/
handshake(callback) {
setTimeout(() => {
callback();
}, 0);
}
/**
* Fake setHeader. Does nothing,
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars,@typescript-eslint/no-empty-function
setHeader(name, value) { }
/**
* Fake subscription that completed after the setTimout event phase.
*
* @param channel The streaming channel.
* @param callback The function to invoke after the subscription completes.
*/
subscribe(channel, callback) {
const subscription = new StreamingMockCometSubscription(this.options);
subscription.on('subscriptionComplete', () => {
if (!this.options.messagePlaylist)
return;
Object.values(this.options.messagePlaylist).forEach((message) => {
setTimeout(() => {
callback(message);
}, 0);
});
});
return subscription;
}
/**
* Fake disconnect. Does Nothing.
*/
disconnect() {
return Promise.resolve();
}
}
exports.StreamingMockCometClient = StreamingMockCometClient;
/**
* Mock class for Salesforce Orgs.
*
* @example
* ```
* const testOrg = new MockTestOrgData();
* await $$.stubAuths(testOrg)
* ```
*/
class MockTestOrgData {
testId;
aliases;
configs;
username;
devHubUsername;
orgId;
loginUrl;
instanceUrl;
clientId;
clientSecret;
authcode;
accessToken;
refreshToken;
tracksSource;
userId;
redirectUri;
isDevHub;
isScratchOrg;
isExpired;
password;
namespacePrefix;
constructor(id = (0, uniqid_1.uniqid)(), options) {
this.testId = id;
this.userId = `user_id_${this.testId}`;
this.orgId = `${this.testId}`;
this.username = options?.username ?? `admin_${this.testId} .org`;
this.loginUrl = `https://login.${this.testId}.salesforce.com`;
this.instanceUrl = `https://instance.${this.testId}.salesforce.com`;
this.clientId = `${this.testId}/client_id`;
this.clientSecret = `${this.testId}/client_secret`;
this.authcode = `${this.testId}/authcode`;
this.accessToken = `${this.testId}/accessToken`;
this.refreshToken = `${this.testId}/refreshToken`;
this.redirectUri = 'http://localhost:1717/OauthRedirect';
this.namespacePrefix = `acme_${this.testId}`;
}
/**
* Add devhub username to properties.
*/
createDevHubUsername(username) {
this.devHubUsername = username;
}
/**
* Mark this org as a devhub.
*/
makeDevHub() {
this.isDevHub = true;
}
/**
* Returns a MockTestOrgData that represents a user created in the org.
*/
createUser(user) {
const userMock = new MockTestOrgData();
userMock.username = user;
userMock.aliases = this.aliases;
userMock.configs = this.configs;
userMock.devHubUsername = this.devHubUsername;
userMock.orgId = this.orgId;
userMock.loginUrl = this.loginUrl;
userMock.instanceUrl = this.instanceUrl;
userMock.clientId = this.clientId;
userMock.clientSecret = this.clientSecret;
userMock.redirectUri = this.redirectUri;
userMock.isDevHub = this.isDevHub;
userMock.isScratchOrg = this.isScratchOrg;
userMock.isExpired = this.isExpired;
userMock.password = this.password;
userMock.accessToken = this.accessToken;
return userMock;
}
/**
* Return mock user information based on this org.
*/
getMockUserInfo() {
return {
Id: this.userId,
Username: this.username,
LastName: `user_lastname_${this.testId}`,
Alias: this.aliases ? this.aliases[0] : 'user_alias_blah',
Configs: this.configs,
TimeZoneSidKey: `user_timezonesidkey_${this.testId}`,
LocaleSidKey: `user_localesidkey_${this.testId}`,
EmailEncodingKey: `user_emailencodingkey_${this.testId}`,
ProfileId: `user_profileid_${this.testId}`,
LanguageLocaleKey: `user_languagelocalekey_${this.testId}`,
Email: `user_email@${this.testId}.com`,
};
}
/**
* Return the auth config file contents.
*/
async getConfig() {
const crypto = await crypto_1.Crypto.create();
const config = {};
config.orgId = this.orgId;
config.clientId = this.clientId;
const accessToken = crypto.encrypt(this.accessToken);
if (accessToken) {
config.accessToken = accessToken;
}
if (this.refreshToken) {
config.refreshToken = crypto.encrypt(this.refreshToken);
}
config.instanceUrl = this.instanceUrl;
config.loginUrl = this.loginUrl;
config.username = this.username;
config.createdOrgInstance = 'CS1';
config.created = '1519163543003';
config.userId = this.userId;
config.tracksSource = this.tracksSource;
if (this.devHubUsername) {
config.devHubUsername = this.devHubUsername;
}
config.isDevHub = this.isDevHub;
if (this.password) {
config.password = crypto.encrypt(this.password);
}
// remove "undefined" properties that don't exist in actual files
return Object.fromEntries(Object.entries(config).filter(([, v]) => v !== undefined));
}
/**
* Return the Connection for the org.
*/
async getConnection() {
return (await org_1.Org.create({ aliasOrUsername: this.username })).getConnection();
}
}
exports.MockTestOrgData = MockTestOrgData;
/**
* Mock class for Salesforce Sandboxes.
*
* @example
* ```
* const testOrg = new MockTestSandboxData();
* await $$.stubSandboxes(testOrg)
* ```
*/
class MockTestSandboxData {
id;
sandboxOrgId;
prodOrgUsername;
sandboxName;
username;
constructor(id = (0, uniqid_1.uniqid)(), options) {
this.id = id;
this.sandboxOrgId = id;
this.prodOrgUsername = options?.prodOrgUsername ?? `admin_${id} .org`;
this.sandboxName = options?.name ?? `sandbox_${id}`;
this.username = options?.username ?? `${this.prodOrgUsername}.sandbox`;
}
/**
* Return the auth config file contents.
*/
// eslint-disable-next-line @typescript-eslint/require-await
async getConfig() {
return {
sandboxOrgId: this.sandboxOrgId,
prodOrgUsername: this.prodOrgUsername,
sandboxName: this.sandboxName,
sandboxUsername: this.username,
};
}
}
exports.MockTestSandboxData = MockTestSandboxData;
//# sourceMappingURL=testSetup.js.map