apostrophe 3.18.0 → 3.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.stylelintrc +2 -1
- package/CHANGELOG.md +23 -1
- package/lib/moog-require.js +7 -1
- package/modules/@apostrophecms/admin-bar/ui/apos/components/TheAposAdminBarLocale.vue +1 -1
- package/modules/@apostrophecms/asset/index.js +281 -24
- package/modules/@apostrophecms/asset/lib/webpack/apos/webpack.config.js +7 -0
- package/modules/@apostrophecms/asset/lib/webpack/src/webpack.config.js +7 -0
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +10 -1
- package/modules/@apostrophecms/i18n/i18n/en.json +3 -0
- package/modules/@apostrophecms/i18n/i18n/es.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/pt-BR.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/sk.json +1 -0
- package/modules/@apostrophecms/image/ui/apos/components/AposImageCropper.vue +2 -2
- package/modules/@apostrophecms/image/ui/apos/components/AposImageRelationshipEditor.vue +5 -5
- package/modules/@apostrophecms/login/ui/apos/components/TheAposLoginHeader.vue +3 -2
- package/modules/@apostrophecms/schema/index.js +2 -1123
- package/modules/@apostrophecms/schema/lib/addFieldTypes.js +1139 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputDateAndTime.vue +115 -0
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +21 -1
- package/modules/@apostrophecms/ui/ui/apos/components/AposSpinner.vue +7 -7
- package/modules/@apostrophecms/ui/ui/apos/components/AposToggle.vue +68 -0
- package/package.json +2 -3
- package/test/assets.js +462 -4
- package/test/schemas.js +25 -0
- package/test-lib/test.js +12 -0
- package/test-lib/util.js +4 -3
package/test/assets.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const t = require('../test-lib/test.js');
|
|
2
|
-
const assert = require('assert');
|
|
2
|
+
const assert = require('assert').strict;
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
|
+
const Promise = require('bluebird');
|
|
5
6
|
|
|
6
7
|
const {
|
|
7
8
|
checkModulesWebpackConfig,
|
|
@@ -13,11 +14,17 @@ let apos;
|
|
|
13
14
|
|
|
14
15
|
const badModules = {
|
|
15
16
|
badModuleConfig: {
|
|
17
|
+
options: {
|
|
18
|
+
ignoreNoCodeWarning: true
|
|
19
|
+
},
|
|
16
20
|
webpack: {
|
|
17
21
|
badprop: {}
|
|
18
22
|
}
|
|
19
23
|
},
|
|
20
24
|
badModuleConfig2: {
|
|
25
|
+
options: {
|
|
26
|
+
ignoreNoCodeWarning: true
|
|
27
|
+
},
|
|
21
28
|
webpack: []
|
|
22
29
|
}
|
|
23
30
|
};
|
|
@@ -78,19 +85,24 @@ const modules = {
|
|
|
78
85
|
describe('Assets', function() {
|
|
79
86
|
const {
|
|
80
87
|
publicFolderPath,
|
|
88
|
+
cacheFolderPath,
|
|
81
89
|
getScriptMarkup,
|
|
82
90
|
getStylesheetMarkup,
|
|
83
91
|
expectedBundlesNames,
|
|
84
92
|
deleteBuiltFolders,
|
|
85
|
-
allBundlesAreIncluded
|
|
93
|
+
allBundlesAreIncluded,
|
|
94
|
+
removeCache,
|
|
95
|
+
getCacheMeta,
|
|
96
|
+
retryAssertTrue
|
|
86
97
|
} = loadUtils();
|
|
87
98
|
|
|
88
99
|
after(async function() {
|
|
89
100
|
await deleteBuiltFolders(publicFolderPath, true);
|
|
101
|
+
await removeCache();
|
|
90
102
|
return t.destroy(apos);
|
|
91
103
|
});
|
|
92
104
|
|
|
93
|
-
this.timeout(
|
|
105
|
+
this.timeout(5 * 60 * 1000);
|
|
94
106
|
|
|
95
107
|
it('should exist on the apos object', async function() {
|
|
96
108
|
apos = await t.create({
|
|
@@ -284,10 +296,407 @@ describe('Assets', function() {
|
|
|
284
296
|
assert(bundlePage.includes(getScriptMarkup('extra2-module-bundle', 'module')));
|
|
285
297
|
assert(bundlePage.includes(getScriptMarkup('extra2-nomodule-bundle', 'nomodule')));
|
|
286
298
|
});
|
|
299
|
+
|
|
300
|
+
it('should build with cache and gain performance', async function() {
|
|
301
|
+
await t.destroy(apos);
|
|
302
|
+
await removeCache();
|
|
303
|
+
await removeCache(cacheFolderPath.replace('/webpack-cache', '/changed'));
|
|
304
|
+
|
|
305
|
+
const es5Modules = {
|
|
306
|
+
...modules,
|
|
307
|
+
'@apostrophecms/asset': {
|
|
308
|
+
options: {
|
|
309
|
+
es5: true
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
apos = await t.create({
|
|
315
|
+
root: module,
|
|
316
|
+
modules: es5Modules
|
|
317
|
+
});
|
|
318
|
+
assert.throws(() => fs.readdirSync(cacheFolderPath), {
|
|
319
|
+
code: 'ENOENT'
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
let startTime;
|
|
323
|
+
|
|
324
|
+
// Cold run
|
|
325
|
+
startTime = Date.now();
|
|
326
|
+
await apos.asset.tasks.build.task({
|
|
327
|
+
'check-apos-build': false
|
|
328
|
+
});
|
|
329
|
+
const execTime = Date.now() - startTime;
|
|
330
|
+
const { meta, folders } = getCacheMeta();
|
|
331
|
+
assert.equal(folders.length, 3);
|
|
332
|
+
assert.equal(Object.keys(meta).length, 3);
|
|
333
|
+
assert(meta['default:apos']);
|
|
334
|
+
assert(meta['default:src']);
|
|
335
|
+
assert(meta['default:src-es5']);
|
|
336
|
+
|
|
337
|
+
// Cache
|
|
338
|
+
startTime = Date.now();
|
|
339
|
+
await apos.asset.tasks.build.task({
|
|
340
|
+
'check-apos-build': false
|
|
341
|
+
});
|
|
342
|
+
const execTimeCached = Date.now() - startTime;
|
|
343
|
+
const { meta: meta2, folders: folders2 } = getCacheMeta();
|
|
344
|
+
assert.equal(folders2.length, 3);
|
|
345
|
+
assert.equal(Object.keys(meta2).length, 3);
|
|
346
|
+
assert(meta2['default:apos']);
|
|
347
|
+
assert(meta2['default:src']);
|
|
348
|
+
assert(meta2['default:src-es5']);
|
|
349
|
+
|
|
350
|
+
// Expect at least 40% gain, in reallity it should be 50+
|
|
351
|
+
const gain = (execTime - execTimeCached) / execTime * 100;
|
|
352
|
+
assert(gain >= 20, `Expected gain >=20%, got ${gain}%`);
|
|
353
|
+
|
|
354
|
+
// Modification times
|
|
355
|
+
assert(meta['default:apos'].mdate);
|
|
356
|
+
assert(meta2['default:apos'].mdate);
|
|
357
|
+
assert(meta['default:src'].mdate);
|
|
358
|
+
assert(meta2['default:src'].mdate);
|
|
359
|
+
assert(meta['default:src-es5'].mdate);
|
|
360
|
+
assert(meta2['default:src-es5'].mdate);
|
|
361
|
+
assert(
|
|
362
|
+
new Date(meta['default:apos'].mdate) < new Date(meta2['default:apos'].mdate)
|
|
363
|
+
);
|
|
364
|
+
assert.equal(
|
|
365
|
+
new Date(meta2['default:apos'].mdate).toISOString(),
|
|
366
|
+
fs.statSync(meta2['default:apos'].location).mtime.toISOString()
|
|
367
|
+
);
|
|
368
|
+
assert(
|
|
369
|
+
new Date(meta['default:src'].mdate) < new Date(meta2['default:src'].mdate)
|
|
370
|
+
);
|
|
371
|
+
assert.equal(
|
|
372
|
+
new Date(meta2['default:src'].mdate).toISOString(),
|
|
373
|
+
fs.statSync(meta2['default:src'].location).mtime.toISOString()
|
|
374
|
+
);
|
|
375
|
+
assert(
|
|
376
|
+
new Date(meta['default:src-es5'].mdate) < new Date(meta2['default:src-es5'].mdate)
|
|
377
|
+
);
|
|
378
|
+
assert.equal(
|
|
379
|
+
new Date(meta2['default:src-es5'].mdate).toISOString(),
|
|
380
|
+
fs.statSync(meta2['default:src-es5'].location).mtime.toISOString()
|
|
381
|
+
);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it('should invalidate build cache when namespace changes', async function() {
|
|
385
|
+
process.env.APOS_DEBUG_NAMESPACE = 'test';
|
|
386
|
+
await apos.asset.tasks.build.task({
|
|
387
|
+
'check-apos-build': false
|
|
388
|
+
});
|
|
389
|
+
const { meta, folders } = getCacheMeta();
|
|
390
|
+
assert.equal(folders.length, 6);
|
|
391
|
+
assert.equal(Object.keys(meta).length, 6);
|
|
392
|
+
assert(meta['test:apos']);
|
|
393
|
+
assert(meta['test:src']);
|
|
394
|
+
assert(meta['test:src-es5']);
|
|
395
|
+
assert(meta['default:apos']);
|
|
396
|
+
assert(meta['default:src']);
|
|
397
|
+
assert(meta['default:src-es5']);
|
|
398
|
+
delete process.env.APOS_DEBUG_NAMESPACE;
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('should invalidate build cache when packages change', async function() {
|
|
402
|
+
await t.destroy(apos);
|
|
403
|
+
const lock = require('./package-lock.json');
|
|
404
|
+
assert.equal(lock.version, 'current');
|
|
405
|
+
lock.version = 'new';
|
|
406
|
+
fs.writeFileSync(
|
|
407
|
+
path.join(process.cwd(), 'test/package-lock.json'),
|
|
408
|
+
JSON.stringify(lock, null, ' '),
|
|
409
|
+
'utf8'
|
|
410
|
+
);
|
|
411
|
+
const es5Modules = {
|
|
412
|
+
...modules,
|
|
413
|
+
'@apostrophecms/asset': {
|
|
414
|
+
options: {
|
|
415
|
+
es5: true
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
apos = await t.create({
|
|
421
|
+
root: module,
|
|
422
|
+
modules: es5Modules
|
|
423
|
+
});
|
|
424
|
+
await apos.asset.tasks.build.task({
|
|
425
|
+
'check-apos-build': false
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
const { meta, folders } = getCacheMeta();
|
|
429
|
+
assert.equal(folders.length, 9);
|
|
430
|
+
assert.equal(Object.keys(meta).length, 9);
|
|
431
|
+
assert(meta['default:apos_2']);
|
|
432
|
+
assert(meta['default:src_2']);
|
|
433
|
+
assert(meta['default:src-es5_2']);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('should invalidate build cache when configuration changes', async function() {
|
|
437
|
+
await t.destroy(apos);
|
|
438
|
+
const es5Modules = {
|
|
439
|
+
...modules,
|
|
440
|
+
'bundle-page': {
|
|
441
|
+
webpack: {
|
|
442
|
+
extensions: {
|
|
443
|
+
ext1: {
|
|
444
|
+
resolve: {
|
|
445
|
+
alias: {
|
|
446
|
+
ext1: 'changed'
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
'@apostrophecms/asset': {
|
|
454
|
+
options: {
|
|
455
|
+
es5: true
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
apos = await t.create({
|
|
460
|
+
root: module,
|
|
461
|
+
modules: es5Modules
|
|
462
|
+
});
|
|
463
|
+
await apos.asset.tasks.build.task({
|
|
464
|
+
'check-apos-build': false
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
const { meta, folders } = getCacheMeta();
|
|
468
|
+
assert.equal(folders.length, 11);
|
|
469
|
+
assert.equal(Object.keys(meta).length, 11);
|
|
470
|
+
assert(!meta['default:apos_3']);
|
|
471
|
+
assert(meta['default:src_3']);
|
|
472
|
+
assert(meta['default:src-es5_3']);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it('should clear build cache', async function() {
|
|
476
|
+
const cacheFolders = fs.readdirSync(cacheFolderPath, 'utf8');
|
|
477
|
+
assert(cacheFolders.length > 0);
|
|
478
|
+
await apos.asset.tasks['clear-cache'].task();
|
|
479
|
+
|
|
480
|
+
assert.equal(fs.readdirSync(cacheFolderPath, 'utf8').length, 0);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it('should be able to override the build cache location via APOS_ASSET_CACHE', async function() {
|
|
484
|
+
await t.destroy(apos);
|
|
485
|
+
await removeCache();
|
|
486
|
+
const altCacheLoc = cacheFolderPath.replace('/webpack-cache', '/changed');
|
|
487
|
+
await removeCache(altCacheLoc);
|
|
488
|
+
process.env.APOS_ASSET_CACHE = altCacheLoc;
|
|
489
|
+
|
|
490
|
+
apos = await t.create({
|
|
491
|
+
root: module,
|
|
492
|
+
modules
|
|
493
|
+
});
|
|
494
|
+
assert.throws(() => fs.readdirSync(altCacheLoc), {
|
|
495
|
+
code: 'ENOENT'
|
|
496
|
+
});
|
|
497
|
+
await apos.asset.tasks.build.task({
|
|
498
|
+
'check-apos-build': false
|
|
499
|
+
});
|
|
500
|
+
const { meta, folders } = getCacheMeta(altCacheLoc);
|
|
501
|
+
assert.equal(folders.length, 2);
|
|
502
|
+
assert.equal(Object.keys(meta).length, 2);
|
|
503
|
+
assert(meta['default:apos']);
|
|
504
|
+
assert(meta['default:src']);
|
|
505
|
+
|
|
506
|
+
delete process.env.APOS_ASSET_CACHE;
|
|
507
|
+
await removeCache(altCacheLoc);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
it('should watch and rebuild assets and reload page in development', async function() {
|
|
511
|
+
await t.destroy(apos);
|
|
512
|
+
|
|
513
|
+
apos = await t.create({
|
|
514
|
+
root: module,
|
|
515
|
+
autoBuild: true,
|
|
516
|
+
modules
|
|
517
|
+
});
|
|
518
|
+
const restartId = apos.asset.restartId;
|
|
519
|
+
assert(apos.asset.buildWatcher);
|
|
520
|
+
assert(apos.asset.restartId);
|
|
521
|
+
|
|
522
|
+
// Modify asset and rebuild
|
|
523
|
+
const assetPath = path.join(process.cwd(), 'test/modules/bundle-page/ui/src/extra.js');
|
|
524
|
+
const assetPathPublic = path.join(process.cwd(), 'test/public/apos-frontend/default/extra-module-bundle.js');
|
|
525
|
+
const assetContent = 'export default () => {};\n';
|
|
526
|
+
fs.writeFileSync(
|
|
527
|
+
assetPath,
|
|
528
|
+
'export default () => { \'bundle-page-watcher-test\'; };\n',
|
|
529
|
+
'utf8'
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
await retryAssertTrue(
|
|
533
|
+
async () => (await fs.readFile(assetPathPublic, 'utf8')).match(/bundle-page-watcher-test/),
|
|
534
|
+
'Unable to verify public asset was rebuilt by the watcher',
|
|
535
|
+
500,
|
|
536
|
+
10000
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
await retryAssertTrue(
|
|
540
|
+
() => apos.asset.restartId !== restartId,
|
|
541
|
+
'Unable to verify restartId has been changed',
|
|
542
|
+
500,
|
|
543
|
+
10000
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
await t.destroy(apos);
|
|
547
|
+
assert.equal(apos.asset.buildWatcher, null);
|
|
548
|
+
apos = null;
|
|
549
|
+
fs.writeFileSync(assetPath, assetContent, 'utf8');
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
it('should watch and rebuild assets in a debounced queue', async function() {
|
|
553
|
+
await t.destroy(apos);
|
|
554
|
+
let timesRebuilt = 0;
|
|
555
|
+
const inc = () => {
|
|
556
|
+
timesRebuilt += 1;
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
apos = await t.create({
|
|
560
|
+
root: module,
|
|
561
|
+
autoBuild: true,
|
|
562
|
+
modules: {
|
|
563
|
+
...modules,
|
|
564
|
+
'@apostrophecms/asset': {
|
|
565
|
+
extendMethods() {
|
|
566
|
+
return {
|
|
567
|
+
async watchUiAndRebuild(_super) {
|
|
568
|
+
return _super(inc);
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
assert(apos.asset.buildWatcher);
|
|
576
|
+
|
|
577
|
+
const assetPath = path.join(process.cwd(), 'test/modules/bundle-page/ui/src/extra.js');
|
|
578
|
+
const assetPathPublic = path.join(process.cwd(), 'test/public/apos-frontend/default/extra-module-bundle.js');
|
|
579
|
+
const assetContent = 'export default () => {};\n';
|
|
580
|
+
|
|
581
|
+
// Modify below the debounce rate
|
|
582
|
+
for (const i of [ 1, 2, 3 ]) {
|
|
583
|
+
await fs.writeFile(
|
|
584
|
+
assetPath,
|
|
585
|
+
`export default () => { 'bundle-page-watcher-test-${i}'; };\n`,
|
|
586
|
+
'utf8'
|
|
587
|
+
);
|
|
588
|
+
await Promise.delay(300);
|
|
589
|
+
}
|
|
590
|
+
await retryAssertTrue(
|
|
591
|
+
async () => (await fs.readFile(assetPathPublic, 'utf8')).match(/bundle-page-watcher-test-3/),
|
|
592
|
+
'Unable to verify public asset rebuilding by the watcher',
|
|
593
|
+
500,
|
|
594
|
+
10000
|
|
595
|
+
);
|
|
596
|
+
await retryAssertTrue(
|
|
597
|
+
() => timesRebuilt === 1,
|
|
598
|
+
`Expected to rebuild 1 time, got ${timesRebuilt}`,
|
|
599
|
+
100,
|
|
600
|
+
5000
|
|
601
|
+
);
|
|
602
|
+
|
|
603
|
+
// Modify above the debounce rate, test the queue cap
|
|
604
|
+
timesRebuilt = 0;
|
|
605
|
+
for (const i of [ 1, 2, 3 ]) {
|
|
606
|
+
await fs.writeFile(
|
|
607
|
+
assetPath,
|
|
608
|
+
`export default () => { 'bundle-page-watcher-test-${i}0'; };\n`,
|
|
609
|
+
'utf8'
|
|
610
|
+
);
|
|
611
|
+
await Promise.delay(1050);
|
|
612
|
+
}
|
|
613
|
+
await retryAssertTrue(
|
|
614
|
+
async () => (await fs.readFile(assetPathPublic, 'utf8')).match(/bundle-page-watcher-test-30/),
|
|
615
|
+
'Unable to verify public asset rebuilding by the watcher',
|
|
616
|
+
500,
|
|
617
|
+
10000
|
|
618
|
+
);
|
|
619
|
+
await retryAssertTrue(
|
|
620
|
+
() => timesRebuilt === 2,
|
|
621
|
+
`Expected to rebuild 2 times, got ${timesRebuilt}`,
|
|
622
|
+
100,
|
|
623
|
+
5000
|
|
624
|
+
);
|
|
625
|
+
|
|
626
|
+
await t.destroy(apos);
|
|
627
|
+
apos = null;
|
|
628
|
+
fs.writeFileSync(assetPath, assetContent, 'utf8');
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it('should be able to setup the debounce time', async function() {
|
|
632
|
+
await t.destroy(apos);
|
|
633
|
+
|
|
634
|
+
apos = await t.create({
|
|
635
|
+
root: module,
|
|
636
|
+
modules: {
|
|
637
|
+
'@apostrophecms/asset': {
|
|
638
|
+
options: {
|
|
639
|
+
watchDebounceMs: 500
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
assert.equal(apos.asset.buildWatcherDebounceMs, 500);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it('should not watch if explicitly disabled by option or env in development', async function() {
|
|
648
|
+
await t.destroy(apos);
|
|
649
|
+
process.env.APOS_ASSET_WATCH = '0';
|
|
650
|
+
|
|
651
|
+
apos = await t.create({
|
|
652
|
+
root: module,
|
|
653
|
+
autoBuild: true
|
|
654
|
+
});
|
|
655
|
+
assert(!apos.asset.buildWatcher);
|
|
656
|
+
delete process.env.APOS_ASSET_WATCH;
|
|
657
|
+
await t.destroy(apos);
|
|
658
|
+
|
|
659
|
+
apos = await t.create({
|
|
660
|
+
root: module,
|
|
661
|
+
autoBuild: true,
|
|
662
|
+
modules: {
|
|
663
|
+
'@apostrophecms/asset': {
|
|
664
|
+
options: {
|
|
665
|
+
watch: false
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
assert(!apos.asset.buildWatcher);
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
it('should not watch if autoBuild is disabled', async function() {
|
|
674
|
+
await t.destroy(apos);
|
|
675
|
+
|
|
676
|
+
apos = await t.create({
|
|
677
|
+
root: module
|
|
678
|
+
});
|
|
679
|
+
assert(!apos.asset.buildWatcher);
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
it('should not watch in production', async function() {
|
|
683
|
+
await t.destroy(apos);
|
|
684
|
+
process.env.NODE_ENV = 'production';
|
|
685
|
+
|
|
686
|
+
apos = await t.create({
|
|
687
|
+
root: module,
|
|
688
|
+
autoBuild: true,
|
|
689
|
+
modules
|
|
690
|
+
});
|
|
691
|
+
assert(!apos.asset.buildWatcher);
|
|
692
|
+
process.env.NODE_ENV = 'development';
|
|
693
|
+
});
|
|
287
694
|
});
|
|
288
695
|
|
|
289
696
|
function loadUtils () {
|
|
290
697
|
const publicFolderPath = path.join(process.cwd(), 'test/public');
|
|
698
|
+
const cacheFolderPath = process.env.APOS_ASSET_CACHE ||
|
|
699
|
+
path.join(process.cwd(), 'test/data/temp/webpack-cache');
|
|
291
700
|
|
|
292
701
|
const getScriptMarkup = (file, mod) => {
|
|
293
702
|
const moduleStr = mod === 'module' ? ' type="module"' : ' nomodule';
|
|
@@ -318,12 +727,61 @@ function loadUtils () {
|
|
|
318
727
|
assert(page.includes(getScriptMarkup('extra2-module-bundle')));
|
|
319
728
|
};
|
|
320
729
|
|
|
730
|
+
const removeCache = async (loc) => {
|
|
731
|
+
await fs.remove(loc || cacheFolderPath);
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
const getCacheMeta = (loc) => {
|
|
735
|
+
const cacheFolders = fs.readdirSync(loc || cacheFolderPath, 'utf8');
|
|
736
|
+
const i = {};
|
|
737
|
+
const meta = cacheFolders
|
|
738
|
+
.reduce((prev, folder) => {
|
|
739
|
+
const location = `${loc || cacheFolderPath}/${folder}/.apos`;
|
|
740
|
+
const m = fs.readFileSync(location, 'utf8');
|
|
741
|
+
let [ mdate, id ] = m.split(' ');
|
|
742
|
+
// e.g. default:apos_2, default:apos_3, etc
|
|
743
|
+
if (prev[id]) {
|
|
744
|
+
i[id] = (i[id] || 1) + 1;
|
|
745
|
+
id = `${id}_${i[id]}`;
|
|
746
|
+
}
|
|
747
|
+
return {
|
|
748
|
+
...prev,
|
|
749
|
+
[id]: {
|
|
750
|
+
mdate: new Date(mdate),
|
|
751
|
+
folder,
|
|
752
|
+
location
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
}, {});
|
|
756
|
+
return {
|
|
757
|
+
folders: cacheFolders,
|
|
758
|
+
meta
|
|
759
|
+
};
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
// Retry `max` ms with `delay` ms between the retries
|
|
763
|
+
// until `assertFn` returns true or fail with `failMsg`
|
|
764
|
+
const retryAssertTrue = async (assertFn, failMsg, delay, max) => {
|
|
765
|
+
let current = 0;
|
|
766
|
+
while (!(await assertFn())) {
|
|
767
|
+
await Promise.delay(delay);
|
|
768
|
+
current += delay;
|
|
769
|
+
if (current >= max) {
|
|
770
|
+
assert.fail(`${failMsg}`);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
};
|
|
774
|
+
|
|
321
775
|
return {
|
|
322
776
|
publicFolderPath,
|
|
777
|
+
cacheFolderPath,
|
|
323
778
|
getScriptMarkup,
|
|
324
779
|
getStylesheetMarkup,
|
|
325
780
|
expectedBundlesNames,
|
|
326
781
|
deleteBuiltFolders,
|
|
327
|
-
allBundlesAreIncluded
|
|
782
|
+
allBundlesAreIncluded,
|
|
783
|
+
removeCache,
|
|
784
|
+
getCacheMeta,
|
|
785
|
+
retryAssertTrue
|
|
328
786
|
};
|
|
329
787
|
}
|
package/test/schemas.js
CHANGED
|
@@ -1652,6 +1652,31 @@ describe('Schemas', function() {
|
|
|
1652
1652
|
age: null
|
|
1653
1653
|
}, 'age', 'required');
|
|
1654
1654
|
});
|
|
1655
|
+
|
|
1656
|
+
it('should save date and time with the right format', async function () {
|
|
1657
|
+
const req = apos.task.getReq();
|
|
1658
|
+
const schema = apos.schema.compose({
|
|
1659
|
+
addFields: [
|
|
1660
|
+
{
|
|
1661
|
+
name: 'emptyValue',
|
|
1662
|
+
type: 'dateAndTime'
|
|
1663
|
+
},
|
|
1664
|
+
{
|
|
1665
|
+
name: 'goodValue',
|
|
1666
|
+
type: 'dateAndTime'
|
|
1667
|
+
}
|
|
1668
|
+
]
|
|
1669
|
+
});
|
|
1670
|
+
|
|
1671
|
+
const output = {};
|
|
1672
|
+
await apos.schema.convert(req, schema, {
|
|
1673
|
+
emptyValue: null,
|
|
1674
|
+
goodValue: '2022-05-09T22:36:00.000Z'
|
|
1675
|
+
}, output);
|
|
1676
|
+
|
|
1677
|
+
assert(output.emptyValue === null);
|
|
1678
|
+
assert(output.goodValue === '2022-05-09T22:36:00.000Z');
|
|
1679
|
+
});
|
|
1655
1680
|
});
|
|
1656
1681
|
|
|
1657
1682
|
async function testSchemaError(schema, input, path, name) {
|
package/test-lib/test.js
CHANGED
|
@@ -34,4 +34,16 @@ for (const dir of dirs) {
|
|
|
34
34
|
|
|
35
35
|
fs.writeFileSync(packageJson, JSON.stringify(packageJsonInfo, null, ' '));
|
|
36
36
|
|
|
37
|
+
// A "project level" package-lock.json for checking webpack build cache
|
|
38
|
+
|
|
39
|
+
const packageLockJson = path.join(__dirname, '/../test/package-lock.json');
|
|
40
|
+
const packageLockJsonInfo = {
|
|
41
|
+
_: 'Do not change, fake lock used for testing',
|
|
42
|
+
name: 'apostrophe',
|
|
43
|
+
version: 'current',
|
|
44
|
+
packages: {}
|
|
45
|
+
};
|
|
46
|
+
fs.removeSync(packageLockJson);
|
|
47
|
+
fs.writeFileSync(packageLockJson, JSON.stringify(packageLockJsonInfo, null, ' '));
|
|
48
|
+
|
|
37
49
|
module.exports = require('./util.js');
|
package/test-lib/util.js
CHANGED
|
@@ -10,10 +10,11 @@ const mongodbConnect = require('../lib/mongodb-connect');
|
|
|
10
10
|
// If `apos` is null, no work is done.
|
|
11
11
|
|
|
12
12
|
async function destroy(apos) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
await apos.destroy();
|
|
13
|
+
if (!apos) {
|
|
14
|
+
return;
|
|
16
15
|
}
|
|
16
|
+
await apos.destroy();
|
|
17
|
+
const dbName = apos.db && apos.db.databaseName;
|
|
17
18
|
// TODO at some point accommodate nonsense like testing remote databases
|
|
18
19
|
// that won't let us use dropDatabase, no shell available etc., but the
|
|
19
20
|
// important principle here is that we should not have to have an apos
|