Skip to content

Commit 084e16f

Browse files
[create-sitecore-jss] Allow proxies to be initialized with main app and rework angular initializer (#1858)
* mock node-xmcloud-proxy logic * mock angular-xmcloud content * Support initializing proxy apps alongside main apps * check for prePushHook command before attempting install
1 parent ba751d2 commit 084e16f

File tree

15 files changed

+419
-129
lines changed

15 files changed

+419
-129
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ Our versioning strategy is as follows:
2121
* XMCloud-based: 'angular,angular-xmcloud'
2222
* Rework Angular initializer to support XMCloud and SXP journeys;
2323

24+
* `[create-sitecore-jss]` Rework Angular initializer to support XMCloud and SXP journeys ([#1845](https://github.com/Sitecore/jss/pull/1845))([#1858](https://github.com/Sitecore/jss/pull/1858))
25+
* `[create-sitecore-jss]` Allows proxy apps to be installed alongside main apps ([#1858](https://github.com/Sitecore/jss/pull/1858))
26+
* `nodeAppDestination` arg can be passed into `create-sitecore-jss` command to define path for proxy to be installed in
27+
2428
### 🛠 Breaking Change
2529

2630
### 🧹 Chores

packages/create-sitecore-jss/src/bin.test.ts

+151-76
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { sep } from 'path';
66
import chalk from 'chalk';
77
import inquirer from 'inquirer';
88
import { ParsedArgs } from 'minimist';
9-
import { parseArgs, main } from './bin';
9+
import { parseArgs, main, promptDestination, getDestinations } from './bin';
1010
import * as helpers from './common/utils/helpers';
1111
import * as initRunner from './init-runner';
1212

@@ -37,6 +37,8 @@ describe('bin', () => {
3737
'test',
3838
'--destination',
3939
'.\\test\\path',
40+
'--proxyAppDestination',
41+
'.\\test\\proxypath',
4042
'--templates',
4143
'foo,bar',
4244
'--hostName',
@@ -231,34 +233,6 @@ describe('bin', () => {
231233
});
232234
});
233235

234-
it('should prompt for destination if missing', async () => {
235-
getAllTemplatesStub.returns(['foo', 'bar']);
236-
getBaseTemplatesStub.returns(['foo']);
237-
fsExistsSyncStub.returns(false);
238-
fsReaddirSyncStub.returns([]);
239-
inquirerPromptStub.returns({
240-
prePushHook: true,
241-
});
242-
243-
const mockDestination = 'my\\path';
244-
inquirerPromptStub.returns({
245-
destination: mockDestination,
246-
});
247-
248-
const args = mockArgs({
249-
templates: 'foo',
250-
});
251-
const expectedTemplates = ['foo'];
252-
await main(args);
253-
254-
expect(inquirerPromptStub).to.have.been.called;
255-
expect(initRunnerStub).to.have.been.calledWith(expectedTemplates, {
256-
...args,
257-
destination: mockDestination,
258-
templates: expectedTemplates,
259-
});
260-
});
261-
262236
it('should prompt for prePushHook if missing', async () => {
263237
getAllTemplatesStub.returns(['foo', 'bar']);
264238
getBaseTemplatesStub.returns(['foo']);
@@ -287,88 +261,189 @@ describe('bin', () => {
287261
});
288262
});
289263

290-
describe('destination default', () => {
291-
it('should use appName', async () => {
292-
getAllTemplatesStub.returns(['foo', 'bar']);
293-
getBaseTemplatesStub.returns(['foo']);
294-
fsExistsSyncStub.returns(false);
295-
fsReaddirSyncStub.returns([]);
296-
264+
describe('promptDestination', () => {
265+
it('should prompt with provided prompt text and return input value', async () => {
297266
const mockDestination = 'my\\path';
267+
const mockPrompt = 'Enter the mocking path';
298268
inquirerPromptStub.returns({
299269
destination: mockDestination,
300270
});
271+
const result = await promptDestination(mockPrompt, 'default');
272+
expect(inquirerPromptStub).to.have.been.called;
273+
expect(inquirerPromptStub.getCall(0).args[0].message).to.be.equal(mockPrompt);
274+
expect(result).to.be.equal(mockDestination);
275+
});
301276

302-
const args = mockArgs({
303-
templates: 'foo',
304-
appName: 'testApp',
277+
it('should use default value', async () => {
278+
inquirerPromptStub.returns({
279+
destination: undefined,
305280
});
306-
const expectedTemplates = ['foo'];
307-
const expectedDestinationDefault = `${process.cwd()}${sep + args.appName}`;
281+
const defaultDestination = 'defa\\ult';
282+
await promptDestination('use default here', defaultDestination);
283+
expect(inquirerPromptStub).to.have.been.called;
284+
expect(inquirerPromptStub.getCall(0).args[0].default()).to.be.equal(defaultDestination);
285+
});
286+
});
308287

309-
await main(args);
288+
describe('getDestinations', () => {
289+
const testTemplates = ['foo', 'bar'];
310290

311-
expect(inquirerPromptStub).to.have.been.called;
312-
expect(inquirerPromptStub.getCall(0).args[0].default()).to.equal(
313-
expectedDestinationDefault
314-
);
315-
expect(initRunnerStub).to.have.been.calledWith(expectedTemplates, {
316-
...args,
317-
destination: mockDestination,
318-
templates: expectedTemplates,
291+
it('should return base args.destination value only when provided', async () => {
292+
const testPath = 'test\\path';
293+
const testArgs = mockArgs({
294+
destination: testPath,
295+
});
296+
expect(await getDestinations(testArgs, testTemplates)).to.deep.equal({
297+
destination: testPath,
319298
});
320299
});
321300

322-
it('should use template if appName not provided', async () => {
323-
getAllTemplatesStub.returns(['foo', 'bar']);
324-
getBaseTemplatesStub.returns(['foo']);
325-
fsExistsSyncStub.returns(false);
326-
fsReaddirSyncStub.returns([]);
301+
it('should return base and proxy destinations from args when templates contain proxy app', async () => {
302+
const testPath = 'test\\path';
303+
const proxyPath = 'proxy\\path';
304+
const testArgs = mockArgs({
305+
destination: testPath,
306+
proxyAppDestination: proxyPath,
307+
});
308+
const templatesWithProxy = [...testTemplates, 'node-app-proxy'];
309+
expect(await getDestinations(testArgs, templatesWithProxy)).to.deep.equal({
310+
destination: testPath,
311+
proxyAppDestination: proxyPath,
312+
});
313+
});
327314

328-
const mockDestination = 'my\\path';
315+
it('should prompt to get base destination when args.destination is empty', async () => {
316+
const testPath = 'test\\path';
329317
inquirerPromptStub.returns({
330-
destination: mockDestination,
318+
destination: testPath,
319+
});
320+
const testArgs = mockArgs({
321+
destination: undefined,
331322
});
323+
await getDestinations(testArgs, testTemplates);
324+
expect(inquirerPromptStub).to.have.been.calledOnce;
325+
expect(inquirerPromptStub.getCall(0).args[0].message).to.be.equal(
326+
'Where would you like your new app created?'
327+
);
328+
});
332329

333-
const args = mockArgs({
334-
templates: 'foo,bar',
330+
it('should prompt for both base and proxy when destinations are missing in args and templates contain proxy app', async () => {
331+
const testPath = 'test\\path';
332+
const proxyPath = 'proxy\\path';
333+
inquirerPromptStub.onCall(0).returns({
334+
destination: testPath,
335335
});
336-
const expectedTemplates = ['foo', 'bar'];
337-
const expectedDestinationDefault = `${process.cwd()}${sep + expectedTemplates[0]}`;
336+
// avoid paths being equal - this case is tested further down
337+
inquirerPromptStub.onCall(1).returns({
338+
destination: proxyPath,
339+
});
340+
const testArgs = mockArgs({
341+
destination: undefined,
342+
proxyAppDestination: undefined,
343+
});
344+
const templatesWithProxy = [...testTemplates, 'node-app-proxy'];
345+
await getDestinations(testArgs, templatesWithProxy);
346+
expect(inquirerPromptStub).to.have.been.calledTwice;
347+
expect(inquirerPromptStub.getCall(0).args[0].message).to.be.equal(
348+
'Where would you like your new app created?'
349+
);
350+
expect(inquirerPromptStub.getCall(1).args[0].message).to.be.equal(
351+
'Where would you like your proxy app created?'
352+
);
353+
});
338354

339-
await main(args);
355+
it('should return default base destination with base template when --yes arg is used', async () => {
356+
const testArgs = mockArgs({
357+
destination: undefined,
358+
yes: true,
359+
});
360+
const expectedDestination = `${process.cwd()}${sep + testTemplates[0]}`;
361+
expect(await getDestinations(testArgs, testTemplates)).to.deep.equal({
362+
destination: expectedDestination,
363+
});
364+
});
340365

341-
expect(inquirerPromptStub).to.have.been.called;
342-
expect(inquirerPromptStub.getCall(0).args[0].default()).to.equal(
343-
expectedDestinationDefault
366+
it('should return default base destination with args.appName when provided and --yes arg is used', async () => {
367+
const testAppName = 'myapp';
368+
const testArgs = mockArgs({
369+
destination: undefined,
370+
appName: testAppName,
371+
yes: true,
372+
});
373+
const expectedDestination = `${process.cwd()}${sep + testAppName}`;
374+
expect(await getDestinations(testArgs, testTemplates)).to.deep.equal({
375+
destination: expectedDestination,
376+
});
377+
});
378+
379+
it('should return default proxy destination when -- yes arg is used', async () => {
380+
const testPath = 'test\\path';
381+
const testArgs = mockArgs({
382+
destination: testPath,
383+
yes: true,
384+
});
385+
const templatesWithProxy = [...testTemplates, 'node-app-proxy'];
386+
const expectedProxyDestination = `${process.cwd()}${sep + 'node-app-proxy'}`;
387+
expect(await getDestinations(testArgs, templatesWithProxy)).to.deep.equal({
388+
destination: testPath,
389+
proxyAppDestination: expectedProxyDestination,
390+
});
391+
});
392+
393+
it('should prompt for proxy destination again if proxy destination is the same as base destination', async () => {
394+
const testPath = 'test\\path';
395+
const proxyPath = 'proxy\\path';
396+
// avoid paths being equal - this case is tested further down
397+
inquirerPromptStub.onCall(0).returns({
398+
destination: proxyPath,
399+
});
400+
const testArgs = mockArgs({
401+
destination: testPath,
402+
proxyAppDestination: testPath,
403+
});
404+
const templatesWithProxy = [...testTemplates, 'node-app-proxy'];
405+
await getDestinations(testArgs, templatesWithProxy);
406+
expect(inquirerPromptStub).to.have.been.calledOnce;
407+
expect(inquirerPromptStub.getCall(0).args[0].message).to.be.equal(
408+
'Proxy app and base app cannot be located in the same folder. Please input another path for proxy'
344409
);
345-
expect(initRunnerStub).to.have.been.calledWith(expectedTemplates, {
346-
...args,
347-
destination: mockDestination,
348-
templates: expectedTemplates,
410+
});
411+
412+
it('should throw when templates are empty', async () => {
413+
const testArgs = mockArgs();
414+
await getDestinations(testArgs, []).catch((error) => {
415+
expect(error.message).to.be.equal(
416+
'Unable to get destinations, provided templates are empty'
417+
);
349418
});
350419
});
420+
});
351421

352-
it('should respect yes', async () => {
422+
// this partially duplicates tests for getDestinations, but we need to ensure initRunnerStub is called with correct values
423+
// no way around it however - sinon cannot mock getDestinations on its own, which could've prevented this
424+
describe('main with destinations from args', () => {
425+
it('should call initRunnerStub with values from getDestinations', async () => {
353426
getAllTemplatesStub.returns(['foo', 'bar']);
354427
getBaseTemplatesStub.returns(['foo']);
355428
fsExistsSyncStub.returns(false);
356429
fsReaddirSyncStub.returns([]);
357430

431+
const mockDestination = 'my\\path';
432+
const proxyDestination = 'my\\proxy';
433+
358434
const args = mockArgs({
359435
templates: 'foo',
360-
appName: 'testApp',
361-
yes: true,
436+
destination: mockDestination,
437+
proxyAppDestination: proxyDestination,
362438
});
363439
const expectedTemplates = ['foo'];
364-
const expectedDestinationDefault = `${process.cwd()}${sep + args.appName}`;
365440

366441
await main(args);
367442

368-
expect(inquirerPromptStub).to.not.have.been.called;
369-
expect(initRunnerStub).to.have.been.calledOnceWith(expectedTemplates, {
443+
expect(initRunnerStub).to.have.been.calledWith(expectedTemplates, {
370444
...args,
371-
destination: expectedDestinationDefault,
445+
destination: mockDestination,
446+
proxyAppDestination: proxyDestination,
372447
templates: expectedTemplates,
373448
});
374449
});

0 commit comments

Comments
 (0)