Skip to content

Commit 8cbe41f

Browse files
committed
test: add unit tests
1 parent 4a22f4c commit 8cbe41f

File tree

8 files changed

+388
-4
lines changed

8 files changed

+388
-4
lines changed

test/convert/convertContext.test.ts

Lines changed: 145 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,20 @@
77

88
import { expect } from 'chai';
99
import { join } from 'path';
10-
import { createSandbox } from 'sinon';
10+
import { createSandbox, match } from 'sinon';
1111
import { Readable } from 'stream';
12-
import { SourceComponent } from '../../src';
12+
import { SourceComponent, VirtualTreeContainer } from '../../src';
1313
import { ComponentSet } from '../../src/collections';
14-
import { XML_NS_KEY, XML_NS_URL } from '../../src/common';
14+
import {
15+
DEFAULT_PACKAGE_ROOT_SFDX,
16+
META_XML_SUFFIX,
17+
XML_NS_KEY,
18+
XML_NS_URL,
19+
} from '../../src/common';
1520
import { WriterFormat } from '../../src/convert';
1621
import { ConvertContext } from '../../src/convert/convertContext';
1722
import { JsToXml } from '../../src/convert/streams';
18-
import { matchingContentFile, mockRegistry, regina } from '../mock/registry';
23+
import { matchingContentFile, mockRegistry, regina, nonDecomposed } from '../mock/registry';
1924

2025
const env = createSandbox();
2126

@@ -158,5 +163,141 @@ describe('Convert Transaction Constructs', () => {
158163
]);
159164
});
160165
});
166+
167+
describe('NonDecomposition', () => {
168+
it('should return WriterFormats for claimed children', async () => {
169+
const component = nonDecomposed.COMPONENT;
170+
const context = new ConvertContext();
171+
env.stub(VirtualTreeContainer.prototype, 'readDirectory').returns([]);
172+
const writeInfos = [
173+
{
174+
output: component.xml,
175+
source: new JsToXml(nonDecomposed.XML_CONTENT),
176+
},
177+
];
178+
context.nonDecomposition.setState((state) => {
179+
state.claimed = {
180+
[component.xml]: {
181+
parent: component,
182+
children: {
183+
[nonDecomposed.CHILD_1_NAME]: nonDecomposed.CHILD_1_XML,
184+
[nonDecomposed.CHILD_2_NAME]: nonDecomposed.CHILD_2_XML,
185+
[nonDecomposed.CHILD_3_NAME]: nonDecomposed.CHILD_3_XML,
186+
},
187+
},
188+
};
189+
});
190+
191+
const result = await context.nonDecomposition.finalize(process.cwd());
192+
193+
expect(result).to.deep.equal([{ component, writeInfos }]);
194+
});
195+
196+
it('should return WriterFormats for unclaimed children', async () => {
197+
const component = nonDecomposed.COMPONENT;
198+
const context = new ConvertContext();
199+
env.stub(VirtualTreeContainer.prototype, 'readDirectory').returns([]);
200+
const [baseName] = component.fullName.split('.');
201+
const output = join(
202+
DEFAULT_PACKAGE_ROOT_SFDX,
203+
component.type.directoryName,
204+
`${baseName}.${component.type.suffix}${META_XML_SUFFIX}`
205+
);
206+
const writeInfos = [{ output, source: new JsToXml(nonDecomposed.XML_CONTENT) }];
207+
context.nonDecomposition.setState((state) => {
208+
state.unclaimed = {
209+
[component.xml]: {
210+
parent: component,
211+
children: {
212+
[nonDecomposed.CHILD_1_NAME]: nonDecomposed.CHILD_1_XML,
213+
[nonDecomposed.CHILD_2_NAME]: nonDecomposed.CHILD_2_XML,
214+
[nonDecomposed.CHILD_3_NAME]: nonDecomposed.CHILD_3_XML,
215+
},
216+
},
217+
};
218+
});
219+
220+
const result = await context.nonDecomposition.finalize(process.cwd());
221+
222+
expect(result).to.deep.equal([{ component, writeInfos }]);
223+
});
224+
225+
it('should add unclaimed children to default parent component', async () => {
226+
const component = nonDecomposed.COMPONENT;
227+
const context = new ConvertContext();
228+
env.stub(VirtualTreeContainer.prototype, 'readDirectory').returns([]);
229+
230+
const writeInfos = [
231+
{ output: component.xml, source: new JsToXml(nonDecomposed.XML_CONTENT) },
232+
];
233+
context.nonDecomposition.setState((state) => {
234+
state.claimed = {
235+
[component.xml]: {
236+
parent: component,
237+
children: {
238+
[nonDecomposed.CHILD_1_NAME]: nonDecomposed.CHILD_1_XML,
239+
[nonDecomposed.CHILD_2_NAME]: nonDecomposed.CHILD_2_XML,
240+
},
241+
},
242+
};
243+
state.unclaimed = {
244+
[component.xml]: {
245+
parent: component,
246+
children: {
247+
[nonDecomposed.CHILD_3_NAME]: nonDecomposed.CHILD_3_XML,
248+
},
249+
},
250+
};
251+
});
252+
253+
const result = await context.nonDecomposition.finalize(process.cwd());
254+
255+
expect(result).to.deep.equal([{ component, writeInfos }]);
256+
});
257+
258+
it('should find all unprocessed components so that unclaimed children can be claimed', async () => {
259+
const component = nonDecomposed.COMPONENT;
260+
const context = new ConvertContext();
261+
const unprocessedComponent = nonDecomposed.COMPONENT2;
262+
263+
env.stub(unprocessedComponent, 'parseXml').resolves(nonDecomposed.PARTIAL_XML_CONTENT);
264+
env.stub(unprocessedComponent, 'parseXmlSync').returns(nonDecomposed.PARTIAL_XML_CONTENT);
265+
env.stub(VirtualTreeContainer.prototype, 'readDirectory').returns(['my-app']);
266+
env
267+
.stub(VirtualTreeContainer.prototype, 'isDirectory')
268+
.withArgs(match('my-app'))
269+
.returns(true);
270+
env
271+
.stub(ComponentSet, 'fromSource')
272+
.withArgs({ fsPaths: [match('my-app')], include: match.any })
273+
.returns(new ComponentSet([unprocessedComponent]));
274+
275+
const writeInfos = [
276+
{ output: component.xml, source: new JsToXml(nonDecomposed.XML_CONTENT) },
277+
];
278+
context.nonDecomposition.setState((state) => {
279+
state.claimed = {
280+
[component.xml]: {
281+
parent: component,
282+
children: {
283+
[nonDecomposed.CHILD_1_NAME]: nonDecomposed.CHILD_1_XML,
284+
[nonDecomposed.CHILD_2_NAME]: nonDecomposed.CHILD_2_XML,
285+
},
286+
},
287+
};
288+
state.unclaimed = {
289+
[component.xml]: {
290+
parent: component,
291+
children: {
292+
[nonDecomposed.CHILD_3_NAME]: nonDecomposed.CHILD_3_XML,
293+
},
294+
},
295+
};
296+
});
297+
298+
const result = await context.nonDecomposition.finalize(process.cwd());
299+
expect(result).to.deep.equal([{ component, writeInfos }]);
300+
});
301+
});
161302
});
162303
});

test/convert/transformers/index.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
describe('Metadata Transformers', () => {
88
require('./defaultMetadataTransformer');
99
require('./decomposedMetadataTransformer');
10+
require('./nonDecomposedMetadataTransformer');
1011
require('./staticResourceMetadataTransformer');
1112
});
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright (c) 2020, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
8+
import { mockRegistry, mockRegistryData, nonDecomposed } from '../../mock/registry';
9+
import { NonDecomposedMetadataTransformer } from '../../../src/convert/transformers/nonDecomposedMetadataTransformer';
10+
import { expect } from 'chai';
11+
import { createSandbox } from 'sinon';
12+
import { ComponentSet, SourceComponent } from '../../../src';
13+
import { ConvertContext } from '../../../src/convert/convertContext';
14+
15+
const env = createSandbox();
16+
17+
describe('NonDecomposedMetadataTransformer', () => {
18+
const component = nonDecomposed.COMPONENT;
19+
20+
beforeEach(() => {
21+
env.stub(component, 'parseXmlSync').returns(nonDecomposed.XML_CONTENT);
22+
env.stub(component, 'parseXml').resolves(nonDecomposed.XML_CONTENT);
23+
});
24+
25+
afterEach(() => env.restore());
26+
27+
describe('toMetadataFormat', () => {
28+
it('should defer write operations and set context state', async () => {
29+
const [child1, child2, child3] = component.getChildren();
30+
31+
const context = new ConvertContext();
32+
const transformer = new NonDecomposedMetadataTransformer(mockRegistry, context);
33+
34+
expect(await transformer.toMetadataFormat(child1)).to.deep.equal([]);
35+
expect(await transformer.toMetadataFormat(child2)).to.deep.equal([]);
36+
expect(await transformer.toMetadataFormat(child3)).to.deep.equal([]);
37+
expect(context.recomposition.state).to.deep.equal({
38+
[component.fullName]: {
39+
component,
40+
children: new ComponentSet([child1, child2, child3], mockRegistry),
41+
},
42+
});
43+
});
44+
});
45+
46+
describe('toSourceFormat', () => {
47+
it('should defer write operations and set context state for unclaimed children', async () => {
48+
const context = new ConvertContext();
49+
const transformer = new NonDecomposedMetadataTransformer(mockRegistry, context);
50+
51+
const result = await transformer.toSourceFormat(component);
52+
expect(result).to.deep.equal([]);
53+
expect(context.decomposition.state).to.deep.equal({});
54+
expect(context.recomposition.state).to.deep.equal({});
55+
expect(context.nonDecomposition.state).to.deep.equal({
56+
unclaimed: {
57+
[component.xml]: {
58+
parent: component,
59+
children: {
60+
[nonDecomposed.CHILD_1_NAME]: nonDecomposed.CHILD_1_XML,
61+
[nonDecomposed.CHILD_2_NAME]: nonDecomposed.CHILD_2_XML,
62+
[nonDecomposed.CHILD_3_NAME]: nonDecomposed.CHILD_3_XML,
63+
},
64+
},
65+
},
66+
claimed: {},
67+
});
68+
});
69+
70+
it('should defer write operations and set context state for claimed children', async () => {
71+
const context = new ConvertContext();
72+
const transformer = new NonDecomposedMetadataTransformer(mockRegistry, context);
73+
const mergeWithComponent = SourceComponent.createVirtualComponent(
74+
{
75+
name: component.type.name,
76+
type: mockRegistryData.types.nondecomposed,
77+
xml: component.xml,
78+
},
79+
[]
80+
);
81+
env.stub(mergeWithComponent, 'parseXml').resolves(nonDecomposed.PARTIAL_XML_CONTENT);
82+
env.stub(mergeWithComponent, 'parseXmlSync').returns(nonDecomposed.PARTIAL_XML_CONTENT);
83+
84+
const result = await transformer.toSourceFormat(component, mergeWithComponent);
85+
expect(result).to.deep.equal([]);
86+
87+
expect(context.nonDecomposition.state).to.deep.equal({
88+
unclaimed: {
89+
[component.xml]: {
90+
parent: component,
91+
children: {
92+
[nonDecomposed.CHILD_1_NAME]: nonDecomposed.CHILD_1_XML,
93+
[nonDecomposed.CHILD_2_NAME]: nonDecomposed.CHILD_2_XML,
94+
},
95+
},
96+
},
97+
claimed: {
98+
[mergeWithComponent.xml]: {
99+
parent: mergeWithComponent,
100+
children: {
101+
[nonDecomposed.CHILD_3_NAME]: nonDecomposed.CHILD_3_XML,
102+
},
103+
},
104+
},
105+
});
106+
});
107+
});
108+
});

test/mock/registry/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export {
1414
mixedContentInFolder,
1515
mixedContentSingleFile,
1616
regina,
17+
nonDecomposed,
1718
decomposedtoplevel,
1819
} from './type-constants';
1920
export { mockRegistry, mockRegistryData } from './mockRegistry';

test/mock/registry/mockRegistry.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,42 @@ export const mockRegistryData = {
8181
adapter: 'mixedContent',
8282
},
8383
},
84+
/**
85+
* Metadata types with children that are not decomposed into separate files
86+
*
87+
* e.g. CustomLabels
88+
*/
89+
nondecomposed: {
90+
id: 'nondecomposedparent',
91+
name: 'nondecomposedparent',
92+
suffix: 'nondecomposed',
93+
directoryName: 'nondecomposed',
94+
inFolder: false,
95+
strictDirectoryName: false,
96+
children: {
97+
types: {
98+
customlabel: {
99+
id: 'nondecomposedchild',
100+
name: 'nondecomposedchild',
101+
ignoreParentName: true,
102+
uniqueIdAttribute: 'id',
103+
directoryName: 'nondecomposed',
104+
suffix: 'nondecomposed',
105+
},
106+
},
107+
suffixes: {
108+
nondecomposed: 'nondecomposed',
109+
},
110+
directories: {
111+
nondecomposed: 'nondecomposed',
112+
},
113+
},
114+
strategies: {
115+
adapter: 'default',
116+
transformer: 'nonDecomposed',
117+
recomposition: 'startEmpty',
118+
},
119+
},
84120
dwaynejohnson: {
85121
id: 'dwaynejohnson',
86122
directoryName: 'dwaynes',

test/mock/registry/type-constants/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import * as mixedContentSingleFile from './mixedContentSingleFileConstants';
1414
import * as regina from './reginaConstants';
1515
import * as decomposedtoplevel from './decomposedTopLevelConstants';
1616
import * as dwayne from './dwayneConstants';
17+
import * as nonDecomposed from './nonDecomposedConstants';
1718
export {
1819
xmlInFolder,
1920
document,
@@ -25,4 +26,5 @@ export {
2526
regina,
2627
decomposedtoplevel,
2728
dwayne,
29+
nonDecomposed,
2830
};

0 commit comments

Comments
 (0)