@@ -466,6 +466,9 @@ describe('MarkdownService', () => {
466
466
const rootNode = document . createElement ( 'button' ) ;
467
467
468
468
const componentRef = {
469
+ changeDetectorRef : {
470
+ markForCheck : ( ) => { } ,
471
+ } ,
469
472
hostView : {
470
473
rootNodes : [ rootNode ] ,
471
474
onDestroy : ( callback ) => { } ,
@@ -486,182 +489,6 @@ describe('MarkdownService', () => {
486
489
return { embeddedViewRef, rootNode } ;
487
490
}
488
491
489
- it ( 'should render clipboard with default button when clipboard is true and buttonComponent/buttonTemplate is not provided' , ( ) => {
490
-
491
- const preElement = document . createElement ( 'pre' ) ;
492
- preElement . innerText = 'mock-pre-element-text' ;
493
- const container = document . createElement ( 'div' ) ;
494
- container . append ( preElement ) ;
495
-
496
- const { componentRef, rootNode } = mockComponentRef ( ) ;
497
-
498
- window [ 'ClipboardJS' ] = class ClipboardJS { } ;
499
-
500
- const clipboardSpy = spyOn ( window , 'ClipboardJS' ) ;
501
-
502
- viewContainerRefSpy . createComponent . and . returnValue ( componentRef ) ;
503
-
504
- markdownService . render ( container , { clipboard : true } , viewContainerRef ) ;
505
-
506
- expect ( viewContainerRefSpy . createComponent ) . toHaveBeenCalledWith ( ClipboardButtonComponent as any ) ;
507
- expect ( clipboardSpy ) . toHaveBeenCalledWith ( rootNode , { text : jasmine . any ( Function ) } ) ;
508
- expect ( ( clipboardSpy . calls . argsFor ( 0 ) [ 1 ] as any ) . text ( ) ) . toBe ( preElement . innerText ) ;
509
- } ) ;
510
-
511
- it ( 'should render clipboard with buttonComponent when clipboard is true and buttonComponent is provided' , ( ) => {
512
-
513
- class MockButtonComponent { mockButton = true ; }
514
-
515
- const preElement = document . createElement ( 'pre' ) ;
516
- preElement . innerText = 'mock-pre-element-text' ;
517
- const container = document . createElement ( 'div' ) ;
518
- container . append ( preElement ) ;
519
-
520
- const { componentRef, rootNode } = mockComponentRef ( ) ;
521
-
522
- window [ 'ClipboardJS' ] = class ClipboardJS { } ;
523
-
524
- const clipboardSpy = spyOn ( window , 'ClipboardJS' ) ;
525
-
526
- viewContainerRefSpy . createComponent . and . returnValue ( componentRef ) ;
527
-
528
- markdownService . render (
529
- container ,
530
- { clipboard : true , clipboardOptions : { buttonComponent : MockButtonComponent } } ,
531
- viewContainerRef ,
532
- ) ;
533
-
534
- expect ( viewContainerRefSpy . createComponent ) . toHaveBeenCalledWith ( MockButtonComponent as any ) ;
535
- expect ( clipboardSpy ) . toHaveBeenCalledWith ( rootNode , { text : jasmine . any ( Function ) } ) ;
536
- expect ( ( clipboardSpy . calls . argsFor ( 0 ) [ 1 ] as any ) . text ( ) ) . toBe ( preElement . innerText ) ;
537
- } ) ;
538
-
539
- it ( 'should render clipboard with buttonTemplate when clipboard is true and buttonTemplate is provided' , ( ) => {
540
-
541
- const mockTemplateRef = {
542
- elementRef : { nativeElement : 'mock-template-ref' } ,
543
- } as TemplateRef < unknown > ;
544
-
545
- const preElement = document . createElement ( 'pre' ) ;
546
- preElement . innerText = 'mock-pre-element-text' ;
547
- const container = document . createElement ( 'div' ) ;
548
- container . append ( preElement ) ;
549
-
550
- const { embeddedViewRef, rootNode } = mockEmbeddedViewRef ( ) ;
551
-
552
- window [ 'ClipboardJS' ] = class ClipboardJS { } ;
553
-
554
- const clipboardSpy = spyOn ( window , 'ClipboardJS' ) ;
555
-
556
- viewContainerRefSpy . createEmbeddedView . and . returnValue ( embeddedViewRef ) ;
557
-
558
- markdownService . render (
559
- container ,
560
- { clipboard : true , clipboardOptions : { buttonTemplate : mockTemplateRef } } ,
561
- viewContainerRef ,
562
- ) ;
563
-
564
- expect ( viewContainerRefSpy . createEmbeddedView ) . toHaveBeenCalledWith ( mockTemplateRef ) ;
565
- expect ( clipboardSpy ) . toHaveBeenCalledWith ( rootNode , { text : jasmine . any ( Function ) } ) ;
566
- expect ( ( clipboardSpy . calls . argsFor ( 0 ) [ 1 ] as any ) . text ( ) ) . toBe ( preElement . innerText ) ;
567
- } ) ;
568
-
569
- it ( 'should destroy clipboard instances when host view is destroyed' , ( ) => {
570
-
571
- const preElement = document . createElement ( 'pre' ) ;
572
- preElement . innerText = 'mock-pre-element-text' ;
573
- const container = document . createElement ( 'div' ) ;
574
- container . append ( preElement ) ;
575
-
576
- const { componentRef } = mockComponentRef ( ) ;
577
- const mockClipboardInstance = { destroy : ( ) => { } } ;
578
-
579
- window [ 'ClipboardJS' ] = ( ) => { } ;
580
-
581
- spyOn ( window , 'ClipboardJS' ) . and . returnValue ( mockClipboardInstance ) ;
582
-
583
- const hostViewDestroySpy = spyOn ( componentRef . hostView , 'onDestroy' ) ;
584
- const clipboardDestroySpy = spyOn ( mockClipboardInstance , 'destroy' ) ;
585
-
586
- viewContainerRefSpy . createComponent . and . returnValue ( componentRef ) ;
587
-
588
- markdownService . render ( container , { clipboard : true } , viewContainerRef ) ;
589
-
590
- expect ( hostViewDestroySpy ) . toHaveBeenCalled ( ) ;
591
-
592
- const hostViewDestroyCallback = hostViewDestroySpy . calls . argsFor ( 0 ) [ 0 ] ;
593
- hostViewDestroyCallback ( ) ;
594
-
595
- expect ( clipboardDestroySpy ) . toHaveBeenCalled ( ) ;
596
- } ) ;
597
-
598
- it ( 'should not render clipboard when clipboard is omitted/false/null/undefined' , ( ) => {
599
-
600
- const preElement = document . createElement ( 'pre' ) ;
601
- const container = document . createElement ( 'div' ) ;
602
- container . append ( preElement ) ;
603
-
604
- window [ 'ClipboardJS' ] = {
605
- new : ( ) => { } ,
606
- } ;
607
-
608
- spyOn ( window , 'ClipboardJS' ) ;
609
-
610
- const useCases = [
611
- ( ) => markdownService . render ( container ) ,
612
- ( ) => markdownService . render ( container , { clipboard : false } , viewContainerRef ) ,
613
- ( ) => markdownService . render ( container , { clipboard : null ! } , viewContainerRef ) ,
614
- ( ) => markdownService . render ( container , { clipboard : undefined } , viewContainerRef ) ,
615
- ] ;
616
-
617
- useCases . forEach ( func => {
618
- func ( ) ;
619
- expect ( window [ 'ClipboardJS' ] ) . not . toHaveBeenCalled ( ) ;
620
- } ) ;
621
- } ) ;
622
-
623
- it ( 'should not render clipboard or throw when platform is not browser' , ( ) => {
624
-
625
- const preElement = document . createElement ( 'pre' ) ;
626
- const container = document . createElement ( 'div' ) ;
627
- container . append ( preElement ) ;
628
-
629
- window [ 'ClipboardJS' ] = { } ;
630
-
631
- spyOn ( window , 'ClipboardJS' ) ;
632
-
633
- markdownService [ 'platform' ] = 'server' ;
634
-
635
- expect ( ( ) => markdownService . render ( container , { clipboard : true } ) ) . not . toThrowError ( ) ;
636
- expect ( window [ 'ClipboardJS' ] ) . not . toHaveBeenCalled ( ) ;
637
- } ) ;
638
-
639
- it ( 'should throw when clipboard is called but not loaded' , ( ) => {
640
-
641
- const container = document . createElement ( 'div' ) ;
642
-
643
- window [ 'ClipboardJS' ] = undefined ;
644
-
645
- expect ( ( ) => markdownService . render ( container , { clipboard : true } ) ) . toThrowError ( errorClipboardNotLoaded ) ;
646
- } ) ;
647
-
648
- it ( 'should throw when clipboard is called and viewContainerRef is omitted/null/undefined' , ( ) => {
649
-
650
- const container = document . createElement ( 'div' ) ;
651
-
652
- window [ 'ClipboardJS' ] = { } ;
653
-
654
- const useCases = [
655
- ( ) => markdownService . render ( container , { clipboard : true } ) ,
656
- ( ) => markdownService . render ( container , { clipboard : true } , null ! ) ,
657
- ( ) => markdownService . render ( container , { clipboard : true } , undefined ) ,
658
- ] ;
659
-
660
- useCases . forEach ( func => {
661
- expect ( func ) . toThrowError ( errorClipboardViewContainerRequired ) ;
662
- } ) ;
663
- } ) ;
664
-
665
492
it ( 'should render katex when katex is true' , ( ) => {
666
493
667
494
const element = document . createElement ( 'div' ) ;
@@ -909,6 +736,237 @@ describe('MarkdownService', () => {
909
736
expect ( mermaid . run ) . not . toHaveBeenCalled ( ) ;
910
737
} ) ;
911
738
739
+ it ( 'should render clipboard after katex and mermaid' , ( ) => {
740
+
741
+ const container = document . createElement ( 'div' ) ;
742
+ const pluginRenderingOrder : string [ ] = [ ] ;
743
+
744
+ // clipboard
745
+ const clipboardPreElement = document . createElement ( 'pre' ) ;
746
+ clipboardPreElement . innerText = 'mock-pre-element-text' ;
747
+ container . append ( clipboardPreElement ) ;
748
+
749
+ const { componentRef } = mockComponentRef ( ) ;
750
+ viewContainerRefSpy . createComponent . and . returnValue ( componentRef ) ;
751
+
752
+ window [ 'ClipboardJS' ] = class ClipboardJS {
753
+ constructor ( ) {
754
+ pluginRenderingOrder . push ( 'clipboard' ) ;
755
+ }
756
+ } ;
757
+
758
+ // katex
759
+ const katexElement = document . createElement ( 'div' ) ;
760
+ katexElement . innerHTML = '$E=mc^2$' ;
761
+ container . append ( katexElement ) ;
762
+
763
+ window [ 'katex' ] = { } ;
764
+ window [ 'renderMathInElement' ] = ( elem : HTMLElement , options ?: KatexOptions ) => { } ;
765
+
766
+ spyOn ( window , 'renderMathInElement' ) . and . callFake ( ( ) => {
767
+ pluginRenderingOrder . push ( 'katex' ) ;
768
+ } ) ;
769
+
770
+ // mermaid
771
+ const mermaidElement = document . createElement ( 'div' ) ;
772
+ mermaidElement . classList . add ( 'mermaid' ) ;
773
+ mermaidElement . innerHTML = 'graph TD; A-->B;' ;
774
+
775
+ container . append ( mermaidElement ) ;
776
+
777
+ window [ 'mermaid' ] = {
778
+ initialize : ( options : MermaidAPI . Config ) => { } ,
779
+ run : ( runOptions : MermaidAPI . RunOptions ) => { } ,
780
+ } ;
781
+
782
+ spyOn ( mermaid , 'run' ) . and . callFake ( ( ) => {
783
+ pluginRenderingOrder . push ( 'mermaid' ) ;
784
+ } ) ;
785
+
786
+ markdownService . render ( container , { clipboard : true , katex : true , mermaid : true } , viewContainerRef ) ;
787
+ expect ( pluginRenderingOrder ) . toEqual ( [ 'katex' , 'mermaid' , 'clipboard' ] ) ;
788
+ } ) ;
789
+
790
+ it ( 'should render clipboard with default button when clipboard is true and buttonComponent/buttonTemplate is not provided' , ( ) => {
791
+
792
+ const preElement = document . createElement ( 'pre' ) ;
793
+ preElement . innerText = 'mock-pre-element-text' ;
794
+ const container = document . createElement ( 'div' ) ;
795
+ container . append ( preElement ) ;
796
+
797
+ const { componentRef, rootNode } = mockComponentRef ( ) ;
798
+
799
+ window [ 'ClipboardJS' ] = class ClipboardJS { } ;
800
+
801
+ const clipboardSpy = spyOn ( window , 'ClipboardJS' ) ;
802
+ const markForCheckSpy = spyOn ( componentRef . changeDetectorRef , 'markForCheck' ) ;
803
+
804
+ viewContainerRefSpy . createComponent . and . returnValue ( componentRef ) ;
805
+
806
+ markdownService . render ( container , { clipboard : true } , viewContainerRef ) ;
807
+
808
+ expect ( viewContainerRefSpy . createComponent ) . toHaveBeenCalledWith ( ClipboardButtonComponent as any ) ;
809
+ expect ( markForCheckSpy ) . toHaveBeenCalled ( ) ;
810
+ expect ( clipboardSpy ) . toHaveBeenCalledWith ( rootNode , { text : jasmine . any ( Function ) } ) ;
811
+ expect ( ( clipboardSpy . calls . argsFor ( 0 ) [ 1 ] as any ) . text ( ) ) . toBe ( preElement . innerText ) ;
812
+ } ) ;
813
+
814
+ it ( 'should render clipboard with buttonComponent when clipboard is true and buttonComponent is provided' , ( ) => {
815
+
816
+ class MockButtonComponent { mockButton = true ; }
817
+
818
+ const preElement = document . createElement ( 'pre' ) ;
819
+ preElement . innerText = 'mock-pre-element-text' ;
820
+ const container = document . createElement ( 'div' ) ;
821
+ container . append ( preElement ) ;
822
+
823
+ const { componentRef, rootNode } = mockComponentRef ( ) ;
824
+
825
+ window [ 'ClipboardJS' ] = class ClipboardJS { } ;
826
+
827
+ const clipboardSpy = spyOn ( window , 'ClipboardJS' ) ;
828
+ const markForCheckSpy = spyOn ( componentRef . changeDetectorRef , 'markForCheck' ) ;
829
+
830
+ viewContainerRefSpy . createComponent . and . returnValue ( componentRef ) ;
831
+
832
+ markdownService . render (
833
+ container ,
834
+ { clipboard : true , clipboardOptions : { buttonComponent : MockButtonComponent } } ,
835
+ viewContainerRef ,
836
+ ) ;
837
+
838
+ expect ( viewContainerRefSpy . createComponent ) . toHaveBeenCalledWith ( MockButtonComponent as any ) ;
839
+ expect ( markForCheckSpy ) . toHaveBeenCalled ( ) ;
840
+ expect ( clipboardSpy ) . toHaveBeenCalledWith ( rootNode , { text : jasmine . any ( Function ) } ) ;
841
+ expect ( ( clipboardSpy . calls . argsFor ( 0 ) [ 1 ] as any ) . text ( ) ) . toBe ( preElement . innerText ) ;
842
+ } ) ;
843
+
844
+ it ( 'should render clipboard with buttonTemplate when clipboard is true and buttonTemplate is provided' , ( ) => {
845
+
846
+ const mockTemplateRef = {
847
+ elementRef : { nativeElement : 'mock-template-ref' } ,
848
+ } as TemplateRef < unknown > ;
849
+
850
+ const preElement = document . createElement ( 'pre' ) ;
851
+ preElement . innerText = 'mock-pre-element-text' ;
852
+ const container = document . createElement ( 'div' ) ;
853
+ container . append ( preElement ) ;
854
+
855
+ const { embeddedViewRef, rootNode } = mockEmbeddedViewRef ( ) ;
856
+
857
+ window [ 'ClipboardJS' ] = class ClipboardJS { } ;
858
+
859
+ const clipboardSpy = spyOn ( window , 'ClipboardJS' ) ;
860
+
861
+ viewContainerRefSpy . createEmbeddedView . and . returnValue ( embeddedViewRef ) ;
862
+
863
+ markdownService . render (
864
+ container ,
865
+ { clipboard : true , clipboardOptions : { buttonTemplate : mockTemplateRef } } ,
866
+ viewContainerRef ,
867
+ ) ;
868
+
869
+ expect ( viewContainerRefSpy . createEmbeddedView ) . toHaveBeenCalledWith ( mockTemplateRef ) ;
870
+ expect ( clipboardSpy ) . toHaveBeenCalledWith ( rootNode , { text : jasmine . any ( Function ) } ) ;
871
+ expect ( ( clipboardSpy . calls . argsFor ( 0 ) [ 1 ] as any ) . text ( ) ) . toBe ( preElement . innerText ) ;
872
+ } ) ;
873
+
874
+ it ( 'should destroy clipboard instances when host view is destroyed' , ( ) => {
875
+
876
+ const preElement = document . createElement ( 'pre' ) ;
877
+ preElement . innerText = 'mock-pre-element-text' ;
878
+ const container = document . createElement ( 'div' ) ;
879
+ container . append ( preElement ) ;
880
+
881
+ const { componentRef } = mockComponentRef ( ) ;
882
+ const mockClipboardInstance = { destroy : ( ) => { } } ;
883
+
884
+ window [ 'ClipboardJS' ] = ( ) => { } ;
885
+
886
+ spyOn ( window , 'ClipboardJS' ) . and . returnValue ( mockClipboardInstance ) ;
887
+
888
+ const hostViewDestroySpy = spyOn ( componentRef . hostView , 'onDestroy' ) ;
889
+ const clipboardDestroySpy = spyOn ( mockClipboardInstance , 'destroy' ) ;
890
+
891
+ viewContainerRefSpy . createComponent . and . returnValue ( componentRef ) ;
892
+
893
+ markdownService . render ( container , { clipboard : true } , viewContainerRef ) ;
894
+
895
+ expect ( hostViewDestroySpy ) . toHaveBeenCalled ( ) ;
896
+
897
+ const hostViewDestroyCallback = hostViewDestroySpy . calls . argsFor ( 0 ) [ 0 ] ;
898
+ hostViewDestroyCallback ( ) ;
899
+
900
+ expect ( clipboardDestroySpy ) . toHaveBeenCalled ( ) ;
901
+ } ) ;
902
+
903
+ it ( 'should not render clipboard when clipboard is omitted/false/null/undefined' , ( ) => {
904
+
905
+ const preElement = document . createElement ( 'pre' ) ;
906
+ const container = document . createElement ( 'div' ) ;
907
+ container . append ( preElement ) ;
908
+
909
+ window [ 'ClipboardJS' ] = {
910
+ new : ( ) => { } ,
911
+ } ;
912
+
913
+ spyOn ( window , 'ClipboardJS' ) ;
914
+
915
+ const useCases = [
916
+ ( ) => markdownService . render ( container ) ,
917
+ ( ) => markdownService . render ( container , { clipboard : false } , viewContainerRef ) ,
918
+ ( ) => markdownService . render ( container , { clipboard : null ! } , viewContainerRef ) ,
919
+ ( ) => markdownService . render ( container , { clipboard : undefined } , viewContainerRef ) ,
920
+ ] ;
921
+
922
+ useCases . forEach ( func => {
923
+ func ( ) ;
924
+ expect ( window [ 'ClipboardJS' ] ) . not . toHaveBeenCalled ( ) ;
925
+ } ) ;
926
+ } ) ;
927
+
928
+ it ( 'should not render clipboard or throw when platform is not browser' , ( ) => {
929
+
930
+ const preElement = document . createElement ( 'pre' ) ;
931
+ const container = document . createElement ( 'div' ) ;
932
+ container . append ( preElement ) ;
933
+
934
+ window [ 'ClipboardJS' ] = { } ;
935
+
936
+ spyOn ( window , 'ClipboardJS' ) ;
937
+
938
+ markdownService [ 'platform' ] = 'server' ;
939
+
940
+ expect ( ( ) => markdownService . render ( container , { clipboard : true } ) ) . not . toThrowError ( ) ;
941
+ expect ( window [ 'ClipboardJS' ] ) . not . toHaveBeenCalled ( ) ;
942
+ } ) ;
943
+
944
+ it ( 'should throw when clipboard is called but not loaded' , ( ) => {
945
+
946
+ const container = document . createElement ( 'div' ) ;
947
+
948
+ window [ 'ClipboardJS' ] = undefined ;
949
+
950
+ expect ( ( ) => markdownService . render ( container , { clipboard : true } ) ) . toThrowError ( errorClipboardNotLoaded ) ;
951
+ } ) ;
952
+
953
+ it ( 'should throw when clipboard is called and viewContainerRef is omitted/null/undefined' , ( ) => {
954
+
955
+ const container = document . createElement ( 'div' ) ;
956
+
957
+ window [ 'ClipboardJS' ] = { } ;
958
+
959
+ const useCases = [
960
+ ( ) => markdownService . render ( container , { clipboard : true } ) ,
961
+ ( ) => markdownService . render ( container , { clipboard : true } , null ! ) ,
962
+ ( ) => markdownService . render ( container , { clipboard : true } , undefined ) ,
963
+ ] ;
964
+
965
+ useCases . forEach ( func => {
966
+ expect ( func ) . toThrowError ( errorClipboardViewContainerRequired ) ;
967
+ } ) ;
968
+ } ) ;
969
+
912
970
it ( 'should highlight element' , ( ) => {
913
971
914
972
const element = document . createElement ( 'div' ) ;
0 commit comments