apostrophe 3.31.0 → 3.32.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/.eslintrc +3 -0
- package/CHANGELOG.md +21 -1
- package/modules/@apostrophecms/asset/index.js +65 -7
- package/modules/@apostrophecms/asset/lib/webpack/utils.js +242 -28
- package/modules/@apostrophecms/doc-type/ui/apos/components/AposDocEditor.vue +26 -16
- package/modules/@apostrophecms/i18n/i18n/en.json +17 -3
- package/modules/@apostrophecms/i18n/i18n/es.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/fr.json +1 -0
- package/modules/@apostrophecms/i18n/i18n/pt-BR.json +2 -1
- package/modules/@apostrophecms/i18n/i18n/sk.json +1 -0
- package/modules/@apostrophecms/i18n/ui/apos/components/AposI18nLocalize.vue +41 -20
- package/modules/@apostrophecms/login/index.js +123 -26
- package/modules/@apostrophecms/login/ui/apos/components/AposForgotPasswordForm.vue +124 -0
- package/modules/@apostrophecms/login/ui/apos/components/AposLoginForm.vue +339 -0
- package/modules/@apostrophecms/login/ui/apos/components/AposResetPasswordForm.vue +163 -0
- package/modules/@apostrophecms/login/ui/apos/components/TheAposLogin.vue +135 -293
- package/modules/@apostrophecms/login/ui/apos/components/TheAposLoginHeader.vue +65 -14
- package/modules/@apostrophecms/login/ui/apos/mixins/AposLoginFormMixin.js +45 -0
- package/modules/@apostrophecms/login/views/passwordResetEmail.html +9 -0
- package/modules/@apostrophecms/modal/ui/apos/components/AposModal.vue +17 -6
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalBody.vue +4 -1
- package/modules/@apostrophecms/modal/ui/apos/components/AposModalTabs.vue +7 -1
- package/modules/@apostrophecms/piece-type/index.js +1 -1
- package/modules/@apostrophecms/rich-text-widget/ui/apos/components/AposRichTextWidgetEditor.vue +4 -3
- package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Default.js +11 -5
- package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Heading.js +6 -2
- package/modules/@apostrophecms/rich-text-widget/ui/apos/tiptap-extensions/Link.js +7 -4
- package/modules/@apostrophecms/schema/lib/addFieldTypes.js +1 -1
- package/modules/@apostrophecms/schema/ui/apos/components/AposInputWrapper.vue +4 -1
- package/modules/@apostrophecms/schema/ui/apos/components/AposSchema.vue +4 -0
- package/modules/@apostrophecms/template/index.js +11 -12
- package/modules/@apostrophecms/template/lib/bundlesLoader.js +20 -5
- package/modules/@apostrophecms/ui/ui/apos/mixins/AposAdvisoryLockMixin.js +2 -1
- package/modules/@apostrophecms/widget-type/index.js +17 -3
- package/package.json +1 -1
- package/test/assets.js +338 -25
- package/test/extra_node_modules/@company/bundle/index.js +8 -0
- package/test/extra_node_modules/@company/bundle/ui/src/company.js +3 -0
- package/test/extra_node_modules/@company/bundle/ui/src/company.scss +3 -0
- package/test/login.js +427 -12
- package/test/modules/@company/bundle/index.js +10 -0
- package/test/modules/@company/bundle/ui/src/company.js +3 -0
- package/test/modules/@company/bundle/ui/src/company.scss +3 -0
- package/test/modules/bundle-edge/index.js +10 -0
- package/test/modules/bundle-edge/ui/src/edge.js +3 -0
- package/test/modules/bundle-edge/ui/src/edge.scss +3 -0
- package/test/modules/bundle-page/index.js +2 -1
- package/test/modules/bundle-page/ui/src/extra.js +3 -1
- package/test/modules/bundle-page/ui/src/extra.scss +3 -0
- package/test/modules/bundle-page/ui/src/main.js +3 -0
- package/test/modules/bundle-page/ui/src/main.scss +3 -0
- package/test/modules/bundle-page-type/index.js +12 -0
- package/test/modules/bundle-page-type/ui/src/another.js +3 -0
- package/test/modules/bundle-page-type/ui/src/index.js +3 -0
- package/test/modules/bundle-page-type/ui/src/index.scss +3 -0
- package/test/modules/bundle-page-type/ui/src/main.js +3 -0
- package/test/modules/bundle-page-type/ui/src/main.scss +3 -0
- package/test/modules/bundle-widget/ui/src/extra2.js +3 -1
- package/test-lib/test.js +9 -1
package/test/login.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
const t = require('../test-lib/test.js');
|
|
2
|
-
const assert = require('assert');
|
|
3
|
-
|
|
4
|
-
let apos;
|
|
2
|
+
const assert = require('assert').strict;
|
|
5
3
|
|
|
6
4
|
describe('Login', function() {
|
|
5
|
+
let apos;
|
|
6
|
+
let resetUserId;
|
|
7
|
+
let resetToken;
|
|
7
8
|
|
|
8
9
|
this.timeout(20000);
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
return t.destroy(apos);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
// EXISTENCE
|
|
15
|
-
|
|
16
|
-
it('should initialize', async function() {
|
|
11
|
+
before(async function () {
|
|
17
12
|
apos = await t.create({
|
|
18
13
|
root: module,
|
|
19
14
|
modules: {
|
|
@@ -25,9 +20,24 @@ describe('Login', function() {
|
|
|
25
20
|
}
|
|
26
21
|
}
|
|
27
22
|
}
|
|
23
|
+
},
|
|
24
|
+
'@apostrophecms/login': {
|
|
25
|
+
options: {
|
|
26
|
+
passwordReset: true
|
|
27
|
+
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
after(function() {
|
|
34
|
+
return t.destroy(apos);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// EXISTENCE
|
|
38
|
+
|
|
39
|
+
it('should initialize', async function() {
|
|
40
|
+
assert(apos);
|
|
31
41
|
|
|
32
42
|
assert(apos.modules['@apostrophecms/login']);
|
|
33
43
|
assert(apos.user.safe.remove);
|
|
@@ -227,7 +237,7 @@ describe('Login', function() {
|
|
|
227
237
|
assert(page.match(/logged out/));
|
|
228
238
|
});
|
|
229
239
|
|
|
230
|
-
it('
|
|
240
|
+
it('changing a user\'s password should invalidate sessions for that user', async function() {
|
|
231
241
|
|
|
232
242
|
const jar = apos.http.jar();
|
|
233
243
|
|
|
@@ -341,7 +351,7 @@ describe('Login', function() {
|
|
|
341
351
|
|
|
342
352
|
});
|
|
343
353
|
|
|
344
|
-
it('
|
|
354
|
+
it('changing a user\'s password should invalidate bearer tokens for that user', async function() {
|
|
345
355
|
|
|
346
356
|
// Log in
|
|
347
357
|
let response = await apos.http.post('/api/v1/@apostrophecms/login/login', {
|
|
@@ -447,4 +457,409 @@ describe('Login', function() {
|
|
|
447
457
|
assert(!page2.match(/Bob Smith/));
|
|
448
458
|
assert(page2.match(/System Task/));
|
|
449
459
|
});
|
|
460
|
+
|
|
461
|
+
it('should validate POST /login/reset-request', async function() {
|
|
462
|
+
const jar = apos.http.jar();
|
|
463
|
+
await apos.http.get(
|
|
464
|
+
'/',
|
|
465
|
+
{
|
|
466
|
+
jar
|
|
467
|
+
}
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
await assert.rejects(() => apos.http.post(
|
|
471
|
+
'/api/v1/@apostrophecms/login/reset-request',
|
|
472
|
+
{
|
|
473
|
+
body: {
|
|
474
|
+
session: true
|
|
475
|
+
},
|
|
476
|
+
jar
|
|
477
|
+
}
|
|
478
|
+
), {
|
|
479
|
+
status: 400
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it('should hide sensitive exceptions POST /login/reset-request', async function() {
|
|
484
|
+
let log;
|
|
485
|
+
const orig = apos.util.error;
|
|
486
|
+
apos.util.error = (m) => {
|
|
487
|
+
log = m;
|
|
488
|
+
};
|
|
489
|
+
const jar = apos.http.jar();
|
|
490
|
+
await apos.http.get(
|
|
491
|
+
'/',
|
|
492
|
+
{
|
|
493
|
+
jar
|
|
494
|
+
}
|
|
495
|
+
);
|
|
496
|
+
await apos.http.post(
|
|
497
|
+
'/api/v1/@apostrophecms/login/reset-request',
|
|
498
|
+
{
|
|
499
|
+
body: {
|
|
500
|
+
email: 'invalidUser',
|
|
501
|
+
session: true
|
|
502
|
+
},
|
|
503
|
+
jar
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
assert.match(log, /invalidUser/);
|
|
507
|
+
|
|
508
|
+
const user = apos.user.newInstance();
|
|
509
|
+
user.title = 'noEmail';
|
|
510
|
+
user.username = 'noEmail';
|
|
511
|
+
user.password = 'secret';
|
|
512
|
+
user.role = 'guest';
|
|
513
|
+
await apos.user.insert(apos.task.getReq(), user);
|
|
514
|
+
|
|
515
|
+
await apos.http.post(
|
|
516
|
+
'/api/v1/@apostrophecms/login/reset-request',
|
|
517
|
+
{
|
|
518
|
+
body: {
|
|
519
|
+
email: 'noEmail',
|
|
520
|
+
session: true
|
|
521
|
+
},
|
|
522
|
+
jar
|
|
523
|
+
}
|
|
524
|
+
);
|
|
525
|
+
assert.match(log, /noEmail/);
|
|
526
|
+
|
|
527
|
+
apos.util.error = orig;
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
it('should reset password POST /login/reset-request (request)', async function() {
|
|
531
|
+
let args;
|
|
532
|
+
const orig = apos.login.email;
|
|
533
|
+
apos.login.email = (req, ...a) => {
|
|
534
|
+
args = a;
|
|
535
|
+
};
|
|
536
|
+
const jar = apos.http.jar();
|
|
537
|
+
await apos.http.get(
|
|
538
|
+
'/',
|
|
539
|
+
{
|
|
540
|
+
jar
|
|
541
|
+
}
|
|
542
|
+
);
|
|
543
|
+
|
|
544
|
+
let user = apos.user.newInstance();
|
|
545
|
+
user.title = 'resetUser';
|
|
546
|
+
user.email = 'resetUser@example.com';
|
|
547
|
+
user.username = 'resetUser';
|
|
548
|
+
user.password = 'secret';
|
|
549
|
+
user.role = 'guest';
|
|
550
|
+
user = await apos.user.insert(apos.task.getReq(), user);
|
|
551
|
+
resetUserId = user._id;
|
|
552
|
+
|
|
553
|
+
await apos.http.post(
|
|
554
|
+
'/api/v1/@apostrophecms/login/reset-request',
|
|
555
|
+
{
|
|
556
|
+
body: {
|
|
557
|
+
email: 'resetUser',
|
|
558
|
+
session: true
|
|
559
|
+
},
|
|
560
|
+
jar
|
|
561
|
+
}
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
{
|
|
565
|
+
assert(Array.isArray(args));
|
|
566
|
+
const [ template, data, opts ] = args;
|
|
567
|
+
assert(template);
|
|
568
|
+
assert.deepEqual(data.user._id, user._id);
|
|
569
|
+
assert(data.user.passwordResetAt);
|
|
570
|
+
assert.match(data.url, /\/login\?reset=/);
|
|
571
|
+
assert.match(data.url, /&email=/);
|
|
572
|
+
assert(data.site);
|
|
573
|
+
assert.equal(opts.to, user.email);
|
|
574
|
+
assert(opts.subject);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
await apos.http.post(
|
|
578
|
+
'/api/v1/@apostrophecms/login/reset-request',
|
|
579
|
+
{
|
|
580
|
+
body: {
|
|
581
|
+
email: 'resetUser@example.com',
|
|
582
|
+
session: true
|
|
583
|
+
},
|
|
584
|
+
jar
|
|
585
|
+
}
|
|
586
|
+
);
|
|
587
|
+
|
|
588
|
+
{
|
|
589
|
+
assert(Array.isArray(args));
|
|
590
|
+
const [ template, data, opts ] = args;
|
|
591
|
+
assert(template);
|
|
592
|
+
assert.deepEqual(data.user._id, user._id);
|
|
593
|
+
assert(data.user.passwordResetAt);
|
|
594
|
+
assert.match(data.url, /\/login\?reset=/);
|
|
595
|
+
assert.match(data.url, /&email=/);
|
|
596
|
+
assert(data.site);
|
|
597
|
+
assert.equal(opts.to, user.email);
|
|
598
|
+
assert(opts.subject);
|
|
599
|
+
|
|
600
|
+
// Safe the token for the reset tests
|
|
601
|
+
const url = new URL(data.url);
|
|
602
|
+
resetToken = url.searchParams.get('reset');
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
apos.login.email = orig;
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
it('should reset password GET /login/reset (validate)', async function() {
|
|
609
|
+
const user = await apos.doc.db.findOne({ _id: resetUserId });
|
|
610
|
+
|
|
611
|
+
// Fail
|
|
612
|
+
await assert.rejects(() => apos.http.get(
|
|
613
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
614
|
+
{
|
|
615
|
+
qs: {}
|
|
616
|
+
}
|
|
617
|
+
), {
|
|
618
|
+
status: 400
|
|
619
|
+
});
|
|
620
|
+
await assert.rejects(() => apos.http.get(
|
|
621
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
622
|
+
{
|
|
623
|
+
qs: {
|
|
624
|
+
reset: 'invalid',
|
|
625
|
+
email: user.username
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
), {
|
|
629
|
+
status: 400
|
|
630
|
+
});
|
|
631
|
+
await assert.rejects(() => apos.http.get(
|
|
632
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
633
|
+
{
|
|
634
|
+
qs: {
|
|
635
|
+
reset: resetToken,
|
|
636
|
+
email: 'invalid'
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
), {
|
|
640
|
+
status: 400
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
// Success
|
|
644
|
+
await apos.http.get(
|
|
645
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
646
|
+
{
|
|
647
|
+
qs: {
|
|
648
|
+
reset: resetToken,
|
|
649
|
+
email: user.username
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
await apos.http.get(
|
|
655
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
656
|
+
{
|
|
657
|
+
qs: {
|
|
658
|
+
reset: resetToken,
|
|
659
|
+
email: user.email
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
);
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
it('should reset password POST /login/reset (validate & reset)', async function() {
|
|
666
|
+
const jar = apos.http.jar();
|
|
667
|
+
const user = await apos.doc.db.findOne({ _id: resetUserId });
|
|
668
|
+
await apos.http.get(
|
|
669
|
+
'/',
|
|
670
|
+
{
|
|
671
|
+
jar
|
|
672
|
+
}
|
|
673
|
+
);
|
|
674
|
+
|
|
675
|
+
// Validate
|
|
676
|
+
await assert.rejects(() => apos.http.post(
|
|
677
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
678
|
+
{
|
|
679
|
+
body: {
|
|
680
|
+
session: true
|
|
681
|
+
},
|
|
682
|
+
jar
|
|
683
|
+
}
|
|
684
|
+
), {
|
|
685
|
+
status: 400
|
|
686
|
+
});
|
|
687
|
+
await assert.rejects(() => apos.http.post(
|
|
688
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
689
|
+
{
|
|
690
|
+
body: {
|
|
691
|
+
reset: 'invalid',
|
|
692
|
+
email: user.email,
|
|
693
|
+
password: 'new more secret',
|
|
694
|
+
session: true
|
|
695
|
+
},
|
|
696
|
+
jar
|
|
697
|
+
}
|
|
698
|
+
), {
|
|
699
|
+
status: 400
|
|
700
|
+
});
|
|
701
|
+
await assert.rejects(() => apos.http.post(
|
|
702
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
703
|
+
{
|
|
704
|
+
body: {
|
|
705
|
+
reset: resetToken,
|
|
706
|
+
email: 'invalid',
|
|
707
|
+
password: 'new more secret',
|
|
708
|
+
session: true
|
|
709
|
+
},
|
|
710
|
+
jar
|
|
711
|
+
}
|
|
712
|
+
), {
|
|
713
|
+
status: 400
|
|
714
|
+
});
|
|
715
|
+
await assert.rejects(() => apos.http.post(
|
|
716
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
717
|
+
{
|
|
718
|
+
body: {
|
|
719
|
+
reset: resetToken,
|
|
720
|
+
email: user.email,
|
|
721
|
+
password: '',
|
|
722
|
+
session: true
|
|
723
|
+
},
|
|
724
|
+
jar
|
|
725
|
+
}
|
|
726
|
+
), {
|
|
727
|
+
status: 400
|
|
728
|
+
});
|
|
729
|
+
await assert.rejects(() => apos.http.post(
|
|
730
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
731
|
+
{
|
|
732
|
+
body: {
|
|
733
|
+
// explicit check for boolean cheat!
|
|
734
|
+
reset: false,
|
|
735
|
+
email: user.email,
|
|
736
|
+
password: 'new more secret',
|
|
737
|
+
session: true
|
|
738
|
+
},
|
|
739
|
+
jar
|
|
740
|
+
}
|
|
741
|
+
), {
|
|
742
|
+
status: 400
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
// Reset
|
|
746
|
+
await apos.http.post(
|
|
747
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
748
|
+
{
|
|
749
|
+
body: {
|
|
750
|
+
reset: resetToken,
|
|
751
|
+
email: user.email,
|
|
752
|
+
password: 'new more secret',
|
|
753
|
+
session: true
|
|
754
|
+
},
|
|
755
|
+
jar
|
|
756
|
+
}
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
// Can not reset anymore
|
|
760
|
+
await assert.rejects(() => apos.http.post(
|
|
761
|
+
'/api/v1/@apostrophecms/login/reset',
|
|
762
|
+
{
|
|
763
|
+
body: {
|
|
764
|
+
reset: resetToken,
|
|
765
|
+
email: user.email,
|
|
766
|
+
password: 'new even more secret',
|
|
767
|
+
session: true
|
|
768
|
+
},
|
|
769
|
+
jar
|
|
770
|
+
}
|
|
771
|
+
), {
|
|
772
|
+
status: 400
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
// Login with the new password
|
|
776
|
+
await apos.http.post(
|
|
777
|
+
'/api/v1/@apostrophecms/login/login',
|
|
778
|
+
{
|
|
779
|
+
body: {
|
|
780
|
+
username: user.email,
|
|
781
|
+
password: 'new more secret',
|
|
782
|
+
session: true
|
|
783
|
+
},
|
|
784
|
+
jar
|
|
785
|
+
}
|
|
786
|
+
);
|
|
787
|
+
const page = await apos.http.get(
|
|
788
|
+
'/',
|
|
789
|
+
{
|
|
790
|
+
jar
|
|
791
|
+
}
|
|
792
|
+
);
|
|
793
|
+
assert(page.match(/logged in/));
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
it('should find user by reset data', async function() {
|
|
797
|
+
let user = apos.user.newInstance();
|
|
798
|
+
user.title = 'getResetUser';
|
|
799
|
+
user.email = 'getResetUser@example.com';
|
|
800
|
+
user.username = 'getResetUser';
|
|
801
|
+
user.password = 'secret';
|
|
802
|
+
user.role = 'guest';
|
|
803
|
+
user = await apos.user.insert(apos.task.getReq(), user);
|
|
804
|
+
|
|
805
|
+
// Find by email
|
|
806
|
+
{
|
|
807
|
+
const found = await apos.login.getPasswordResetUser(user.email);
|
|
808
|
+
assert.equal(found._id, user._id);
|
|
809
|
+
}
|
|
810
|
+
// Find by username
|
|
811
|
+
{
|
|
812
|
+
const found = await apos.login.getPasswordResetUser(user.username);
|
|
813
|
+
assert.equal(found._id, user._id);
|
|
814
|
+
}
|
|
815
|
+
// Fail with no token
|
|
816
|
+
await assert.rejects(
|
|
817
|
+
() => apos.login.getPasswordResetUser(user.username, ''),
|
|
818
|
+
{
|
|
819
|
+
message: 'invalid'
|
|
820
|
+
}
|
|
821
|
+
);
|
|
822
|
+
await assert.rejects(
|
|
823
|
+
() => apos.login.getPasswordResetUser(user.username, null),
|
|
824
|
+
{
|
|
825
|
+
message: 'invalid'
|
|
826
|
+
}
|
|
827
|
+
);
|
|
828
|
+
await assert.rejects(
|
|
829
|
+
() => apos.login.getPasswordResetUser(user.username, 'invalid'),
|
|
830
|
+
{
|
|
831
|
+
message: 'notfound'
|
|
832
|
+
}
|
|
833
|
+
);
|
|
834
|
+
|
|
835
|
+
user.passwordReset = 'secret';
|
|
836
|
+
user.passwordResetAt = new Date();
|
|
837
|
+
user = await apos.user.update(apos.task.getReq(), user);
|
|
838
|
+
// Find by email and validate token
|
|
839
|
+
{
|
|
840
|
+
const found = await apos.login.getPasswordResetUser(user.email, 'secret');
|
|
841
|
+
assert.equal(found._id, user._id);
|
|
842
|
+
}
|
|
843
|
+
// // Find by username and validate token
|
|
844
|
+
{
|
|
845
|
+
const found = await apos.login.getPasswordResetUser(user.username, 'secret');
|
|
846
|
+
assert.equal(found._id, user._id);
|
|
847
|
+
}
|
|
848
|
+
await assert.rejects(
|
|
849
|
+
() => apos.login.getPasswordResetUser(user.username, 'invalid'),
|
|
850
|
+
{
|
|
851
|
+
message: 'Incorrect passwordReset'
|
|
852
|
+
}
|
|
853
|
+
);
|
|
854
|
+
|
|
855
|
+
// Expired
|
|
856
|
+
user.passwordResetAt = new Date(0);
|
|
857
|
+
user = await apos.user.update(apos.task.getReq(), user);
|
|
858
|
+
await assert.rejects(
|
|
859
|
+
() => apos.login.getPasswordResetUser(user.username, 'invalid'),
|
|
860
|
+
{
|
|
861
|
+
message: 'notfound'
|
|
862
|
+
}
|
|
863
|
+
);
|
|
864
|
+
});
|
|
450
865
|
});
|
package/test-lib/test.js
CHANGED
|
@@ -29,7 +29,15 @@ const packageJsonInfo = {
|
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
for (const dir of dirs) {
|
|
32
|
-
|
|
32
|
+
// Add namespaced modules support
|
|
33
|
+
if (dir.startsWith('@')) {
|
|
34
|
+
const submodules = fs.readdirSync(path.join(extras, dir));
|
|
35
|
+
for (const submodule of submodules) {
|
|
36
|
+
packageJsonInfo.dependencies[`${dir}/${submodule}`] = '1.0.0';
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
packageJsonInfo.dependencies[dir] = '1.0.0';
|
|
40
|
+
}
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
fs.writeFileSync(packageJson, JSON.stringify(packageJsonInfo, null, ' '));
|