UNPKG

7.68 kBMarkdownView Raw
1[![NPM](https://img.shields.io/npm/v/@salesforce/core.svg)](https://www.npmjs.com/package/@salesforce/core)
2[![CircleCI](https://circleci.com/gh/forcedotcom/sfdx-core.svg?style=svg&circle-token=2377ca31221869e9d13448313620486da80e595f)](https://circleci.com/gh/forcedotcom/sfdx-core)
3
4- [Description](#description)
5- [Usage](#usage)
6 - [Contributing](#contributing)
7- [Using TestSetup](#using-testsetup)
8 - [Mocking Authorizations](#mocking-authorizations)
9 - [Mocking Config Files](#mocking-config-files)
10 - [Using the Built-in Sinon Sandboxes](#using-the-built-in-sinon-sandboxes)
11 - [Testing Expected Failures](#testing-expected-failures)
12 - [Testing Log Lines](#testing-log-lines)
13
14# Description
15
16The @salesforce/core library provides client-side management of Salesforce DX projects, org authentication, connections to Salesforce APIs, and other utilities. Much of the core functionality that powers the Salesforce CLI plugins comes from this library. You can use this functionality in your plugins too.
17
18# Usage
19
20See the [API documentation](https://forcedotcom.github.io/sfdx-core/).
21
22## Contributing
23
24If you are interested in contributing, please take a look at the [CONTRIBUTING](CONTRIBUTING.md) guide.
25
26# Using TestSetup
27
28The Salesforce DX Core Library provides a unit testing utility to help with mocking and sand-boxing core components. This feature allows unit tests to execute without needing to make API calls to salesforce.com.
29
30## Mocking Authorizations
31
32Here you can mock authorization for a Salesforce scratch org.
33
34```typescript
35import { strictEqual } from 'assert';
36import { MockTestOrgData, testSetup } from '@salesforce/core/lib/testSetup';
37import { AuthInfo } from '@salesforce/core';
38
39const $$ = testSetup();
40
41describe('Mocking Auth data', () => {
42 it('example', async () => {
43 const testData = new MockTestOrgData();
44 await $$.stubAuths(testData)
45 const auth = await AuthInfo.create({ username: testData.username });
46 strictEqual(auth.getUsername(), testData.username);
47 });
48});
49```
50
51After having a valid AuthInfo object you can then create fake connections to a Salesforce.com scratch org. This allows for writing tests that can validate result responses for SOQL queries and REST endpoints.
52
53```typescript
54import { AuthInfo, Connection, SfError } from '@salesforce/core';
55import { MockTestOrgData, testSetup } from '@salesforce/core/lib/testSetup';
56import { AnyJson, ensureJsonMap, JsonMap } from '@salesforce/ts-types';
57import { ensureString } from '@salesforce/ts-types';
58import { deepStrictEqual } from 'assert';
59import { QueryResult } from 'jsforce';
60
61const $$ = testSetup();
62
63describe('Mocking a force server call', () => {
64 it('example', async () => {
65 const records: AnyJson = { records: ['123456', '234567'] };
66 const testData = new MockTestOrgData();
67 await $$.stubAuths(testData);
68 $$.fakeConnectionRequest = (request: AnyJson): Promise<AnyJson> => {
69 const _request = ensureJsonMap(request);
70 if (request && ensureString(_request.url).includes('Account')) {
71 return Promise.resolve(records);
72 } else {
73 return Promise.reject(new SfError(`Unexpected request: ${_request.url}`));
74 }
75 };
76 const connection = await Connection.create({
77 authInfo: await AuthInfo.create({ username: testData.username }),
78 });
79 const result = await connection.query('select Id From Account');
80 deepStrictEqual(result, records);
81 });
82});
83```
84
85## Mocking Config Files
86
87You can mock the contents of various config files
88
89```typescript
90import { strictEqual } from 'assert';
91import { MockTestOrgData, testSetup } from '@salesforce/core/lib/testSetup';
92import { StateAggregator, OrgConfigProperties } from '@salesforce/core';
93
94const $$ = testSetup();
95
96describe('Mocking Aliases', () => {
97 it('example', async () => {
98 const testData = new MockTestOrgData();
99 await $$.stubAliases({ myAlias: testData.username });
100 const alias = (await StateAggregator.getInstance()).aliases.get(testData.username);
101 strictEqual(alias, 'myAlais');
102 });
103});
104
105describe('Mocking Config', () => {
106 it('example', async () => {
107 const testData = new MockTestOrgData();
108 await $$.stubConfig({ [OrgConfigProperties.TARGET_ORG]: testData.username });
109 const {value} = (await ConfigAggregator.create()).getInfo(OrgConfigProperties.TARGET_ORG);
110 strictEqual(value, testData.username);
111 });
112});
113
114describe('Mocking Arbitrary Config Files', () => {
115 it('example', async () => {
116 // MyConfigFile must extend the ConfigFile class in order for this to work properly.
117 $$.setConfigStubContents('MyConfigFile', { contents: { foo: 'bar' } });
118 });
119});
120```
121
122## Using the Built-in Sinon Sandboxes
123
124sfdx-core uses Sinon as its underlying mocking system. If you're unfamiliar with Sinon and it's sandboxing concept you can find more information here:
125https://sinonjs.org/
126Sinon `stub`s and `spy`s must be cleaned up after test invocations. To ease the use of Sinon with sfdx core we've exposed our sandbox in TestSetup. After adding your own `stub`s and/or `spy`s they will automatically be cleaned up after each test using mocha's afterEach method.
127
128```typescript
129import { strictEqual } from 'assert';
130
131import { testSetup } from '@salesforce/core/lib/testSetup';
132import * as os from 'os';
133
134const $$ = testSetup();
135
136describe('Using the built in Sinon sandbox.', () => {
137 it('example', async () => {
138 const unsupportedOS = 'LEO';
139 $$.SANDBOX.stub(os, 'platform').returns(unsupportedOS);
140 strictEqual(os.platform(), unsupportedOS);
141 });
142});
143```
144
145## Testing Expected Failures
146
147It's important to have negative tests that ensure proper error handling. With `shouldThrow` it's easy to test for expected async rejections.
148
149```typescript
150import { SfError } from '@salesforce/core';
151import { shouldThrow } from '@salesforce/core/lib/testSetup';
152import { strictEqual } from 'assert';
153
154class TestObject {
155 public static async method() {
156 throw new SfError('Error', 'ExpectedError');
157 }
158}
159
160describe('Testing for expected errors', () => {
161 it('example', async () => {
162 try {
163 await shouldThrow(TestObject.method());
164 } catch (e) {
165 strictEqual(e.name, 'ExpectedError');
166 }
167 });
168});
169```
170
171You can also use `shouldThrowSync` for syncrhonous functions you expect to fail
172
173```typescript
174import { SfError } from '@salesforce/core';
175import { shouldThrowSync } from '@salesforce/core/lib/testSetup';
176import { strictEqual } from 'assert';
177
178class TestObject {
179 public static method() {
180 throw new SfError('Error', 'ExpectedError');
181 }
182}
183
184describe('Testing for expected errors', () => {
185 it('example', async () => {
186 try {
187 shouldThrowSync(() => TestObject.method());
188 } catch (e) {
189 strictEqual(e.name, 'ExpectedError');
190 }
191 });
192});
193```
194
195## Testing Log Lines
196
197It's also useful to check expected values and content from log lines. TestSetup configures the sfdx-core logger to use an in memory LogLine storage structure. These can be easily accessed from tests.
198
199```typescript
200import { Logger, LogLine } from '@salesforce/core';
201import { testSetup } from '@salesforce/core/lib/testSetup';
202import { strictEqual } from 'assert';
203
204const $$ = testSetup();
205
206const TEST_STRING = 'foo was here';
207
208class TestObject {
209 constructor(private logger: Logger) {
210 this.logger = logger.child('TestObject');
211 }
212
213 public method() {
214 this.logger.error(TEST_STRING);
215 }
216}
217
218describe('Testing log lines', () => {
219 it('example', async () => {
220 const obj = new TestObject($$.TEST_LOGGER);
221 obj.method();
222 const records = $$.TEST_LOGGER.getBufferedRecords();
223 strictEqual(records.length, 1);
224 strictEqual(records[0].msg, TEST_STRING);
225 });
226});
227```