@@ -523,6 +523,137 @@ describe('CliRepl', () => {
523
523
} ) ;
524
524
} ) ;
525
525
526
+ context ( 'in --json mode' , ( ) => {
527
+ beforeEach ( ( ) => {
528
+ cliReplOptions . shellCliOptions . quiet = true ;
529
+ } ) ;
530
+
531
+ it ( 'serializes results as EJSON with --json' , async ( ) => {
532
+ cliReplOptions . shellCliOptions . eval = [ '({ a: Long("0") })' ] ;
533
+ cliReplOptions . shellCliOptions . json = true ;
534
+ cliRepl = new CliRepl ( cliReplOptions ) ;
535
+ await startWithExpectedImmediateExit ( cliRepl , '' ) ;
536
+ expect ( JSON . parse ( output ) ) . to . deep . equal ( { a : { $numberLong : '0' } } ) ;
537
+ expect ( exitCode ) . to . equal ( 0 ) ;
538
+ } ) ;
539
+
540
+ it ( 'serializes results as EJSON with --json=canonical' , async ( ) => {
541
+ cliReplOptions . shellCliOptions . eval = [ '({ a: Long("0") })' ] ;
542
+ cliReplOptions . shellCliOptions . json = 'canonical' ;
543
+ cliRepl = new CliRepl ( cliReplOptions ) ;
544
+ await startWithExpectedImmediateExit ( cliRepl , '' ) ;
545
+ expect ( JSON . parse ( output ) ) . to . deep . equal ( { a : { $numberLong : '0' } } ) ;
546
+ expect ( exitCode ) . to . equal ( 0 ) ;
547
+ } ) ;
548
+
549
+ it ( 'serializes results as EJSON with --json=relaxed' , async ( ) => {
550
+ cliReplOptions . shellCliOptions . eval = [ '({ a: Long("0") })' ] ;
551
+ cliReplOptions . shellCliOptions . json = 'relaxed' ;
552
+ cliRepl = new CliRepl ( cliReplOptions ) ;
553
+ await startWithExpectedImmediateExit ( cliRepl , '' ) ;
554
+ expect ( JSON . parse ( output ) ) . to . deep . equal ( { a : 0 } ) ;
555
+ expect ( exitCode ) . to . equal ( 0 ) ;
556
+ } ) ;
557
+
558
+ it ( 'serializes user errors as EJSON with --json' , async ( ) => {
559
+ cliReplOptions . shellCliOptions . eval = [ 'throw new Error("asdf")' ] ;
560
+ cliReplOptions . shellCliOptions . json = true ;
561
+ cliRepl = new CliRepl ( cliReplOptions ) ;
562
+ await startWithExpectedImmediateExit ( cliRepl , '' ) ;
563
+ const parsed = JSON . parse ( output ) ;
564
+ expect ( parsed ) . to . haveOwnProperty ( 'message' , 'asdf' ) ;
565
+ expect ( parsed ) . to . haveOwnProperty ( 'name' , 'Error' ) ;
566
+ expect ( parsed . stack ) . to . be . a ( 'string' ) ;
567
+ expect ( exitCode ) . to . equal ( 1 ) ;
568
+ } ) ;
569
+
570
+ it ( 'serializes mongosh errors as EJSON with --json' , async ( ) => {
571
+ cliReplOptions . shellCliOptions . eval = [ 'db' ] ;
572
+ cliReplOptions . shellCliOptions . json = true ;
573
+ cliRepl = new CliRepl ( cliReplOptions ) ;
574
+ await startWithExpectedImmediateExit ( cliRepl , '' ) ;
575
+ const parsed = JSON . parse ( output ) ;
576
+ expect ( parsed ) . to . haveOwnProperty ( 'message' , '[SHAPI-10004] No connected database' ) ;
577
+ expect ( parsed ) . to . haveOwnProperty ( 'name' , 'MongoshInvalidInputError' ) ;
578
+ expect ( parsed ) . to . haveOwnProperty ( 'code' , 'SHAPI-10004' ) ;
579
+ expect ( parsed . stack ) . to . be . a ( 'string' ) ;
580
+ expect ( exitCode ) . to . equal ( 1 ) ;
581
+ } ) ;
582
+
583
+ it ( 'serializes primitive exceptions as EJSON with --json' , async ( ) => {
584
+ cliReplOptions . shellCliOptions . eval = [ 'throw null' ] ;
585
+ cliReplOptions . shellCliOptions . json = true ;
586
+ cliRepl = new CliRepl ( cliReplOptions ) ;
587
+ await startWithExpectedImmediateExit ( cliRepl , '' ) ;
588
+ const parsed = JSON . parse ( output ) ;
589
+ expect ( parsed ) . to . haveOwnProperty ( 'message' , 'null' ) ;
590
+ expect ( parsed ) . to . haveOwnProperty ( 'name' , 'Error' ) ;
591
+ expect ( parsed . stack ) . to . be . a ( 'string' ) ;
592
+ expect ( exitCode ) . to . equal ( 1 ) ;
593
+ } ) ;
594
+
595
+ it ( 'handles first-attempt EJSON serialization errors' , async ( ) => {
596
+ cliReplOptions . shellCliOptions . eval = [ '({ toJSON() { throw new Error("nested error"); }})' ] ;
597
+ cliReplOptions . shellCliOptions . json = true ;
598
+ cliRepl = new CliRepl ( cliReplOptions ) ;
599
+ await startWithExpectedImmediateExit ( cliRepl , '' ) ;
600
+ const parsed = JSON . parse ( output ) ;
601
+ expect ( parsed ) . to . haveOwnProperty ( 'message' , 'nested error' ) ;
602
+ expect ( parsed ) . to . haveOwnProperty ( 'name' , 'Error' ) ;
603
+ expect ( parsed . stack ) . to . be . a ( 'string' ) ;
604
+ expect ( exitCode ) . to . equal ( 1 ) ;
605
+ } ) ;
606
+
607
+ it ( 'does not handle second-attempt EJSON serialization errors' , async ( ) => {
608
+ cliReplOptions . shellCliOptions . eval = [ '({ toJSON() { throw ({ toJSON() { throw new Error("nested error") }}) }})' ] ;
609
+ cliReplOptions . shellCliOptions . json = true ;
610
+ cliRepl = new CliRepl ( cliReplOptions ) ;
611
+ try {
612
+ await cliRepl . start ( '' , { } ) ;
613
+ expect . fail ( 'missed exception' ) ;
614
+ } catch ( err ) {
615
+ expect ( err . message ) . to . equal ( 'nested error' ) ;
616
+ }
617
+ } ) ;
618
+
619
+ it ( 'rejects --json without --eval specifications' , async ( ) => {
620
+ cliReplOptions . shellCliOptions . json = true ;
621
+ cliRepl = new CliRepl ( cliReplOptions ) ;
622
+ try {
623
+ await cliRepl . start ( '' , { } ) ;
624
+ expect . fail ( 'missed exception' ) ;
625
+ } catch ( err ) {
626
+ expect ( err . message ) . to . equal ( 'Cannot use --json without --eval or with --shell or with extra files' ) ;
627
+ }
628
+ } ) ;
629
+
630
+ it ( 'rejects --json with --shell specifications' , async ( ) => {
631
+ cliReplOptions . shellCliOptions . eval = [ '1' ] ;
632
+ cliReplOptions . shellCliOptions . json = true ;
633
+ cliReplOptions . shellCliOptions . shell = true ;
634
+ cliRepl = new CliRepl ( cliReplOptions ) ;
635
+ try {
636
+ await cliRepl . start ( '' , { } ) ;
637
+ expect . fail ( 'missed exception' ) ;
638
+ } catch ( err ) {
639
+ expect ( err . message ) . to . equal ( 'Cannot use --json without --eval or with --shell or with extra files' ) ;
640
+ }
641
+ } ) ;
642
+
643
+ it ( 'rejects --json with --file specifications' , async ( ) => {
644
+ cliReplOptions . shellCliOptions . eval = [ '1' ] ;
645
+ cliReplOptions . shellCliOptions . json = true ;
646
+ cliReplOptions . shellCliOptions . fileNames = [ 'a.js' ] ;
647
+ cliRepl = new CliRepl ( cliReplOptions ) ;
648
+ try {
649
+ await cliRepl . start ( '' , { } ) ;
650
+ expect . fail ( 'missed exception' ) ;
651
+ } catch ( err ) {
652
+ expect ( err . message ) . to . equal ( 'Cannot use --json without --eval or with --shell or with extra files' ) ;
653
+ }
654
+ } ) ;
655
+ } ) ;
656
+
526
657
context ( 'with a global configuration file' , ( ) => {
527
658
it ( 'loads a global config file as YAML if present' , async ( ) => {
528
659
const globalConfigFile = path . join ( tmpdir . path , 'globalconfig.conf' ) ;
@@ -1402,7 +1533,7 @@ describe('CliRepl', () => {
1402
1533
1403
1534
context ( 'with a mongos' , ( ) => {
1404
1535
verifyAutocompletion ( {
1405
- testServer : startTestServer ( 'not-shared' , '--replicaset' , '--sharded' , '0' ) ,
1536
+ testServer : startTestServer ( 'not-shared' , '--replicaset' , '--csrs' , '-- sharded', '0' ) ,
1406
1537
wantWatch : true ,
1407
1538
wantShardDistribution : true ,
1408
1539
hasCollectionNames : false , // We're only spinning up a mongos here
0 commit comments