@salesforce/core
Version:
Core libraries to interact with SFDX projects, orgs, and APIs.
860 lines • 33 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockTestSandboxData = exports.MockTestOrgData = exports.StreamingMockCometClient = exports.StreamingMockCometSubscription = exports.StreamingMockSubscriptionCall = exports.shouldThrowSync = exports.shouldThrow = exports.unexpectedResult = exports.restoreContext = exports.stubContext = exports.instantiateContext = exports.uniqid = exports.TestContext = void 0;
/*
* 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 @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 = require("node:fs");
const crypto_1 = require("crypto");
const events_1 = require("events");
const os_1 = require("os");
const path_1 = require("path");
const util = require("util");
const ts_sinon_1 = require("@salesforce/ts-sinon");
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_2 = 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 = require("./stateAggregator/accessors/aliasAccessor");
const streamingClient_1 = require("./status/streamingClient");
const stateAggregator_1 = require("./stateAggregator");
const org_1 = require("./org");
const sandboxAccessor_1 = require("./stateAggregator/accessors/sandboxAccessor");
const global_1 = require("./global");
/**
* Instantiate a @salesforce/core test context.
*/
class TestContext {
constructor(options = {}) {
/**
* id A unique id for the test run.
*/
this.id = uniqid();
/**
* An object used in tests that interact with config files.
*/
this.configStubs = {};
/**
* A record of stubs created during instantiation.
*/
this.stubs = {};
const opts = { setup: true, ...options };
const sinon = this.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 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);
(0, ts_sinon_1.stubMethod)(this.SANDBOX, stateAggregator_1.OrgAccessor.prototype, 'getAllFiles').resolves([...orgMap.keys()].map((o) => `${o}.json`));
(0, ts_sinon_1.stubMethod)(this.SANDBOX, stateAggregator_1.OrgAccessor.prototype, 'hasFile').callsFake((username) => orgMap.has(username));
const retrieveContents = async function () {
const username = (0, 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];
}));
(0, ts_sinon_1.stubMethod)(this.SANDBOX, org_1.User.prototype, 'retrieve').callsFake((username) => Promise.resolve(mockUsers.find((org) => org.username === username)));
const retrieveContents = async function () {
const orgId = (0, 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);
(0, ts_sinon_1.stubMethod)(this.SANDBOX, sandboxAccessor_1.SandboxAccessor.prototype, 'getAllFiles').resolves([...sandboxMap.keys()].map((o) => `${o}.sandbox.json`));
const retrieveContents = async function () {
const username = (0, 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, 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();
}
/**
* Stub the tokens in the global token config file.
*/
stubTokens(tokens) {
this.configStubs.TokensConfig = { contents: tokens };
}
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();
});
}
requireSinon(sinon) {
if (sinon)
return sinon;
try {
sinon = require('sinon');
}
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})');
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return sinon;
}
}
exports.TestContext = TestContext;
/**
* A function to generate a unique id and return it in the context of a template, if supplied.
*
* A template is a string that can contain `${%s}` to be replaced with a unique id.
* If the template contains the "%s" placeholder, it will be replaced with the unique id otherwise the id will be appended to the template.
*
* @param options an object with the following properties:
* - template: a template string.
* - length: the length of the unique id as presented in hexadecimal.
*/
function uniqid(options) {
const uniqueString = (0, crypto_1.randomBytes)(Math.ceil((options?.length ?? 32) / 2.0))
.toString('hex')
.slice(0, options?.length ?? 32);
if (!options?.template) {
return uniqueString;
}
return options.template.includes('%s')
? util.format(options.template, uniqueString)
: `${options.template}${uniqueString}`;
}
exports.uniqid = uniqid;
function getTestLocalPath(uid) {
return (0, path_1.join)((0, os_1.tmpdir)(), uid, 'sfdx_core', 'local');
}
function getTestGlobalPath(uid) {
return (0, path_1.join)((0, os_1.tmpdir)(), uid, 'sfdx_core', 'global');
}
function retrieveRootPathSync(isGlobal, uid = uniqid()) {
return isGlobal ? getTestGlobalPath(uid) : getTestLocalPath(uid);
}
// eslint-disable-next-line @typescript-eslint/require-await
async function retrieveRootPath(isGlobal, uid = 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.
(0, ts_sinon_1.stubMethod)(testContext.SANDBOX, logger_1.Logger, 'child').resolves(testContext.TEST_LOGGER);
(0, ts_sinon_1.stubMethod)(testContext.SANDBOX, 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));
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.PROJECT, sfProject_1.SfProjectJson.prototype, 'doesPackageExist').callsFake(() => true);
const initStubForRead = (configFile) => {
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.setContentsFromObject(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 (newContents) {
if (!testContext.configStubs[this.constructor.name]) {
testContext.configStubs[this.constructor.name] = {};
}
const stub = testContext.configStubs[this.constructor.name];
if (!stub)
return;
this.setContents(newContents ?? this.getContents());
stub.contents = this.toObject();
};
const write = async function (newContents) {
if (!testContext.configStubs[this.constructor.name]) {
testContext.configStubs[this.constructor.name] = {};
}
const stub = testContext.configStubs[this.constructor.name];
if (!stub)
return;
if (stub.writeFn) {
return stub.writeFn.call(this, newContents);
}
if (stub.updateContents) {
writeSync.call(this, await stub.updateContents.call(this));
}
else {
writeSync.call(this);
}
};
stubs.configWriteSync = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONFIG, configFile_1.ConfigFile.prototype, 'writeSync').callsFake(writeSync);
stubs.configWrite = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONFIG, configFile_1.ConfigFile.prototype, 'write').callsFake(write);
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CRYPTO, crypto_2.Crypto.prototype, 'getKeyChain').callsFake(() => Promise.resolve({
setPassword: () => Promise.resolve(),
getPassword: (data, cb) => cb(undefined, '12345678901234567890123456789012'),
}));
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONNECTION, connection_1.Connection.prototype, 'isResolvable').resolves(true);
(0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.CONNECTION, 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);
});
(0, ts_sinon_1.stubMethod)(testContext.SANDBOX, aliasAccessorEntireFile, 'getFileLocation').returns(getAliasFileLocation());
stubs.configExists = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.ORGS, stateAggregator_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 = (0, ts_sinon_1.stubMethod)(testContext.SANDBOXES.ORGS, stateAggregator_1.OrgAccessor.prototype, 'remove').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);
});
// 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, path_1.join)((0, 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();
// 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;
}
}
exports.shouldThrow = shouldThrow;
/**
* 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;
}
}
exports.shouldThrowSync = shouldThrowSync;
/**
* 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 || (exports.StreamingMockSubscriptionCall = {}));
/**
* Simulates a comet subscription to a streaming channel.
*/
class StreamingMockCometSubscription extends events_1.EventEmitter {
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;
StreamingMockCometSubscription.SUBSCRIPTION_COMPLETE = 'subscriptionComplete';
StreamingMockCometSubscription.SUBSCRIPTION_FAILED = 'subscriptionFailed';
/**
* 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 {
/**
* 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 {
constructor(id = 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_2.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);
}
return config;
}
/**
* 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 {
constructor(id = 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